working_dir: &working_dir
  working_directory: /go/src/github.com/palantir/k8s-spark-scheduler

# Uses a custom image to support efficient cross-compilation for darwin and linux with no CGo. This image has the Go
# standard libraries without CGo for both platforms precompiled and sets CGO_ENABLED to 0. Defaults to disabling CGo so
# that the compiled binaries do not have any dependencies on C (which allows more portability to run in environments
# like alpine-linux where glibc is not standard.
darwin-linux-no-cgo: &darwin-linux-no-cgo
  <<: *working_dir
  docker:
    - image: nmiyake/go:go-darwin-linux-no-cgo-1.11.2-java-8u181-t137
      environment:
        CGO_ENABLED: 0

# Standard Go image with Docker installed to allow execution of Docker operations.
go-docker: &go-docker
  <<: *working_dir
  docker:
    - image: nmiyake/go:go-1.11.2-docker-17.06.0-ce-t137

# Operations for saving and loading gödel cache, which contains all of the plugin and asset executables. Cache is keyed
# on checksum of godelw and godel/config/godel.yml, as the content of these files should be enough to identify the
# dependencies.
godel-cache-restore: &godel-cache-restore
  restore_cache:
    keys:
      - &godel-cache-key godel-cache-{{ checksum "godelw" }}-{{ checksum "godel/config/godel.yml" }}-v1
godel-cache-save: &godel-cache-save
  save_cache:
    key: *godel-cache-key
    paths:
      - ~/.godel

go-version: &go-version
  run: go version

godel-version: &godel-version
  run: ./godelw version

# Steps for publishing the ".config.tgz" artifact and the Docker image. Publishes all tags for all Docker images on
# snapshots and only the tags with the key name "release" (as specified in dist-config.yml) on releases.
#
# Preconditions:
#   * Docker images to be published have been built with a blank repository name and saved to a file using "docker save" in a persisted workspace.
docker_publish_steps: &docker_publish_steps
  - setup_remote_docker:
      docker_layer_caching: true
  - attach_workspace:
      at: /tmp/docker-cache/
  - checkout
  - *go-version
  - *godel-cache-restore
  - *godel-version
  - run: docker load -i /tmp/docker-cache/docker-images.tar
  - run: docker login -u "$DOCKERHUB_USERNAME" -p "$DOCKERHUB_PASSWORD"
  # if release type is "release", then only push the tags with the key "release" (these tags typically include a concrete version to ensure that they are
  # globally unique). Required because release repository typically does not include overwrite permissions, so tags like "latest" or "snapshot" should not
  # be pushed on real releases (whereas it is fine for snapshots).
  - run: |
      if [ "$RELEASE_TYPE" == "release" ]; then
        ./godelw docker push --repository "$DOCKER_REPO" --tags=release
      else
        ./godelw docker push --repository "$DOCKER_REPO" --tags=latest
      fi

define-tests-dir: &define-tests-dir
  run: echo 'export TESTS_DIR=/tmp/test-results' >> $BASH_ENV

mkdir-tests-dir: &mkdir-tests-dir
  run: mkdir -p "${TESTS_DIR}"

store-test-results: &store-test-results
  type: test-results-store
  path: /tmp/test-results

store-artifacts: &store-artifacts
  type: artifacts-store
  path: /tmp/test-results
  destination: test-results

version: 2
jobs:
  # Runs all "./godelw verify" tasks except for tests.
  verify:
    <<: *darwin-linux-no-cgo
    steps:
      - checkout
      - *go-version
      - *godel-cache-restore
      - *godel-version
      - *godel-cache-save
      - run: ./godelw verify --apply=false --skip-test
  # Runs tests.
  test:
    <<: *darwin-linux-no-cgo
    steps:
      - checkout
      - *go-version
      - *godel-cache-restore
      - *godel-version
      - *godel-cache-save
      - *define-tests-dir
      - *mkdir-tests-dir
      - run: ./godelw test --junit-output="$TESTS_DIR/$CIRCLE_PROJECT_REPONAME-tests.xml"
      - *store-test-results
      - *store-artifacts
  docker-build:
    <<: *go-docker
    steps:
      - setup_remote_docker:
          docker_layer_caching: true
      - checkout
      - *go-version
      - *godel-cache-restore
      - *godel-version
      - *godel-cache-save
      - run: ./godelw docker build --verbose
      - run: |
          mkdir -p /tmp/docker-cache
          docker save -o /tmp/docker-cache/docker-images.tar $(./godelw artifacts docker)
      - persist_to_workspace:
          root: /tmp/docker-cache/
          paths:
            - docker-images.tar
  push-docker-release:
    <<: *go-docker
    environment:
      RELEASE_TYPE: release
    steps: *docker_publish_steps
  push-docker-snapshot:
    <<: *go-docker
    steps: *docker_publish_steps

### Workflows ###
# The set of jobs that should be run on every build. All publish operations block on these jobs.
requires_jobs: &requires_jobs
  - verify
  - test
  - docker-build

# Filter that matches all tags (will run on every build).
all-tags-filter: &all-tags-filter
  filters: { tags: { only: /.*/ } }

# Filter that matches only release tags. Used for jobs that publish releases.
release-requires-filter: &release-requires-filter
  requires: *requires_jobs
  filters:
    tags:
      only: /^v?[0-9]+(\.[0-9]+)+(-rc[0-9]+)?$/
    branches:
      ignore: /.*/

# Filter that matches only the "master" branch. Used for jobs that publish snapshots.
master-requires-filter: &master-requires-filter
  requires: *requires_jobs
  filters: { tags: { ignore: /.*/ }, branches: { only: /master/ } }

workflows:
  version: 2
  verify:
    jobs:
      - verify:
          <<: *all-tags-filter
      - test:
          <<: *all-tags-filter
      - docker-build:
          <<: *all-tags-filter
      - push-docker-release:
          <<: *release-requires-filter
      - push-docker-snapshot:
          <<: *master-requires-filter
