# SPDX-FileCopyrightText: 2022-2024 Sarah Vaupel <sarah.vaupel@uniworx.de>, Gregor Kleen <gregor@kleen.consulting>
#
# SPDX-License-Identifier: AGPL-3.0-or-later

### IMPORTANT NOTICE ###
# Our pipeline consists of static and dynamic parts.
# 
# This file only contains the static parts of our pipeline.
# Dynamic jobs are defined in .gitlab-ci/frontend.yml and .gitlab-ci/backend.yml.
# These are used as a template to generate downstream (child) pipelines during 
# the runtime of the upstream (parent) pipeline.
###


# workflow:
#   rules:
#     - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
#     - if: $CI_MERGE_REQUEST_ID
#     - if: $CI_COMMIT_TAG =~ /^v/
#     - if: $CI_COMMIT_TAG =~ /^t/
#     - if: $CI_COMMIT_TAG =~ /^d/


variables:
  IMAGE_BUILDER: quay.io/buildah/stable:latest
  FRONTEND_IMAGE_DEPENDENCIES:
    docker/frontend/Dockerfile
    package.json
    package-lock.json
    webpack.config.js
  BACKEND_IMAGE_DEPENDENCIES:
    docker/backend/Dockerfile
    package.yaml
    stack.yaml
    stack.yaml.lock


default:
  image:
    name: ${CI_REGISTRY}/uniworx/containers/debian:12.5
    entrypoint: [""]
    docker:
      platform: x86_64
  artifacts:
    name: "${CI_JOB_NAME}-${CI_COMMIT_SHORT_SHA}"
    expire_in: "1 day"
  retry: 2
  interruptible: true


stages:
  - setup
  - frontend
  - backend
  - release


setup:dynamic:
  stage: setup
  before_script:
    - apt-get -y update
    - apt-get -y install git
  variables:
    GIT_DEPTH: 99999
    GIT_STRATEGY: clone
    GIT_LOG_COMMAND: 'git log --max-count=1 --date=format:%Y-%m-%dT%H-%M --pretty=format:%cd'
  script:
    - echo "${FRONTEND_IMAGE_DEPENDENCIES}"
    - echo "${BACKEND_IMAGE_DEPENDENCIES}"
    - FRONTEND_IMAGE_VERSION=`${GIT_LOG_COMMAND} ${FRONTEND_IMAGE_DEPENDENCIES} | tee frontend-image-version`
    - BACKEND_IMAGE_VERSION=`${GIT_LOG_COMMAND} ${BACKEND_IMAGE_DEPENDENCIES} | tee backend-image-version`
    - 'echo "FRONTEND_IMAGE_VERSION: ${FRONTEND_IMAGE_VERSION}, BACKEND_IMAGE_VERSION: ${BACKEND_IMAGE_VERSION}"'
    - cat .gitlab-ci/frontend.yml | .gitlab-ci/dynamci.pl FRONTEND_IMAGE_VERSION=${FRONTEND_IMAGE_VERSION} > frontend.yml
    - cat .gitlab-ci/backend.yml | .gitlab-ci/dynamci.pl BACKEND_IMAGE_VERSION=${BACKEND_IMAGE_VERSION} PARENT_PIPELINE_ID=${CI_PIPELINE_ID} > backend.yml
  artifacts:
    paths:
      - frontend-image-version
      - backend-image-version
      - frontend.yml
      - backend.yml
  rules:
    - when: always

setup:containers:frontend: &setup-container
  stage: setup
  needs:
    - setup:dynamic
  image: ${IMAGE_BUILDER}
  variables:
    IMAGE_TYPE: frontend
  before_script: &container-before
    - IMAGE_VERSION=`cat ${IMAGE_TYPE}-image-version`
    - IMAGE_TAG=${CI_COMMIT_REF_SLUG}/${IMAGE_TYPE}:${IMAGE_VERSION}
    - REGISTRY_DESTINATION=${CI_REGISTRY_IMAGE}/${CI_COMMIT_REF_SLUG}/${IMAGE_TYPE}:${IMAGE_VERSION}
  script:
    - curl --request GET --header "PRIVATE-TOKEN:${REGISTRY_AUTH_TOKEN}" "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/registry/repositories?tags=true" > .gitlab-ci/.container-registry-contents.json
    - cat .gitlab-ci/.container-registry-contents.json
    - IMAGE_EXISTS=`grep \""${REGISTRY_DESTINATION}"\" .gitlab-ci/.container-registry-contents.json || :`
    - echo "${IMAGE_EXISTS}"
    - test "${CI_JOB_MANUAL}" = true && echo "Force rebuilding container."
    - >
      if [ -z "${IMAGE_EXISTS}" -o "${CI_JOB_MANUAL}" = true ] ; then
        echo "Building image ${REGISTRY_DESTINATION}..."
        buildah bud -t ${IMAGE_TAG} --build-arg PROJECT_DIR=${CI_PROJECT_DIR} --build-arg MOUNT_DIR=/mnt/${CI_PROJECT_DIR} --volume ${CI_PROJECT_DIR}:/mnt/${CI_PROJECT_DIR} --file docker/${IMAGE_TYPE}/Dockerfile
        buildah push --creds "${CI_REGISTRY_USER}:${CI_JOB_TOKEN}" ${IMAGE_TAG} ${REGISTRY_DESTINATION}
      else
        echo "Image ${IMAGE_TAG} already exists in the container registry. Skipping build."
      fi
  rules:
    - if: $CI_MERGE_REQUEST_ID
      when: never
    - when: always
setup:containers:frontend:wait: &setup-container-wait
  stage: setup
  needs:
    - setup:dynamic
  before_script: *container-before
  variables:
    GIT_STRATEGY: none
    IMAGE_TYPE: frontend
  script:
    - apt-get -y update && apt-get -y install curl
    - >
      while ! curl --request GET --header "PRIVATE-TOKEN:${REGISTRY_AUTH_TOKEN}" "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/registry/repositories?tags=true" | grep \""${REGISTRY_DESTINATION}"\" ; do
        echo "Waiting for container ${IMAGE_TAG} to appear in the container registry..."
        sleep 5
      done
    - echo "Image ${IMAGE_TAG} has been found in the container registry. Proceeding with the pipeline."
  rules:
    - if: $CI_MERGE_REQUEST_ID
      when: always
    - when: never
  retry: 0
  interruptible: true
  timeout: 3h

setup:containers:backend:
  <<: *setup-container
  variables:
    IMAGE_TYPE: backend
setup:containers:backend:wait:
  <<: *setup-container-wait
  variables:
    GIT_STRATEGY: none
    IMAGE_TYPE: backend


frontend:
  stage: frontend
  variables:
    GIT_STRATEGY: clone
  needs:
    - setup:dynamic
    - job: setup:containers:frontend
      optional: true
  trigger:
    strategy: depend
    include:
      - artifact: frontend.yml
        job: setup:dynamic


backend:dev: &backend
  stage: backend
  variables:
    GIT_STRATEGY: clone
  needs:
    - setup:dynamic
    - job: setup:containers:backend
      optional: true
    - frontend
  trigger:
    strategy: depend
    include:
      - artifact: backend.yml
        job: setup:dynamic

backend:prod:
  <<: *backend
  variables:
    PROD_BUILD: -prod


release:changelog:
  stage: release
  rules: &release-rules
    - if: $CI_COMMIT_TAG =~ /^v[0-9\.]+$/
    - if: $CI_COMMIT_TAG =~ /^v[0-9\.]+-test-.*$/
  script:
    - echo "Preparing release..."
    - ./.gitlab-ci/version.pl > .current-version
    - echo "VERSION=$(cat .current-version)" >> build.env
    - ./.gitlab-ci/version.pl -changelog CHANGELOG.md
  artifacts:
    reports:
      dotenv: build.env
    paths:
      - .current-version
      - .changelog.md
    name: "changelog-${CI_COMMIT_SHORT_SHA}"
    expire_in: "1 day"

release:container:
  stage: release
  rules: *release-rules
  variables:
    GIT_STRATEGY: none
  image: ${IMAGE_BUILDER}
  script:
    - echo "Building container for release ${VERSION}..."
    - buildah bud --tag fradrive:${VERSION} --file docker/fradrive/Dockerfile
    - buildah add --chown uniworx:uniworx bin/uniworx /bin/uniworx
    - echo "Pushing container ${VERSION} to container registry..."
    - buildah push --creds "${CI_REGISTRY_USER}:${CI_JOB_TOKEN}" fradrive:${VERSION} ${CI_REGISTRY_IMAGE}/fradrive:${VERSION}
  needs:
    - frontend # sanity
    - backend:prod # sanity
    - release:changelog

release:release:
  stage: release
  rules: *release-rules
  variables:
    GIT_STRATEGY: none
  image: registry.gitlab.com/gitlab-org/release-cli:latest
  script:
    - echo "Creating release ${VERSION}"
  release:
    name: "${VERSION}"
    tag_name: "{$CI_COMMIT_TAG}"
    description: .changelog.md
  needs:
    - frontend # sanity
    - backend:prod # sanity
    - release:changelog
    - release:container
  retry: 0



# frontend dependencies:
#   stage: setup
#   cache:
#     - &npm-cache
#       key: default-npm
#       paths: &npm-paths
#         - node_modules/
#         - .npm/
#         - .npmrc
#   script:
#     - make node_modules
#   artifacts:
#     paths: *npm-paths

# well-known:
#   stage: setup
#   script:
#     - make well-known
#   needs:
#     - job: frontend dependencies
#       artifacts: true
#   cache:
#     - &frontend-cache
#       key: default-frontend
#       paths:
#         - .well-known-cache
#   artifacts:
#     paths:
#       - well-known/
#       - .well-known-cache/

# # TODO: cache is always uploaded even if up-to-date; prevent re-upload when up-to-date
# backend dependencies:
#   stage: setup
#   cache:
#     - &stack-cache
#       key: default-stack
#       paths:
#         - .stack/
#         - .stack-work/
#   script:
#     - make backend-dependencies-prod
#   artifacts:
#     paths:
#       - .stack/
#       - .stack-work/

# frontend build:
#   stage: build
#   cache:
#     - *frontend-cache
#   script:
#     - make frontend-build
#   needs:
#     - job: frontend dependencies
#       artifacts: true
#     - job: well-known
#       artifacts: true
#   artifacts:
#     paths:
#       - static/
#       - config/webpack.yml

# # TODO: .stack-work cache not working
# backend build:
#   stage: build
#   cache:
#     - *stack-cache
#   script:
#     - make bin/uniworx
#     # - find .stack-work
#     # - cp $(stack path --dist-dir)/build/hlint/hlint bin/test-hlint
#     # - cp $(stack path --dist-dir)/build/yesod/yesod bin/test-yesod
#   needs:
#     - job: frontend dependencies # transitive
#       artifacts: false
#     - job: well-known
#       artifacts: true
#     - job: backend dependencies
#       artifacts: true
#     - job: frontend build
#       artifacts: true
#   artifacts:
#     paths:
#       - bin/
#   resource_group: ram

# # TODO: part of backend build; probably deprecated
# # uniworxdb:
# #   stage: build
# #   script:
# #     - make bin/uniworxdb
# #   needs:
# #     # TODO: no frontend needed
# #     - job: frontend dependencies # transitive
# #       artifacts: false
# #     - job: frontend build # transitive
# #       artifacts: false
# #   artifacts:
# #     paths:
# #       - bin/uniworxdb

# # TODO: part of backend build; probably deprecated
# # TODO: rewrite
# # uniworx:exe:uniworxload:
# #   stage: build
# #   script:
# #     - xzcat uniworx:lib:uniworx.nar.xz | nix-store --import
# #     - nix -L build -o result ".#uniworx:exe:uniworxload"
# #     - nix-store --export $(nix-store -qR result) | xz -T0 -2 > uniworx:exe:uniworxload.nar.xz
# #   needs:
# #     - job: frontend dependencies # transitive
# #       artifacts: false
# #     - job: frontend build # transitive
# #       artifacts: false
# #   artifacts:
# #     paths:
# #       - uniworx:exe:uniworxload.nar.xz

# frontend lint:
#   stage: lint
#   script:
#     - make frontend-lint
#   cache:
#     - *frontend-cache
#   needs:
#     - job: frontend dependencies
#       artifacts: true
#     - job: well-known # TODO: is this really needed?
#       artifacts: true

# backend lint:
#   stage: lint
#   cache:
#     - *stack-cache
#   script:
#     # TODO: - make backend-lint-dev
#     - make backend-lint-prod
#   needs:
#     - job: backend dependencies
#       artifacts: true
#     - job: backend build
#       artifacts: true
#     - job: frontend build
#       artifacts: true
#     - job: well-known
#       artifacts: true

# frontend test:
#   stage: test
#   script:
#     - make frontend-test
#   cache: *frontend-cache
#   needs:
#     - job: frontend dependencies
#       artifacts: true
#   # TODO: configure report artifacts

# backend test:
#   stage: test
#   script:
#     - make backend-test-prod
#   cache: *stack-cache
#   needs:
#     - job: well-known
#       artifacts: true
#     - job: frontend build
#       artifacts: true
#     - job: backend dependencies
#       artifacts: true
#     - job: backend build
#       artifacts: true
#   # TODO: configure report artifacts

# # TODO: unify prod and test versions
# # TODO: rewrite
# container:
#   stage: container
#   script:
#     - xzcat uniworx:exe:uniworx.nar.xz | nix-store --import
#     - cp -pr --reflink=auto -L $(nix build --print-out-paths  ".#uniworxDocker") uniworx.tar.gz
#   needs:
#     - job: frontend dependencies # transitive
#       artifacts: false
#     - job: frontend build # transitive
#       artifacts: false
#     - job: frontend test # sanity
#       artifacts: false
#     - job: backend test # sanity
#       artifacts: false
#   artifacts:
#     paths:
#       - uniworx.tar.gz
#   rules: &release-rules
#     - if: $CI_COMMIT_TAG =~ /^v/
# # TODO: rewrite
# test container:
#   stage: container
#   script:
#     - xzcat uniworx:exe:uniworx.nar.xz | nix-store --import
#     - cp -pr --reflink=auto -L $(nix build --print-out-paths  ".#uniworxTestDocker") uniworx.tar.gz
#   needs:
#     - job: frontend dependencies # transitive
#       artifacts: false
#     - job: frontend build # transitive
#       artifacts: false
#     - job: frontend test # sanity
#       artifacts: false
#     - job: backend test # sanity
#       artifacts: false
#   artifacts:
#     paths:
#       - uniworx.tar.gz
#   rules: &test-release-rules
#     - if: $CI_COMMIT_TAG =~ /^t/

# # TODO: unify prod and test versions
# # TODO: rewrite
# parse changelog:
#   stage: prepare release
#   needs:
#     - job: frontend dependencies
#       artifacts: true
#   rules: *release-rules
#   script:
#     - xzcat node-dependencies.nar.xz | nix-store --import
#     - nix -L run ".#jqChangelogJson" -- -r '.versions[0].version' > .current-version
#     - nix -L run ".#jqChangelogJson" -- -r '.versions[0].body' > .current-changelog.md
#     - echo "VERSION=$(cat .current-version)" >> build.env
#   artifacts:
#     reports:
#       dotenv: build.env
#     paths:
#       - .current-version
#       - .current-changelog.md
#     name: "changelog-${CI_COMMIT_SHORT_SHA}"
#     expire_in: "1 day"
# # TODO: rewrite
# parse test changelog:
#   stage: prepare release
#   needs:
#     - job: frontend dependencies
#       artifacts: true
#   rules: *test-release-rules
#   script:
#     - xzcat node-dependencies.nar.xz | nix-store --import
#     - nix -L run ".#jqChangelogJson" -- -r '.versions[0].version' > .current-version
#     - nix -L run ".#jqChangelogJson" -- -r '.versions[0].body' > .current-changelog.md
#     - echo "VERSION=$(cat .current-version)" >> build.env
#   artifacts:
#     reports:
#       dotenv: build.env
#     paths:
#       - .current-version
#       - .current-changelog.md
#     name: "changelog-${CI_COMMIT_SHORT_SHA}"

# # TODO: unify prod and test versions
# # TODO: rewrite
# upload container:
#   variables:
#     GIT_STRATEGY: none
#   stage: release
#   image: quay.io/skopeo/stable:latest
#   script:
#     - skopeo --insecure-policy copy --dest-creds "${CI_REGISTRY_USER}:${CI_JOB_TOKEN}" docker-archive://$(pwd)/uniworx.tar.gz docker://${CI_REGISTRY_IMAGE}:${VERSION}
#     - skopeo --insecure-policy copy --src-creds "${CI_REGISTRY_USER}:${CI_JOB_TOKEN}" --dest-creds "${CI_REGISTRY_USER}:${CI_JOB_TOKEN}" docker://${CI_REGISTRY_IMAGE}:${VERSION} docker://${CI_REGISTRY_IMAGE}:latest
#   needs:
#     - job: frontend dependencies # transitive
#       artifacts: false
#     - job: frontend build # transitive
#       artifacts: false
#     - job: container
#       artifacts: true
#     - job: parse changelog
#       artifacts: true
#     - job: frontend test # sanity
#       artifacts: false
#     - job: backend test # sanity
#       artifacts: false
#   rules: *release-rules
# # TODO: rewrite
# upload test container:
#   variables:
#     GIT_STRATEGY: none
#   stage: release
#   image: quay.io/skopeo/stable:latest
#   script:
#     - skopeo --insecure-policy copy --dest-creds "${CI_REGISTRY_USER}:${CI_JOB_TOKEN}" docker-archive://$(pwd)/uniworx.tar.gz docker://${CI_REGISTRY}/fradrive/fradrive/test:${CI_COMMIT_REF_NAME}
#     - skopeo --insecure-policy copy --src-creds "${CI_REGISTRY_USER}:${CI_JOB_TOKEN}" --dest-creds "${CI_REGISTRY_USER}:${CI_JOB_TOKEN}" docker://${CI_REGISTRY}/fradrive/fradrive/test:${CI_COMMIT_REF_NAME} docker://${CI_REGISTRY}/fradrive/fradrive/test:latest
#   needs:
#     - job: frontend dependencies # transitive
#       artifacts: false
#     - job: frontend build # transitive
#       artifacts: false
#     - job: test container
#       artifacts: true
#     - job: parse test changelog
#       artifacts: true
#     - job: frontend test # sanity
#       artifacts: false
#     - job: backend test # sanity
#       artifacts: false
#   rules: *test-release-rules

# # TODO: unify prod and test versions
# # TODO: rewrite
# release:
#   variables:
#     GIT_STRATEGY: none
#   stage: release
#   image: registry.gitlab.com/gitlab-org/release-cli:latest
#   rules: *release-rules
#   script:
#     - echo "Will create release ${VERSION}..."
#   release:
#     name: '$VERSION'
#     tag_name: '$CI_COMMIT_TAG'
#     description: .current-changelog.md
#   needs:
#     - job: frontend test # sanity
#       artifacts: false
#     - job: backend test # sanity
#       artifacts: false
#     - job: parse changelog
#       artifacts: true
#   retry: 0
# # TODO: rewrite
# test release:
#   variables:
#     GIT_STRATEGY: none
#   stage: release
#   image: registry.gitlab.com/gitlab-org/release-cli:latest
#   rules: *test-release-rules
#   script:
#     - echo "Will create test release ${VERSION}-test..."
#   release:
#     name: "${VERSION}-test"
#     tag_name: '$CI_COMMIT_TAG'
#     description: .current-changelog.md
#   needs:
#     - job: frontend test # sanity
#       artifacts: false
#     - job: backend test # sanity
#       artifacts: false
#     - job: parse test changelog
#       artifacts: true
#   retry: 0
