---
version: '3'

vars:
  SCENARIO:
    sh: |
      {{if .CLI_ARGS}}echo "{{.CLI_ARGS}}"{{else}}
      SCENARIO="$(jq -r '.blueprint.dockerBaseTag' package.json)"
      if [ "$SCENARIO" != 'null' ]; then
        echo "$SCENARIO"
      else
        echo 'default'
      fi
      {{end}}
  SLUG:
    sh: jq -r '.blueprint.slug' package.json

tasks:
  codeclimate:
    cmds:
      - |
        if [ -d ./test ]; then
          TEST_FOLDERS="$(find ./test -mindepth 1 -maxdepth 1 -type d)"
          if echo "$TEST_FOLDERS" | grep '/test/' &> /dev/null; then
            CURR_DIR="$PWD"
            for TEST_DIR in $TEST_FOLDERS; do
              if [ -f "${TEST_DIR}/.codeclimate.yml" ]; then
                RAN_CODECLIMATE=true
                task -t "$CURR_DIR/Taskfile.yml" lint:codeclimate
              fi
            done
            if [ -z "$RAN_CODECLIMATE" ]; then
              .config/log warn 'None of the folders in the `./test` directory contained a `.codeclimate.yml` file so CodeClimate was not tested'
            fi
          fi
        fi
    status:
      - '[[ "$(docker images -q {{.DOCKER_IMAGE}}:latest-codeclimate 2> /dev/null)" == "" ]]'
      - '[[ "$(docker images -q {{.DOCKER_IMAGE}}:slim-codeclimate 2>/dev/null)" == "" ]]'

  container-structure-test:
    desc: Runs ContainerStructureTest for Dockerfile build
    hide:
      sh: '[ ! -d ./test/structure ] || ! find ./test/structure -mindepth 1 -maxdepth 1 -name "*.yml" | grep .yml'
    cmds:
      - task: container-structure-test:latest
      - task: container-structure-test:slim

  container-structure-test:latest:
    deps:
      - :install:software:container-structure-test
      - :install:software:docker
    vars:
      TAG_POST: '{{if .CLI_ARGS}}{{if ne .DOCKER_BASE_TAG .CLI_ARGS}}-{{.CLI_ARGS}}{{end}}{{end}}'
    log:
      error: '`container-structure-test` reported error(s) when testing
        `{{.DOCKERHUB_PROFILE}}/{{.SLUG}}:latest{{.TAG_POST}}`'
      start: Testing the `{{.DOCKERHUB_PROFILE}}/{{.SLUG}}:latest`
        Docker image with `container-structure-test{{.TAG_POST}}`
      success: '`{{.DOCKERHUB_PROFILE}}/{{.SLUG}}:latest{{.TAG_POST}}` was
        successfully validated by `container-structure-test`'
    cmds:
      - container-structure-test test --image {{.DOCKERHUB_PROFILE}}/{{.SLUG}}:latest{{.TAG_POST}} --config ./test/structure/{{.SCENARIO}}.yml
    status:
      - '[[ "$(docker images -q {{.DOCKERHUB_PROFILE}}/{{.SLUG}}:latest{{.TAG_POST}} 2>/dev/null)" == "" ]] || [ ! -f ./test/structure/{{.SCENARIO}}.yml ]'

  container-structure-test:slim:
    deps:
      - :install:software:container-structure-test
      - :install:software:docker
    vars:
      TAG_POST: '{{if .CLI_ARGS}}{{if ne .DOCKER_BASE_TAG .CLI_ARGS}}-{{.CLI_ARGS}}{{end}}{{end}}'
    log:
      error: '`container-structure-test` reported error(s) when testing
        `{{.DOCKERHUB_PROFILE}}/{{.SLUG}}:slim{{.TAG_POST}}`'
      start: Testing the `{{.DOCKERHUB_PROFILE}}/{{.SLUG}}:slim{{.TAG_POST}}`
        Docker image with `container-structure-test`
      success: '`{{.DOCKERHUB_PROFILE}}/{{.SLUG}}:slim{{.TAG_POST}}` was
        successfully validated by `container-structure-test`'
    cmds:
      - container-structure-test test --image {{.DOCKERHUB_PROFILE}}/{{.SLUG}}:slim{{.TAG_POST}} --config ./test/structure/{{.SCENARIO}}.yml
    status:
      - '[[ "$(docker images -q {{.DOCKERHUB_PROFILE}}/{{.SLUG}}:slim{{.TAG_POST}} 2> /dev/null)" == "" ]] | [ ! -f ./test/structure/{{.SCENARIO}}.yml ]'

  container-structure-tests:
    cmds:
      - |
        if [ -d ./test/structure ]; then
          TESTS="$(find ./test/structure -mindepth 1 -maxdepth 1 -name "*.yml")"
          if echo "$TESTS" | grep '.yml' > /dev/null; then
            for TEST_FILE in $TESTS; do
              TARGET="$(echo "$TEST_FILE" | sed 's/.*\/\([^\/]*\).yml$/\1/')"
              task docker:test:container-structure-test -- "$TARGET"
            done
          else
            .config/log error 'The `./test/structure` folder is present but there are no container-structure-tests in it. Add tests \
            for each build target in the `Dockerfile` that you would like to generate an image for.'
            exit 1
          fi
        else
          .config/log warn 'No tests are defined in `./test/structure` so no container-structure-tests will be performed'
        fi

  gitlab-runner:
    deps:
      - :install:software:docker
      - :install:software:gitlab-runner
      - :install:software:jq
      - :install:software:yq
    env:
      CI_TESTS:
        sh: yq e 'keys | .[] | select( . | test("integration"))' .gitlab-ci.yml
    log:
      error: Error encountered while validating with the integration tests in `.gitlab-ci.yml`
      start: Running integration tests defined in `.gitlab-ci.yml`
      success: Successfully passed the integration tests defined in `.gitlab-ci.yml`
    cmds:
      - |
        for CI_TEST in $CI_TESTS; do
          export CI_TEST
          .config/log warn 'GitLab Runner no longer supports running gitlab-runner exec so this test is no longer active (for now)'
          # if [ "$(yq e '.[strenv(CI_TEST)].image' .gitlab-ci.yml)" != 'null' ]; then
          #   .config/log info 'Simulating the `'"$CI_TEST"'` job in `.gitlab-ci.yml`'
          #   gitlab-runner exec "$CI_TEST"
          #   .config/log success 'Successfully ran the `'"$CI_TEST"'` job in `.gitlab-ci.yml`'
          # else
          #   .config/log warn "$CI_TEST does not appear to be an option with an image in .gitlab-ci.yml"
          # fi
        done
    status:
      - >
        ! yq e 'keys | .[] | select( . | test("integration"))' .gitlab-ci.yml | grep 'integration:' > /dev/null

  output:
    deps:
      - :install:software:docker
    desc: For each folder matching `./test/output*`, ensure slim and latest output match with default command
    summary: |
      # Ensure Identical Output

      This task ensures the output of the default command is identical for both the latest and slim images.
      If both of the command's outputs match, then that is a good indicator that the slim image is
      behaiving like the latest image. The test is performed on each project folder in the `test-output/` folder.
    vars:
      DIND_MOUNT:
        sh: |
          if [ "$(jq -r '.blueprint.dockerInDocker' package.json)" == 'true' ]; then
            echo "-v {{.DIND_MOUNT_MAPPING}} "
          fi
      MOUNT_PATH: '{{if .CLI_ARGS}}{{.CLI_ARGS}}{{else}}$PWD{{end}}'
      OUTPUT_COMMAND:
        sh: |
          BP_OUTPUT="$(jq -r '.blueprint.dockerOutputCommand' package.json)"
          if [ "$BP_OUTPUT" != 'null' ]; then
            echo "$BP_OUTPUT"
          else
            echo '.'
          fi
    hide:
      sh: '! find ./test -mindepth 1 -maxdepth 1 -type d | grep output'
    log:
      error: There was an error while comparing `latest` and `slim` image outputs for `{{.DOCKER_IMAGE}}`
      start: Comparing outputs of the `latest` and `slim` images for `{{.DOCKER_IMAGE}}`
      success: The outputs of the `latest` and `slim` images match for `{{.DOCKER_IMAGE}}`!
    cmds:
      - |
        LATEST_OUTPUT="$(docker run -v "{{.MOUNT_PATH}}:/work" -w /work {{.DOCKER_IMAGE}}:latest {{.OUTPUT_COMMAND}} || true)"
        .config/log success 'Acquired `latest` image output'
        .config/log info 'Acquiring `slim` image output'
        SLIM_OUTPUT="$(docker run -v "{{.MOUNT_PATH}}:/work" -w /work {{.DOCKER_IMAGE}}:slim {{.OUTPUT_COMMAND}} || true)"
        .config/log success 'Acquired `slim` image output'
        if [ "$LATEST_OUTPUT" != "$SLIM_OUTPUT" ]; then
          .config/log error 'The `latest` image output did not match the `slim` image output with the command `{{.OUTPUT_COMMAND}}`'
          echo "$LATEST_OUTPUT" > latest.log
          .config/log info 'The `latest` image output has been written to `latest.log`'
          echo "$SLIM_OUTPUT" > slim.log
          .config/log info 'The `slim` image output has been written to `slim.log`'
          exit 1
        else
          .config/log success 'The output from the `{{.OUTPUT_COMMAND}}` command generated the same output for both the `slim` and `latest` builds'
        fi

  outputs:
    log:
      error: Error intitializing Docker output tests
      start: Initializing Docker output test phase
      success: Completed Docker output test phase
    cmds:
      - |
        if [ -d test ]; then
          TESTS="$(find ./test -mindepth 1 -maxdepth 1 -type d -name "output-*")"
          if echo "$TESTS" | grep 'output'; then
            for TEST_FILE in $TESTS; do
              TARGET="$(echo "$TEST_FILE" | sed 's/.*\/\([^\/]*\).yml$/\1/')"
              task docker:test:output -- "$TARGET"
            done
          else
            .config/log info 'No folders matching `test/output*` were found so output comparison test is being skipped'
          fi
        else
          .config/log info 'No `./test` folder. See the `docs/CONTRIBUTING.md` to see how to set up the tests for Docker image builds'
        fi
    status:
      - '(! find ./test -mindepth 1 -maxdepth 1 -type d -name "output-*" | grep output-)
        || [[ "$(docker images -q {{.DOCKER_IMAGE}}:slim 2> /dev/null)" == "" ]]
        || [[ "$(docker images -q {{.DOCKER_IMAGE}}:latest 2>/dev/null)" == "" ]]'
