name: Release

on:
  workflow_dispatch:
    inputs:
      version:
        description: "Version to release (e.g. v1.2.3)"
        required: true
      kind:
        description: "Release kind"
        type: choice
        options: [minor, patch]
        required: true
        default: "minor"

concurrency:
  group: ${{ github.ref }}
  cancel-in-progress: true
jobs:
  verify-inputs:
    name: Verify inputs
    runs-on: ubuntu-22.04
    env:
      FULL_VERSION: ${{ inputs.version }}
    outputs:
      WITHOUT_V: ${{ steps.version-info.outputs.WITHOUT_V }}
      PART_MAJOR: ${{ steps.version-info.outputs.PART_MAJOR }}
      PART_MINOR: ${{ steps.version-info.outputs.PART_MINOR }}
      PART_PATCH: ${{ steps.version-info.outputs.PART_PATCH }}
      MAJOR: ${{ steps.version-info.outputs.MAJOR }}
      MAJOR_MINOR: ${{ steps.version-info.outputs.MAJOR_MINOR }}
      MAJOR_MINOR_PATCH: ${{ steps.version-info.outputs.MAJOR_MINOR_PATCH }}
      RELEASE_BRANCH: ${{ steps.version-info.outputs.RELEASE_BRANCH }}
      WORKING_BRANCH: ${{ steps.version-info.outputs.WORKING_BRANCH }}
    steps:
      - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0

      - name: Working branch
        run: echo "WORKING_BRANCH=$(git branch --show-current)" | tee -a "$GITHUB_ENV"

      - name: Verify version
        run: |
          if [[ ! "${FULL_VERSION}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
            echo "Version must be in the form of vX.Y.Z"
            exit 1
          fi

      - name: Verify temporary branch
        run: |
          if [[ ! "${WORKING_BRANCH}" =~ ^tmp/v[0-9]+\.[0-9]+\.[0-9] ]]; then
            echo "Workflow can only be triggered from a temporary branch in the form of tmp/vX.Y.Z"
            exit 1
          fi

      - name: Extract version info
        id: version-info
        run: |
          WITHOUT_V=${FULL_VERSION#v}
          PART_MAJOR=${WITHOUT_V%%.*}
          PART_MINOR=${WITHOUT_V#*.}
          PART_MINOR=${PART_MINOR%%.*}
          PART_PATCH=${WITHOUT_V##*.}
          {
            echo "WITHOUT_V=${WITHOUT_V}"
            echo "PART_MAJOR=${PART_MAJOR}"
            echo "PART_MINOR=${PART_MINOR}"
            echo "PART_PATCH=${PART_PATCH}"
            echo "MAJOR=${PART_MAJOR}"
            echo "MAJOR_MINOR=${PART_MAJOR}.${PART_MINOR}"
            echo "MAJOR_MINOR_PATCH=${PART_MAJOR}.${PART_MINOR}.${PART_PATCH}"
            echo "RELEASE_BRANCH=release/v${PART_MAJOR}.${PART_MINOR}"
            echo "WORKING_BRANCH=${WORKING_BRANCH}"
          } | tee -a "$GITHUB_OUTPUT"

  docs:
    name: Create docs release (from main)
    runs-on: ubuntu-22.04
    if: inputs.kind == 'minor'
    needs: verify-inputs
    permissions:
      contents: write
      pull-requests: write
    env:
      VERSION: ${{ inputs.version }}
      MAJOR_MINOR: ${{ needs.verify-inputs.outputs.MAJOR_MINOR }}
      BRANCH: docs/${{ needs.verify-inputs.outputs.MAJOR_MINOR }}
    steps:
      - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
        with:
          ref: main

      - name: Create docs release
        working-directory: docs
        run: |
          npm install
          npm run docusaurus docs:version "${MAJOR_MINOR}"

      - name: Create docs pull request
        uses: peter-evans/create-pull-request@153407881ec5c347639a548ade7d8ad1d6740e38 # v5.0.2
        with:
          branch: ${{ env.BRANCH }}
          base: main
          title: "docs: add release ${{ env.VERSION }}"
          body: |
            :robot: *This is an automated PR.* :robot:

            The PR is triggered as part of the automated release process of version ${{ env.VERSION }}.
            It releases a new version of the documentation.
          commit-message: "docs: add release ${{ env.VERSION }}"
          committer: edgelessci <edgelessci@users.noreply.github.com>
          labels: no changelog
          # We need to push changes using a token, otherwise triggers like on:push and on:pull_request won't work.
          token: ${{ !github.event.pull_request.head.repo.fork && secrets.CI_COMMIT_PUSH_PR || '' }}

  check-working-branch:
    name: Check temporary working branch
    runs-on: ubuntu-22.04
    needs: verify-inputs
    permissions:
      contents: write
    env:
      RELEASE_BRANCH: ${{ needs.verify-inputs.outputs.RELEASE_BRANCH }}
      WORKING_BRANCH: ${{ needs.verify-inputs.outputs.WORKING_BRANCH }}
    steps:
      - name: Checkout
        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
        with:
          ref: ${{ needs.verify-inputs.outputs.WORKING_BRANCH }}

      - name: Check if we are strictly ahead of the release branch (if it exists)
        run: |
          git fetch
          git pull
          git checkout "${RELEASE_BRANCH}" || exit 0
          git checkout "${WORKING_BRANCH}"
          ahead=$(git rev-list HEAD --not "${RELEASE_BRANCH}"  | wc -l)
          if [[ "${ahead}" -eq 0 ]]; then
            echo "The current branch is not strictly ahead of the release branch. Please rebase."
            exit 1
          fi

      - name: Write version to version.txt
        run: |
          git checkout "${WORKING_BRANCH}"
          echo "${{ inputs.version }}" > version.txt
          git config --global user.name "edgelessci"
          git config --global user.email "edgelessci@users.noreply.github.com"
          git add version.txt
          git diff --staged --quiet || git commit -m "chore: update version.txt to ${{ inputs.version }}"
          git push origin "${WORKING_BRANCH}"

  update-versions:
    name: Update container image versions
    needs: [verify-inputs, check-working-branch]
    runs-on: ubuntu-22.04
    permissions:
      contents: write
      packages: read
    env:
      VERSION: ${{ inputs.version }}
      WITHOUT_V: ${{ needs.verify-inputs.outputs.WITHOUT_V }}
    steps:
      - name: Checkout
        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
        with:
          ref: ${{ needs.verify-inputs.outputs.WORKING_BRANCH }}

      - name: Update enterprise image version
        run: |
          defaultVersionReg='defaultImage = \"[^\"]*\"'

          # Ensure regexp matches (otherwise the file was changed or the workflow is broken).
          grep -E "${defaultVersionReg}" internal/config/image_enterprise.go

          # Update version.
          sed -i "s/${defaultVersionReg}/defaultImage = \"${VERSION}\"/" internal/config/image_enterprise.go
          git add internal/config/image_enterprise.go

      - name: Update s3proxy Chart version
        run: |
          yq eval -i ".version = \"$WITHOUT_V\"" s3proxy/deploy/s3proxy/Chart.yaml
          yq eval -i ".image = \"ghcr.io/edgelesssys/constellation/s3proxy:$VERSION\"" s3proxy/deploy/s3proxy/values.yaml

          git add s3proxy/deploy/s3proxy/Chart.yaml

      - name: Commit
        run: |
          git config --global user.name "edgelessci"
          git config --global user.email "edgelessci@users.noreply.github.com"
          if git diff-index --quiet HEAD --; then
            echo "No changes to commit"
          else
            git commit -m "deps: update versions to ${VERSION}"
            git push
          fi

      - name: Publish s3proxy
        uses: ./.github/actions/publish_helmchart
        with:
          chartPath: ${{ github.workspace }}/s3proxy/deploy/s3proxy
          githubToken: ${{ secrets.CI_GITHUB_REPOSITORY }}

  os-image:
    name: Build OS image
    needs: [verify-inputs, update-versions]
    uses: ./.github/workflows/build-os-image.yml
    permissions:
      id-token: write
      contents: read
      packages: read
    secrets: inherit
    with:
      imageVersion: ${{ inputs.version }}
      isRelease: true
      stream: "stable"
      ref: ${{ needs.verify-inputs.outputs.WORKING_BRANCH }}

  update-hardcoded-measurements:
    name: Update hardcoded measurements (in the CLI)
    needs: [verify-inputs, os-image]
    permissions:
      contents: write
    runs-on: ubuntu-22.04
    env:
      VERSION: ${{ inputs.version }}
      WITHOUT_V: ${{ needs.verify-inputs.outputs.WITHOUT_V }}
    steps:
      - name: Checkout
        uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
        with:
          ref: ${{ needs.verify-inputs.outputs.WORKING_BRANCH }}

      - name: Setup Go environment
        uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
        with:
          go-version: "1.21.5"
          cache: true

      - name: Build generateMeasurements tool
        working-directory: internal/attestation/measurements/measurement-generator
        run: go build -o generate -tags=enterprise .

      - name: Update hardcoded measurements
        working-directory: internal/attestation/measurements
        run: |
          ./measurement-generator/generate
          git add measurements_enterprise.go

      - name: Commit
        run: |
          git config --global user.name "edgelessci"
          git config --global user.email "edgelessci@users.noreply.github.com"
          git commit -m "attestation: hardcode measurements for ${VERSION}"
          git push

  draft-release:
    name: Draft release (CLI)
    needs: [verify-inputs, update-hardcoded-measurements]
    uses: ./.github/workflows/draft-release.yml
    permissions:
      actions: read
      contents: write
      id-token: write
      packages: write
    secrets: inherit
    with:
      versionName: ${{ inputs.version }}
      ref: ${{ needs.verify-inputs.outputs.WORKING_BRANCH }}
      pushContainers: true
      key: 'release'

  e2e-tests:
    name: Run E2E tests
    needs: [verify-inputs, draft-release]
    uses: ./.github/workflows/e2e-test-release.yml
    permissions:
      checks: write
      packages: write
      id-token: write
      contents: read
    secrets: inherit
    with:
      ref: ${{ needs.verify-inputs.outputs.WORKING_BRANCH }}
      targetVersion: ${{ inputs.version }}

  mini-e2e:
    name: Run mini E2E tests
    needs: [verify-inputs, draft-release]
    uses: ./.github/workflows/e2e-mini.yml
    permissions:
      checks: write
      packages: write
      id-token: write
      contents: read
    secrets: inherit
    with:
      ref: ${{ needs.verify-inputs.outputs.WORKING_BRANCH }}
