image: "python:slim"

stages:
  - test
  - pages
  - build-package
  - publish-package
  - publish-docker

variables:
  PACKAGE_NAME: "herosdevices"
  PYPI_URL: "https://gitlab.com/api/v4/projects/${CI_PROJECT_ID}/packages/pypi"

####################################
# build script for docker images
.build-docker-image:
  image: quay.io/buildah/stable
  variables:
    IMAGE_TAG: "latest"
    BUILDAH_FORMAT: docker
    STORAGE_DRIVER: vfs
  tags:
    - docker
  before_script:
    - echo "$CI_REGISTRY_PASSWORD" | buildah login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY
  script:
    - cd "${CI_PROJECT_DIR}"
    # separate manifest for builder stage for caching
    - buildah build -f "Dockerfile" --layers --target builder --platform=linux/arm64/v8,linux/amd64 --manifest "${CI_REGISTRY_IMAGE}:${TAG_NAME}-builder" .
    # final stage for standard
    - buildah build -f "Dockerfile" --layers --target final --platform=linux/arm64/v8,linux/amd64 --manifest "${CI_REGISTRY_IMAGE}:${TAG_NAME}" .
    # publish
    # standard
    - buildah tag "${CI_REGISTRY_IMAGE}:${TAG_NAME}" "${CI_REGISTRY_IMAGE}:latest"
    - buildah manifest push --all "${CI_REGISTRY_IMAGE}:${TAG_NAME}"
    - buildah manifest push --all "${CI_REGISTRY_IMAGE}:latest"

.build-docker-image-rpi:
  image: quay.io/buildah/stable
  variables:
    IMAGE_TAG: "latest"
    BUILDAH_FORMAT: docker
    STORAGE_DRIVER: vfs
  tags:
    - docker
  before_script:
    - echo "$CI_REGISTRY_PASSWORD" | buildah login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY
  script:
    - cd "${CI_PROJECT_DIR}"
    # final stage for rpi
    - buildah build -f "Dockerfile.rpi" --layers --platform=linux/arm64/v8 --manifest "${CI_REGISTRY_IMAGE}:${TAG_NAME}-rpi" .
    # publish
    # rpi
    - buildah tag "${CI_REGISTRY_IMAGE}:${TAG_NAME}-rpi" "${CI_REGISTRY_IMAGE}:latest-rpi"
    - buildah manifest push --all "${CI_REGISTRY_IMAGE}:${TAG_NAME}-rpi"
    - buildah manifest push --all "${CI_REGISTRY_IMAGE}:latest-rpi"

####################################
# publish script for pypi packages
.publish-package-to-repo:
  stage: publish-package
  tags:
    - docker
  image: "quay.io/pypa/manylinux_2_28_x86_64"
  needs: ["build-package"] # Ensure package is built before publishing
  before_script:
    - pipx install twine

####################################
# build
build-package:
  stage: build-package
  tags:
    - docker
  parallel:
    matrix:
      - IMAGE: ["quay.io/pypa/manylinux_2_28_x86_64"]
  image: $IMAGE
  script:
    - pipx install hatch
    - hatch build # Builds source tarball and wheel
  before_script:
    - apt-get update && apt-get install -y build-essential
  artifacts:
    paths:
      - dist/
  rules:
    - if: '$CI_JOB_TRIGGER == "boss"'
      when: never
    - when: always

####################################
# test
pytest:
  stage: test
  tags:
    - docker
  script:
    - pip install --upgrade uv
    - uv venv
    - uv pip install -e .[dev]
    - uv run pytest --color=yes --junitxml=report.xml --cov-report html --cov-report term --cov-report xml:cobertura.xml --cov=src/ tests/
  before_script:
    - apt-get update && apt-get install -y build-essential
  coverage: '/(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/'
  artifacts:
    paths:
      - htmlcov
      - report.xml
      - cobertura.xml
    reports:
      junit: report.xml
      coverage_report:
        coverage_format: cobertura
        path: cobertura.xml
  rules:
    - if: '$CI_JOB_TRIGGER == "boss"'
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == "main"

####################################
# lint
ruff:
  stage: test
  tags:
    - docker
  script:
    - pip install --upgrade uv
    - uv venv
    - uv pip install -e .[dev]
    - uv run ruff check
  before_script:
    - apt-get update && apt-get install -y build-essential
  rules:
    - if: '$CI_JOB_TRIGGER == "boss"'
      when: never
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == "main"
  allow_failure: false

mypy:
  stage: test
  tags:
    - docker
  script:
    - pip install --upgrade uv
    - uv venv
    - uv pip install -e .[dev]
    - uv run mypy src
  before_script:
    - apt-get update && apt-get install -y build-essential
  rules:
    - if: '$CI_JOB_TRIGGER == "boss"'
      when: never
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == "main"
  allow_failure: true

####################################
# publish package
publish-package-gitlab:
  stage: publish-package
  extends: .publish-package-to-repo
  script:
    - twine upload --repository-url "$PYPI_URL" -u "gitlab-ci-token" -p "$CI_JOB_TOKEN" dist/*
  rules:
    - if: '$CI_JOB_TRIGGER == "boss"'
      when: never
    - if: '$CI_COMMIT_BRANCH == "main"'
      when: on_success

publish-package-pypi:
  stage: publish-package
  extends: .publish-package-to-repo
  script:
    - twine upload --skip-existing -p "$PYPI_API_TOKEN" dist/*
  rules:
    - if: '$CI_JOB_TRIGGER == "boss"'
      when: never
    - if: '$CI_COMMIT_BRANCH == "main"'
      when: on_success

####################################
# docker image git commit sha with last commit from main (not on tag)
publish-docker-main:
  stage: publish-docker
  extends: .build-docker-image
  variables:
    TAG_NAME: "$CI_COMMIT_SHORT_SHA"
  rules:
    - if: '$CI_COMMIT_REF_NAME == "main"'
    - if: '$CI_PIPELINE_SOURCE == "pipeline"'

publish-docker-main-rpi:
  stage: publish-docker
  extends: .build-docker-image-rpi
  needs: [publish-docker-main]
  variables:
    TAG_NAME: "$CI_COMMIT_SHORT_SHA"
  rules:
    - if: '$CI_COMMIT_REF_NAME == "main"'
    - if: '$CI_PIPELINE_SOURCE == "pipeline"'

####################################
# publish pages
pages-base:
  tags:
    - docker
  script:
    - apt-get update && apt-get install -y make graphviz
    - pip install --upgrade uv
    - uv venv
    - uv pip install -e .[docs]
    - cd docs
    - uv run make clean && uv run make html
    - echo "Copying docs to $ARTIFACT_PATH"
    - mkdir ../"$ARTIFACT_PATH"
    - mv build/html/* ../"$ARTIFACT_PATH"
  before_script:
    - apt-get update && apt-get install -y build-essential
  artifacts:
    paths:
      - $ARTIFACT_PATH
  rules:
    - when: never

pages-publish:
  stage: pages
  extends: pages-base
  pages: true
  variables:
    ARTIFACT_PATH: public
  rules:
    - if: '$CI_JOB_TRIGGER == "boss"'
      when: never
    - if: '$CI_COMMIT_BRANCH == "main"'
      when: on_success

pages-temp:
  stage: test
  extends: pages-base
  variables:
    ARTIFACT_PATH: $CI_MERGE_REQUEST_ID
  artifacts:
    expire_in: 2 days
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
      when: on_success
