# Define rules for a job that should run for events related to a merge request
# - merge request is opened, a new commit is pushed to its branch, etc.  This
# definition does nothing by itself but can be referenced by jobs that want to
# run in this condition.
.merge_request_rules: &RUN_ON_MERGE_REQUEST
  rules:
    # If the pipeline is triggered by a merge request event then we should
    # run.
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'

    # If the pipeline is triggered by anything else then we should not run.
    - when: "never"

# As above, but rules for running when the scheduler triggers the pipeline.
.schedule_rules: &RUN_ON_SCHEDULE
  rules:
    # There are multiple schedules so make sure this one is for us.  The
    # `SCHEDULE_TARGET` variable is explicitly, manually set by us in the
    # schedule configuration.
    - if: '$SCHEDULE_TARGET != $CI_JOB_NAME'
      when: "never"

    # Make sure this is actually a scheduled run
    - if: '$CI_PIPELINE_SOURCE != "schedule"'
      when: "never"

    # Conditions look good: run.
    - when: "always"

stages:
  - "build"
  - "deploy"

default:
  # Guide the choice of an appropriate runner for all these jobs.
  # https://docs.gitlab.com/ee/ci/runners/#runner-runs-only-tagged-jobs
  tags:
    - "nixos"
    - "shell"

variables:
  # https://docs.gitlab.com/ee/ci/runners/configure_runners.html#job-stages-attempts
  GET_SOURCES_ATTEMPTS: 10

docs:
  <<: *RUN_ON_MERGE_REQUEST
  stage: "build"
  script:
    - "nix-build --attr docs --out-link result-docs"
    # GitLab wants to lchown artifacts.  It can't do that to store paths.  Get
    # a copy of the docs outside of the store.
    - "cp --recursive --no-preserve=mode ./result-docs/docs ./docs-build/"
  artifacts:
    paths:
      - "./docs-build/"
    expose_as: "documentation"

unit-tests:
  <<: *RUN_ON_MERGE_REQUEST
  stage: "build"
  script:
    - "nix-build --attr unit-tests && cat result"

.morph-build: &MORPH_BUILD
  <<: *RUN_ON_MERGE_REQUEST
  timeout: "3 hours"
  stage: "build"
  script:
    - |
      set -x
      # GRID is set in one of the "instantiations" of this job template.
      nix-shell --pure --run "morph build --show-trace morph/grid/${GRID}/grid.nix"


morph-build-localdev:
  <<: *MORPH_BUILD
  variables:
    GRID: "local"

  before_script:
    - |
      # The local grid configuration is *almost* complete enough to build.  It
      # just needs this tweak.
      echo '{}' > morph/grid/${GRID}/public-keys/users.nix

morph-build-staging:
  <<: *MORPH_BUILD
  variables:
    GRID: "testing"


morph-build-production:
  <<: *MORPH_BUILD
  variables:
    GRID: "production"


vulnerability-scan:
  <<: *RUN_ON_MERGE_REQUEST
  stage: "build"
  script:
    - "ci-tools/vulnerability-scan security-report.json"
    - "ci-tools/count-vulnerabilities <security-report.json"
  artifacts:
    paths:
      - "security-report.json"
    expose_as: "security report"


system-tests:
  <<: *RUN_ON_MERGE_REQUEST
  timeout: "3 hours"
  stage: "build"
  script:
    - "nix-shell --pure --run 'nix-build --attr system-tests'"

# A template for a job that can update one of the grids.
.update-grid: &UPDATE_GRID
  stage: "deploy"
  script: |
    env --ignore-environment - \
      NIX_PATH="$NIX_PATH" \
      GITLAB_USER_LOGIN="$GITLAB_USER_LOGIN" \
      CI_JOB_NAME="$CI_JOB_NAME" \
      CI_PIPELINE_SOURCE="$CI_PIPELINE_SOURCE" \
      CI_COMMIT_BRANCH="$CI_COMMIT_BRANCH" \
      ./ci-tools/update-grid-servers "${PRIVATESTORAGEIO_SSH_DEPLOY_KEY_PATH}" "${CI_ENVIRONMENT_NAME}"

# Update the staging deployment - only on a commit to the develop branch.
update-staging:
  <<: *UPDATE_GRID

  # https://docs.gitlab.com/ee/ci/yaml/#rules
  rules:
    # https://docs.gitlab.com/ee/ci/yaml/index.html#rulesif
    # https://docs.gitlab.com/ee/ci/jobs/job_control.html#cicd-variable-expressions
    # https://docs.gitlab.com/ee/ci/variables/predefined_variables.html
    - if: '$CI_COMMIT_BRANCH == "develop"'
  environment:
    # You can find some status information about environments in GitLab at
    # https://whetstone.privatestorage.io/privatestorage/PrivateStorageio/-/environments.
    name: "staging"
    # The URL controls where the "View Deployment" button for this environment
    # will take you.  The main website isn't controlled by this codebase so we
    # don't point there.  The monitoring system *is* controlled by this
    # codebase and it also tells us lots of stuff about other things
    # controlled by this codebase so that seems like a good place to land.
    # Not that I make it a habit to visit the deployment using the GitLab
    # button...  Still, discoverability or something.
    url: "https://monitoring.privatestorage-staging.com/"

# Update the production deployment - only on a commit to the production branch.
deploy-to-production:
  <<: *UPDATE_GRID

  # https://docs.gitlab.com/ee/ci/yaml/#rules
  rules:
    # https://docs.gitlab.com/ee/ci/yaml/index.html#rulesif
    # https://docs.gitlab.com/ee/ci/jobs/job_control.html#cicd-variable-expressions
    # https://docs.gitlab.com/ee/ci/variables/predefined_variables.html
    - if: '$CI_COMMIT_BRANCH == "production"'

  environment:
    # See notes in `update-staging`.
    name: "production"
    url: "https://monitoring.private.storage/"

update-nixpkgs:
  <<: *RUN_ON_SCHEDULE
  stage: "build"
  script:
    - |
      ./ci-tools/with-ssh-agent \
          ./ci-tools/update-nixpkgs \
              "$CI_SERVER_URL" \
              "$CI_SERVER_HOST" \
              "$CI_PROJECT_PATH" \
              "$CI_PROJECT_ID" \
              "$CI_DEFAULT_BRANCH"

update-production:
  <<: *RUN_ON_SCHEDULE
  stage: "build"
  script:
    - |
      ./ci-tools/update-production \
              "$CI_SERVER_URL" \
              "$CI_PROJECT_ID" \
              "develop" \
              "production"
