---
version: '3'

tasks:
  fat:
    deps:
      - :install:software:docker
      - :install:software:jq
    desc: Build a normal Docker container from the Dockerfile
    hide:
      sh: '[ ! -f Dockerfile ]'
    summary: |
      # Build Docker Container from Dockerfile

      This task builds a normal Docker container. It expects the Dockerfile to be
      named `Dockerfile` and for it to be in the root of the repository.

      For more information on building Docker containers, see
      [Docker's build guide](https://docs.docker.com/engine/reference/commandline/build/).
    vars:
      BUILD_DATE:
        sh: git show -s --format=%cI
      DOCKER_IMAGE:
        sh: echo "{{.DOCKERHUB_PROFILE}}/{{if .CLI_ARGS}}{{.CLI_ARGS}}{{else}}$(jq -r '.blueprint.slug' package.json){{end}}"
      REVISION:
        sh: git rev-parse HEAD
      SLUG:
        sh: |
          {{if .CLI_ARGS}}
          if echo '{{.CLI_ARGS}}' | grep 'codeclimate-' > /dev/null; then
            echo '{{.CLI_ARGS}}'
          else
            echo 'false'
          fi
          {{else}}
          echo "codeclimate-$(jq -r '.blueprint.slug' package.json)"
          {{end}}
      VERSION:
        sh: jq -r '.version' package.json
    log:
      error: Error building `{{.DOCKER_IMAGE}}:{{.VERSION}}`
      start: Building Docker container `{{.DOCKER_IMAGE}}:{{.VERSION}}` (also tagged as latest)
      success: Successfully built Docker container named `{{.DOCKER_IMAGE}}:{{.VERSION}}`
    cmds:
      - .config/log info 'Running `docker build --build-arg BUILD_DATE={{.BUILD_DATE}} --build-arg REVISION={{.REVISION}} --build-arg VERSION={{.VERSION}}
        --tag {{.DOCKER_IMAGE}}:latest --tag {{.DOCKER_IMAGE}}:{{.VERSION}} {{if eq .REPOSITORY_SUBTYPE "codeclimate"}}{{if ne .SLUG "false"}}
        --tag codeclimate/{{.SLUG}}:latest{{end}}{{end}}{{if .CLI_ARGS}} --target {{.CLI_ARGS}}{{end}} .`'
      - docker build --build-arg BUILD_DATE={{.BUILD_DATE}} --build-arg REVISION={{.REVISION}} --build-arg VERSION={{.VERSION}}
        --tag {{.DOCKER_IMAGE}}:latest --tag {{.DOCKER_IMAGE}}:{{.VERSION}}{{if eq .REPOSITORY_SUBTYPE "codeclimate"}}{{if ne .SLUG "false"}}
        --tag codeclimate/{{.SLUG}}:latest{{end}}{{end}}{{if .CLI_ARGS}} --target {{.CLI_ARGS}}{{end}} .

  slim:
    deps:
      - :install:software:docker
      - :install:software:docker-slim
    desc: Build a slim version of the Docker image
    hide:
      sh: '[ ! -f Dockerfile ]'
    summary: |
      # Build a compressed and secure container from the `regular` Docker image

      This task takes the Docker container generated by running `task build:normal` and
      compresses it using DockerSlim. Compressing it actually makes the container more
      secure too because there is a smaller attack surface with unnecessary tools and services
      removed.

      For more information, see [DockerSlim's GitHub page](https://github.com/docker-slim/docker-slim).
    cmds:
      - task: fat
      - task: slim:command
      - task: slim:finish

  slim:command:
    vars:
      DOCKER_IMAGE:
        sh: echo "{{.DOCKERHUB_PROFILE}}/{{if .CLI_ARGS}}{{.CLI_ARGS}}{{else}}$(jq -r '.blueprint.slug' package.json){{end}}"
      IMAGE_TYPE:
        sh: echo "{{if .CLI_ARGS}}{{.CLI_ARGS}}{{else}}$(jq -r '.blueprint.slug' package.json){{end}}"
      SLIM_COMMAND:
        sh: |
          COMMAND_TYPE="$(jq -r '.blueprint.dockerSlimCommand | type' package.json)"
          if [ "$COMMAND_TYPE" == 'string' ]; then
            echo "$(jq -r '.blueprint.dockerSlimCommand' package.json)"
          else
            echo "$(jq --arg type {{.IMAGE_TYPE}} -r '.blueprint.dockerSlimCommand[$type]' package.json)"
          fi
      SLUG:
        sh: jq -r '.blueprint.slug' package.json
    log:
      error: Error building `{{.DOCKER_IMAGE}}:slim` with `docker-slim`
      start: Building Docker container named `{{.DOCKER_IMAGE}}:slim`
      success: Successfully built Docker container named `{{.DOCKER_IMAGE}}:slim`
    cmds:
      - >
        .config/log info 'Running `docker-slim build --tag {{.DOCKER_IMAGE}}:slim
        {{if eq .REPOSITORY_SUBTYPE "codeclimate"}}--tag codeclimate/codeclimate-{{.SLUG}}:slim {{end}}
        {{.SLIM_COMMAND | replace "'" "\""}} {{.DOCKER_IMAGE}}:latest`'
      - >
        docker-slim build --tag {{.DOCKER_IMAGE}}:slim
        {{if eq .REPOSITORY_SUBTYPE "codeclimate"}}--tag codeclimate/codeclimate-{{.SLUG}}:slim {{end}}
        {{.SLIM_COMMAND | replace "'" "\""}} {{.DOCKER_IMAGE}}:latest

  slim:finish:
    deps:
      - slim:prettier
      - slim:sizes

  slim:prettier:
    deps:
      - :install:npm:prettier
    log:
      error: Failed to format `slim.report.json` with Prettier
      start: Formatting `slim.report.json` with Prettier
      success: Formatted `slim.report.json` with Prettier
    cmds:
      - '{{.NPX_HANDLE}}prettier --write slim.report.json > /dev/null'
      - mv slim.report.json docs/slim.report.json

  slim:sizes:
    cmds:
      - task: slim:sizes:assets
      - task: slim:sizes:calculate
      - task: slim:sizes:clean

  slim:sizes:assets:
    deps:
      - :install:software:docker
      - :install:software:gzip
    vars:
      DOCKER_IMAGE:
        sh: echo "{{.DOCKERHUB_PROFILE}}/{{if .CLI_ARGS}}{{.CLI_ARGS}}{{else}}$(jq -r '.blueprint.slug' package.json){{end}}"
      SLUG:
        sh: echo "{{if .CLI_ARGS}}{{.CLI_ARGS}}{{else}}$(jq -r '.blueprint.slug' package.json){{end}}"
    cmds:
      - |
        function zipUp() {
          docker save "{{.DOCKER_IMAGE}}:$1" > "{{.SLUG}}-$1.tar"
          gzip -f "{{.SLUG}}-$1.tar"
        }
        zipUp "latest" &
        zipUp "slim" &
        wait

  slim:sizes:calculate:
    deps:
      - :install:software:jq
    vars:
      DOCKER_IMAGE_SLUG:
        sh: echo "{{if .CLI_ARGS}}{{.CLI_ARGS}}{{else}}$(jq -r '.blueprint.slug' package.json){{end}}"
      PREVIOUS_REGULAR_SIZE:
        sh: jq --arg slug '{{.DOCKER_IMAGE_SLUG}}' -r '.blueprint.dockerLatestSize[$slug]' package.json
      PREVIOUS_SLIM_SIZE:
        sh: jq --arg slug '{{.DOCKER_IMAGE_SLUG}}' -r '.blueprint.dockerSlimSize[$slug]' package.json
      REGULAR_SIZE:
        sh: stat -c%s {{.DOCKER_IMAGE_SLUG}}-latest.tar.gz | numfmt --to iec
      SLIM_SIZE:
        sh: stat -c%s {{.DOCKER_IMAGE_SLUG}}-slim.tar.gz | numfmt --to iec
    log:
      error: Failed to acquire / inject `:slim` image file size information into `package.json` blueprint data
      start: Injecting `:slim` image file size into `package.json` blueprint data
    cmds:
      - |
        TMP="$(mktemp)"
        jq --arg a '{{.SLIM_SIZE}}' --arg b '{{.REGULAR_SIZE}}' --arg slug '{{.DOCKER_IMAGE_SLUG}}' \
        '.blueprint.dockerSlimSize[$slug] = $a | .blueprint.dockerLatestSize[$slug] = $b' package.json > "$TMP"
        mv "$TMP" package.json
      - task: slim:sizes:clean
      - task: :common:update:update
    status:
      - '[[ "{{.PREVIOUS_SLIM_SIZE}}" == "{{.SLIM_SIZE}}" ]]'
      - '[[ "{{.PREVIOUS_REGULAR_SIZE}}" == "{{.REGULAR_SIZE}}" ]]'

  slim:sizes:clean:
    cmds:
      - rm -f *-latest.tar.gz
      - rm -f *-latest.tar
      - rm -f *-slim.tar.gz
      - rm -f *-slim.tar
    status:
      - >
        ! test -n "$(find . -maxdepth 1 -name '*.tar.gz' -print -quit)"
