name: Deployment

on:
  push:
  pull_request:
  schedule:
    - cron: '0 10 * * *'
  workflow_dispatch:
    inputs:
      check-ci:
        description: "Require the CI to have passed for this commit"
        required: true
        default: "yes"
      version:
        description: "Override the release version number (e.g. 8.0.0a5)"

jobs:
  deploy-pypi:
    name: PyPI deployment
    runs-on: "ubuntu-latest"
    if: github.event_name != 'push' || github.repository == 'DIRACGrid/diracx'
    outputs:
      new-version: ${{ steps.check-tag.outputs.new-version }}
      create-release: ${{ steps.check-tag.outputs.create-release }}
    permissions:
      id-token: write  # IMPORTANT: this permission is mandatory for trusted publishing on pypi
      actions: write
      checks: write
      contents: write
      deployments: write
      discussions: write
      issues: write
      packages: write
      pages: write
      pull-requests: write
      repository-projects: write
      security-events: write
      statuses: write
    defaults:
      run:
        # We need extglob for REFERENCE_BRANCH substitution
        shell: bash -l -O extglob {0}
    steps:
      - uses: actions/checkout@v5
        with:
          token: ${{ github.token }}
      - run: |
          git fetch --prune --unshallow
          git config --global user.email "ci@diracgrid.org"
          git config --global user.name "DIRACGrid CI"
      - uses: actions/setup-python@v6
        with:
          python-version: '3.11'
      - name: Installing dependencies
        run: |
          python -m pip install \
              build \
              python-dateutil \
              pytz \
              readme_renderer[md] \
              requests \
              setuptools_scm
      - name: Validate README for PyPI
        run: |
          python -m readme_renderer README.md -o /tmp/README.html
      - name: Prepare release notes
        run: |
          set -xeuo pipefail
          IFS=$'\n\t'
          # Needed for the advanced pattern matching used in REFERENCE_BRANCH
          PREV_VERSION=$(git describe --tags --abbrev=0)
          # In case of manual trigger,
          # GITHUB_REF is of the form refs/heads/main -> we want main
          # In case of PR it is of the form refs/pull/59/merge -> we want pull/59/merge
          REFERENCE_BRANCH=${GITHUB_REF##refs*(/heads)/}
          echo "Making release notes for ${REFERENCE_BRANCH} since ${PREV_VERSION}"
          (git log ${PREV_VERSION}...${REFERENCE_BRANCH} --oneline --no-merges --) > release.notes.new
          cat release.notes.new
      - name: Create tag if required
        id: check-tag
        run: |
          set -xeuo pipefail
          IFS=$'\n\t'
          # Only do a real release for workflow_dispatch events
          if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
            echo "Will create a real release"
            export NEW_VERSION="v${{ github.event.inputs.version }}"
            if [[ "${NEW_VERSION}" == "v" ]]; then
              # If version wasn't given as an input to the workflow, use setuptools_scm to guess while removing "dev" portion of the version number
              NEW_VERSION=v$(python -m setuptools_scm | sed 's@Guessed Version @@g' | sed -E 's@(\.dev|\+g).+@@g')
              export NEW_VERSION
            fi
            echo "Release will be named $NEW_VERSION"
            # Validate the version
            # Ensure the version doesn't look like a PEP-440 "dev release" (which might happen if the automatic version bump has issues)
            python -c $'from packaging.version import Version; v = Version('"'$NEW_VERSION'"$')\nif v.is_devrelease:\n    raise ValueError(v)'
            # Make sure we always only create pre-releases
            python -c $'from packaging.version import Version; v = Version('"'$NEW_VERSION'"$')\nif not v.is_prerelease:\n    raise ValueError("integration should only be used for pre-releases")'
            # Commit the release notes
            mv release.notes release.notes.old
            cat release.notes.old
            (echo -e "[${NEW_VERSION}]" &&  cat release.notes.new release.notes.old) > release.notes
            ###################3
            # TODO: we should add the release notes somewhere at some point
            # now we just don't do it because main branch is protected
            # and we can't push directly from the CI
            #git add release.notes
            #git commit -m "docs: Add release notes for $NEW_VERSION"
            # Stash is mandatory not to leave the repo dirty
            git stash
            ########################
            git show
            # Create the tag
            git tag "$NEW_VERSION"
            echo "create-release=true" >> $GITHUB_OUTPUT
            echo "new-version=$NEW_VERSION" >> $GITHUB_OUTPUT
          fi
      - name: Build distributions
        run: |
          for pkg_dir in $PWD/diracx-*; do
            echo "Building $pkg_dir"
            python -m build --outdir $PWD/dist $pkg_dir
          done
          # Also build the diracx metapackage
          python -m build --outdir $PWD/dist .
      - name: 'Upload Artifact'
        uses: actions/upload-artifact@v4
        with:
          name: diracx-whl
          path: dist/diracx*.whl
          retention-days: 5
      - name: Make release on GitHub
        if: steps.check-tag.outputs.create-release == 'true'
        run: |
          set -e
          export NEW_VERSION=${{ steps.check-tag.outputs.new-version }}
          REFERENCE_BRANCH=${GITHUB_REF##refs*(/heads)/}
          echo "Pushing tagged release notes to ${REFERENCE_BRANCH}"
          git push "origin" "${REFERENCE_BRANCH}"
          echo "Making GitHub release for ${NEW_VERSION}"
          .github/workflows/make_release.py \
            --repo="${{ github.repository }}" \
            --token="${{ secrets.GITHUB_TOKEN }}" \
            --version="${NEW_VERSION}" \
            --rev="$(git rev-parse HEAD)" \
            --release-notes-fn="release.notes.new"
      # Use trusted publisher for pypi
      # https://docs.pypi.org/trusted-publishers/
      - name: Publish package on PyPI
        if: steps.check-tag.outputs.create-release == 'true'
        uses: pypa/gh-action-pypi-publish@release/v1

  docker:
    needs: deploy-pypi
    timeout-minutes:  30
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v5
      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3
      - name: Login to GitHub container registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - name: Download diracx wheels
        uses: actions/download-artifact@v5
        with:
            name: diracx-whl
      - name: "Find wheels"
        id: find_wheel
        run: |
          # We need to copy them there to be able to access them in the RUN --mount
          cp diracx*.whl containers/client/
          cp diracx*.whl containers/services/
          for wheel_fn in *.whl; do
            pkg_name=$(basename "${wheel_fn}" | cut -d '-' -f 1)
            echo "${pkg_name}-wheel-name=$(ls "${pkg_name}"-*.whl)" >> $GITHUB_OUTPUT
          done

      - name: Build and push client (release)
        uses: docker/build-push-action@v6
        if: ${{ needs.deploy-pypi.outputs.create-release == 'true' }}
        with:
          context: containers/client/
          push: ${{ needs.deploy-pypi.outputs.create-release == 'true' }}
          tags: "ghcr.io/diracgrid/diracx/client:${{ needs.deploy-pypi.outputs.new-version }}"
          platforms: linux/amd64,linux/arm64
          build-args: EXTRA_PACKAGES_TO_INSTALL=DIRACCommon~=9.0.0a1
      - name: Build and push services (release)
        uses: docker/build-push-action@v6
        if: ${{ needs.deploy-pypi.outputs.create-release == 'true' }}
        with:
          context: containers/services/
          push: ${{ needs.deploy-pypi.outputs.create-release == 'true' }}
          tags: "ghcr.io/diracgrid/diracx/services:${{ needs.deploy-pypi.outputs.new-version }}"
          platforms: linux/amd64,linux/arm64
          build-args: EXTRA_PACKAGES_TO_INSTALL=DIRACCommon~=9.0.0a1

      - name: Build and push client (dev)
        uses: docker/build-push-action@v6
        with:
          context: containers/client/
          push: ${{ github.event_name != 'pull_request' && github.repository == 'DIRACGrid/diracx' && github.ref_name == 'main' }}
          tags: ghcr.io/diracgrid/diracx/client:dev
          platforms: linux/amd64,linux/arm64
          build-args: |
            EXTRA_PACKAGES_TO_INSTALL=git+https://github.com/DIRACGrid/DIRAC.git@integration#egg=diraccommon\&subdirectory=dirac-common
      - name: Build and push services (dev)
        uses: docker/build-push-action@v6
        with:
          context: containers/services/
          push: ${{ github.event_name != 'pull_request' && github.repository == 'DIRACGrid/diracx' && github.ref_name == 'main' }}
          tags: ghcr.io/diracgrid/diracx/services:dev
          platforms: linux/amd64,linux/arm64
          build-args: |
            EXTRA_PACKAGES_TO_INSTALL=git+https://github.com/DIRACGrid/DIRAC.git@integration#egg=diraccommon\&subdirectory=dirac-common

  update-charts:
    name: Update Helm charts
    needs:
      - deploy-pypi
      - docker
    runs-on: ubuntu-latest
    if: ${{ needs.deploy-pypi.outputs.create-release == 'true' }}
    steps:
      - name: Checkout diracx
        uses: actions/checkout@v5
        with:
          path: diracx

      - name: Checkout diracx-charts
        uses: actions/checkout@v5
        with:
          repository: DIRACGrid/diracx-charts
          token: ${{ secrets.CHARTS_UPDATE_TOKEN }}
          path: diracx-charts

      - name: Configure Git
        run: |
          cd diracx-charts
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"

      - name: Update chart versions
        id: update-versions
        run: |
          cd diracx-charts
          VERSION="${{ needs.deploy-pypi.outputs.new-version }}"

          # Get current chart version before updating
          CURRENT_CHART_VERSION=$(grep '^version:' diracx/Chart.yaml | sed 's/version: //' | tr -d '"')

          # Use Python script to update versions
          python ../diracx/.github/workflows/update_chart_version.py \
            --charts-dir . \
            --diracx-version "$VERSION"

          # Get new chart version after update
          NEW_CHART_VERSION=$(grep '^version:' diracx/Chart.yaml | sed 's/version: //' | tr -d '"')

          echo "current_chart_version=$CURRENT_CHART_VERSION" >> $GITHUB_OUTPUT
          echo "new_chart_version=$NEW_CHART_VERSION" >> $GITHUB_OUTPUT
          echo "diracx_version=$VERSION" >> $GITHUB_OUTPUT

      - name: Install pre-commit
        run: |
          pip install pre-commit

      - name: Run pre-commit to update README
        run: |
          cd diracx-charts
          pre-commit run --all-files || true

      - name: Commit and push changes
        if: success()
        run: |
          cd diracx-charts

          # Stage all changes
          git add -A

          # Check if there are changes to commit
          if ! git diff --cached --quiet; then
            # Commit the changes
            git commit -m "chore: bump chart to ${{ steps.update-versions.outputs.new_chart_version }} for DiracX ${{ steps.update-versions.outputs.diracx_version }}

            - Update appVersion to ${{ steps.update-versions.outputs.diracx_version }}
            - Update image tag to ${{ steps.update-versions.outputs.diracx_version }}
            - Bump chart version from ${{ steps.update-versions.outputs.current_chart_version }} to ${{ steps.update-versions.outputs.new_chart_version }}"

            # Push the commit to main branch
            git push origin main

            echo "✅ Successfully pushed chart version ${{ steps.update-versions.outputs.new_chart_version }} and tag ${TAG_NAME}"
          else
            echo "No changes to commit"
          fi
