name: release

on:
  workflow_dispatch:
    inputs:
      set-release-version:
        description: 'Desired delivery version (x.y.z)'
        required: true
        type: string

concurrency: release

jobs:
  set-context:
    env:
      GITHUB_CONTEXT: ${{ toJson(github) }}
      GITHUB_TOKEN: ${{ secrets.HURL_BOT_TOKEN }}
    outputs:
      release_version: ${{ steps.set-release-version.outputs.release_version }}
      release_branch: ${{ steps.set-release-branch.outputs.release_branch }}
    name: set-context
    runs-on: ubuntu-latest
    steps:
      - name: Check trigger branch
        run: |
          if [ $(echo "${{ github.ref_name }}" | grep -Ec "^master$|^release/") -eq 1 ] ; then
            echo "  - ✅ The branch triggering this workflow is ${{ github.ref_name }}."
          else
            echo "  - ❌ The branch triggering this workflow is ${{ github.ref_name }} instead of master or release/[0-9].[0-9].[0-9]."
            exit 1
          fi

      - name: Set release version
        id: set-release-version
        run: |
          echo "release_version=${{ github.event.inputs.set-release-version }}" | tee -a $GITHUB_OUTPUT

      - name: Set release branch
        id: set-release-branch
        run: |
          if [ $(echo "${{ github.ref_name }}" | grep -c "^release/") -eq 1 ] ; then
            echo "release_branch=${{ github.ref_name }}" | tee -a $GITHUB_OUTPUT
          else
            echo "release_branch=release/${{ github.event.inputs.set-release-version }}" | tee -a $GITHUB_OUTPUT
          fi

  clean-release:
    needs: set-context
    env:
      GITHUB_CONTEXT: ${{ toJson(github) }}
      GITHUB_TOKEN: ${{ secrets.HURL_BOT_TOKEN }}
    name: clean-release
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4.1.7

      - name: Check release pull request existence
        id: check-release-pull-request-existence
        run: |
          actual_pr_number=$(gh pr list --repo "${{ github.repository }}" --head "${{ needs.set-context.outputs.release_branch }}" --state "open" --json number --jq .[].number)
          actual_pr_number=${actual_pr_number:-0}
          echo "actual_pr_number=${actual_pr_number}" | tee -a "${GITHUB_OUTPUT}"
          if [ ${actual_pr_number} -eq 0 ] ; then
            echo "  - ✅ There is no pull request."
            echo "release_pr_exists=false" | tee -a $GITHUB_OUTPUT
          else
            echo "  - ✅ Actual pull request number is ${actual_pr_number}."
            echo "release_pr_exists=true" | tee -a $GITHUB_OUTPUT
          fi

      - name: Close actual pull request
        if: steps.check-release-pull-request-existence.outputs.release_pr_exists == 'true'
        run: |
          comment="  - ✅ Pull request n°${{ steps.check-release-pull-request-existence.outputs.actual_pr_number }} closed before opening new one."
          gh pr close "${{ steps.check-release-pull-request-existence.outputs.actual_pr_number }}" --comment "${comment}" --delete-branch && gh_exit_code=0 || gh_exit_code=$?
          if [ ${gh_exit_code} -eq 0 ] ; then
            echo "  - ${comment}"
          else
            comment="  - ❌ A problem occurs when attempting to close PR n°${{ steps.check-release-pull-request-existence.outputs.actual_pr_number }}."
            gh pr comment "${{ steps.check-release-pull-request-existence.outputs.actual_pr_number }}" --body "${comment} Please refer to ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID} logs."
            echo "  - ${comment}"
            exit 1
          fi

      - name: Check GitHub release existence
        id: check-github-release-existence
        run: |
          gh release list || true
          escaped_version=$(echo "${{ needs.set-context.outputs.release_version }}" | sed "s#\.#\\\.#g")
          github_release_exists=$(gh release list | (grep -c "${escaped_version}" || true))
          if [ ${github_release_exists} -eq 0 ] ; then
            echo "  - ✅ GitHub release  ${{ needs.set-context.outputs.release_version }} does not exist."
            echo "github_release_exists=false" | tee -a $GITHUB_OUTPUT
          else
            echo "  - ✅ GitHub release  ${{ needs.set-context.outputs.release_version }} already exists on remote."
            echo "github_release_exists=true" | tee -a $GITHUB_OUTPUT
          fi

      - name: Delete GitHub release
        if: steps.check-github-release-existence.outputs.github_release_exists == 'true'
        run: |
          gh release delete  ${{ needs.set-context.outputs.release_version }} --yes && gh_exit_code=0 || gh_exit_code=$?
          if [ ${gh_exit_code} -eq 0 ] ; then
            echo "  - ✅  ${{ needs.set-context.outputs.release_version }} GitHub release deleted."
          else
            echo "  - ❌ A problem occurs when attempting to delete  ${{ needs.set-context.outputs.release_version }} GitHub release."
            exit 1
          fi

      - name: Check tag existence
        id: check-tag-existence
        run: |
          escaped_version=$(echo "${{ needs.set-context.outputs.release_version }}" | sed "s#\.#\\\.#g")
          tag_exists=$(git ls-remote --tags | (grep -c "${escaped_version}" || true))
          if [ ${tag_exists} -eq 0 ] ; then
            echo "  - ✅ The origin/${{ needs.set-context.outputs.release_version }} tag does not exists on remote."
            echo "release_tag_exists=false" | tee -a $GITHUB_OUTPUT
          else
            echo "  - ✅ The origin/${{ needs.set-context.outputs.release_version }} tag already exists on remote."
            echo "release_tag_exists=true" | tee -a $GITHUB_OUTPUT
          fi

      - name: Delete release tag
        if: steps.check-tag-existence.outputs.release_tag_exists == 'true'
        run: |
          git push origin --delete ${{ needs.set-context.outputs.release_version }} && git_exit_code=0 || git_exit_code=$?
          if [ ${git_exit_code} -eq 0 ] ; then
            echo "  - ✅ ${{ needs.set-context.outputs.release_version }} tag deleted."
          else
            echo "  - ❌ A problem occurs when attempting to delete ${{ needs.set-context.outputs.release_version }} tag."
            exit 1
          fi

      - name: Check release branch existence
        id: check-release-branch-existence
        if: github.ref_name == 'master'
        run: |
          escaped_version=$(echo "${{ needs.set-context.outputs.release_version }}" | sed "s#\.#\\\.#g")
          branch_exists=$(git ls-remote | (grep -c "${escaped_version}" || true))
          if [ ${branch_exists} -eq 0 ] ; then
            echo "  - ✅ The origin/${{ needs.set-context.outputs.release_branch }} branch does not exists on remote."
            echo "release_branch_exists=false" | tee -a $GITHUB_OUTPUT
          else
            echo "  - ✅ The origin/${{ needs.set-context.outputs.release_branch }} branch already exists on remote."
            echo "release_branch_exists=true" | tee -a $GITHUB_OUTPUT
          fi

      - name: Delete release branch
        if: github.ref_name == 'master' && steps.check-release-branch-existence.outputs.release_branch_exists == 'true'
        run: |
          git push origin --delete ${{ needs.set-context.outputs.release_branch }} && git_exit_code=0 || git_exit_code=$?
          if [ ${git_exit_code} -eq 0 ] ; then
            echo "  - ✅ ${{ needs.set-context.outputs.release_branch }} branch deleted."
          else
            echo "  - ❌ A problem occurs when attempting to delete ${{ needs.set-context.outputs.release_branch }} branch."
            exit 1
          fi

  update-release-branch:
    needs:
      - set-context
      - clean-release
    env:
      GITHUB_CONTEXT: ${{ toJson(github) }}
      GITHUB_TOKEN: ${{ secrets.HURL_BOT_TOKEN }}
    name: update-release-branch
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        if: github.ref_name == 'master'
        uses: actions/checkout@v4.1.7

      - name: Create release branch
        if: github.ref_name == 'master'
        id: create-release-branch
        run: |
          git checkout -b "${{ needs.set-context.outputs.release_branch }}"
          git push origin "${{ needs.set-context.outputs.release_branch }}" && git_exit_code=0 || git_exit_code=$?
          if [ ${git_exit_code} -eq 0 ] ; then
            echo "  - ✅ ${{ needs.set-context.outputs.release_branch }} branch created."
          else
            echo "  - ❌ A problem occurs when attempting to create ${{ needs.set-context.outputs.release_branch }} branch."
            exit 1
          fi

      - name: Checkout new release branch
        uses: actions/checkout@v4.1.7
        with:
          ref: ${{ needs.set-context.outputs.release_branch }}

      - name: Check CHANGELOG
        run: |
          pip install beautifulsoup4
          bin/check/changelog.sh

      - name: Update version
        run: |
          hurl_packages="hurl_core hurl hurlfmt"
          for package in ${hurl_packages} ; do
            cargo_toml="packages/${package}/Cargo.toml"
            sed -i "s/^version.*/version = \"${{ needs.set-context.outputs.release_version }}\"/" "${cargo_toml}"
            echo "----------------------------"
            echo "  > package version for ${cargo_toml}"
            echo "      $(grep "^version =" "${cargo_toml}")"
            for dep_package in ${hurl_packages} ; do
              if [  $(grep -c "^${dep_package} =" "${cargo_toml}") -gt 0 ] ; then
                sed -i "s/^${dep_package} = { version .*/${dep_package} = { version = \"${{ needs.set-context.outputs.release_version }}\", path = \"..\/${dep_package}\" }/" "${cargo_toml}"
                echo "  > ${dep_package} dep package version for ${cargo_toml}"
                echo "      $(grep "^${dep_package} =" "${cargo_toml}")"
              fi
            done
          done

      - name: Cargo update
        run: |
          ./bin/update_crates.sh

      - name: Update installation doc
        run: |
          old_version=$(grep -E "^\\$ VERSION=" docs/installation.md | head -1 | cut --delimiter "=" --field 2)
          sed -i "s/${old_version}/${{ needs.set-context.outputs.release_version }}/g" docs/installation.md

      - name: Update man
        run: |
          for package in hurl hurlfmt ; do
            python3 bin/release/gen_manpage.py "docs/manual/${package}.md" > "docs/manual/${package}.1"
          done

      - name: Update general docs
        run: |
          python3 bin/docs/build_man_md.py docs/manual/hurl.md > docs/manual.md
          python3 bin/docs/build_readme.py github > README.md
          python3 bin/docs/build_readme.py crates > packages/hurl/README.md

      - name: Init git bot context
        uses: crazy-max/ghaction-import-gpg@v6.1.0
        with:
          gpg_private_key: ${{ secrets.HURL_BOT_GPG_PRIVATE_KEY }}
          passphrase: ${{ secrets.HURL_BOT_GPG_PRIVATE_KEY_PASSPHRASE }}
          git_committer_name: "hurl-bot"
          git_committer_email: "bot@hurl.dev"
          git_user_signingkey: true
          git_commit_gpgsign: true

      - name: Push create release commits
        run: |
          git diff --exit-code && diff=false || diff=true
          if [ "${diff}" == "true" ] ; then
            git commit -am "Create ${{ needs.set-context.outputs.release_version }} release"
            git push && git_exit_code=0 || git_exit_code=$?
            if [ ${git_exit_code} -eq 0 ] ; then
              echo "  - ✅ commits pushed to ${{ needs.set-context.outputs.release_branch }}."
            else
              echo "  - ❌ A problem occurs when attempting to push create release commits to ${{ needs.set-context.outputs.release_branch }} branch."
              exit 1
            fi
          else
            echo "  - ✅ no changes"
          fi

      - name: Archive artifacts
        uses: actions/upload-artifact@v4.3.6
        if: ${{ always() }}
        with:
          name: release-changelog
          path: |
            release_changelog.md

  package-release:
    needs:
      - set-context
      - clean-release
      - update-release-branch
    name: package-release
    uses: ./.github/workflows/package.yml
    with:
      branch: ${{ needs.set-context.outputs.release_branch }}

  deliver-github-release:
    env:
      GITHUB_CONTEXT: ${{ toJson(github) }}
      GITHUB_TOKEN: ${{ secrets.HURL_BOT_TOKEN }}
      REPO: ${{ github.repository }}
    needs:
      - set-context
      - clean-release
      - update-release-branch
      - package-release
    name: deliver-github-release
    runs-on: ubuntu-latest
    steps:
      - name: Checkout new release branch
        uses: actions/checkout@v4.1.7
        with:
          ref: ${{ needs.set-context.outputs.release_branch }}

      - name: Init git bot context
        uses: crazy-max/ghaction-import-gpg@v6.1.0
        with:
          gpg_private_key: ${{ secrets.HURL_BOT_GPG_PRIVATE_KEY }}
          passphrase: ${{ secrets.HURL_BOT_GPG_PRIVATE_KEY_PASSPHRASE }}
          git_committer_name: "hurl-bot"
          git_committer_email: "bot@hurl.dev"
          git_user_signingkey: true
          git_commit_gpgsign: true

      - uses: actions/download-artifact@v4.1.8
        with:
          path: artifacts

      - name: Push tag
        run: |
          git tag -a ${{ needs.set-context.outputs.release_version }} -m "Release ${{ needs.set-context.outputs.release_version }}"
          git tag -n
          git push --tags && git_exit_code=0 || git_exit_code=$?
          if [ ${git_exit_code} -eq 0 ] ; then
            echo "  - ✅ ${{ needs.set-context.outputs.release_version }} tag created."
            git fetch
          else
            echo "  - ❌ A problem occurs when attempting to create ${{ needs.set-context.outputs.release_version }} tag."
            exit 1
          fi

      - name: Create sha256sums
        run: |
            bin/release/sha256sum.sh --write \
            artifacts/release-deb-x64-artifacts/hurl_"${{ needs.set-context.outputs.release_version }}"_amd64.deb \
            artifacts/release-generic-linux-x64-artifacts/hurl-"${{ needs.set-context.outputs.release_version }}"-x86_64-unknown-linux-gnu.tar.gz \
            artifacts/release-macos-x64-artifacts/hurl-"${{ needs.set-context.outputs.release_version }}"-x86_64-apple-darwin.tar.gz \
            artifacts/release-macos-aarch64-artifacts/hurl-"${{ needs.set-context.outputs.release_version }}"-aarch64-apple-darwin.tar.gz \
            artifacts/release-windows-x64-artifacts/hurl-"${{ needs.set-context.outputs.release_version }}"-x86_64-pc-windows-msvc-installer.exe \
            artifacts/release-windows-x64-artifacts/hurl-"${{ needs.set-context.outputs.release_version }}"-x86_64-pc-windows-msvc.zip
            echo "file,sha256" > release-${{ needs.set-context.outputs.release_version }}.sha256.csv
            find ./artifacts -name "*sha256" | xargs -I FILE sh -c 'echo "$(basename FILE),$(cat FILE)"' >> release-${{ needs.set-context.outputs.release_version }}.sha256.csv

      - name: Archive sha256 artifacts
        uses: actions/upload-artifact@v4.3.6
        with:
          name: release-sha256-csv
          path: release-${{ needs.set-context.outputs.release_version }}.sha256.csv


      - name: Deliver release
        run: |
          echo "::group::Extract CHANGELOG"
            ls -l CHANGELOG.md
            cat CHANGELOG.md | python3 bin/release/changelog_extract.py ${{ needs.set-context.outputs.release_version }} > release_changelog.md
            ls -l release_changelog.md
            cat release_changelog.md
          echo "::endgroup::"
          echo "::group::List artifacts"
            ls -l \
                artifacts/release-deb-x64-artifacts/* \
                artifacts/release-generic-linux-x64-artifacts/* \
                artifacts/release-macos-x64-artifacts/* \
                artifacts/release-macos-aarch64-artifacts/* \
                artifacts/release-windows-x64-artifacts/*
          echo "::endgroup::"
          echo "::group::Deliver Release"
            gh release create ${{ needs.set-context.outputs.release_version }} \
                --target ${{ needs.set-context.outputs.release_branch }} \
                --notes-file release_changelog.md \
                --title ${{ needs.set-context.outputs.release_version }} \
                --draft \
                artifacts/release-deb-x64-artifacts/hurl_${{ needs.set-context.outputs.release_version }}_amd64.deb \
                artifacts/release-deb-x64-artifacts/hurl_${{ needs.set-context.outputs.release_version }}_amd64.deb.sha256 \
                artifacts/release-generic-linux-x64-artifacts/hurl-${{ needs.set-context.outputs.release_version }}-x86_64-unknown-linux-gnu.tar.gz \
                artifacts/release-generic-linux-x64-artifacts/hurl-${{ needs.set-context.outputs.release_version }}-x86_64-unknown-linux-gnu.tar.gz.sha256 \
                artifacts/release-macos-x64-artifacts/hurl-${{ needs.set-context.outputs.release_version }}-x86_64-apple-darwin.tar.gz \
                artifacts/release-macos-x64-artifacts/hurl-${{ needs.set-context.outputs.release_version }}-x86_64-apple-darwin.tar.gz.sha256 \
                artifacts/release-macos-aarch64-artifacts/hurl-${{ needs.set-context.outputs.release_version }}-aarch64-apple-darwin.tar.gz \
                artifacts/release-macos-aarch64-artifacts/hurl-${{ needs.set-context.outputs.release_version }}-aarch64-apple-darwin.tar.gz.sha256 \
                artifacts/release-windows-x64-artifacts/hurl-${{ needs.set-context.outputs.release_version }}-x86_64-pc-windows-msvc-installer.exe \
                artifacts/release-windows-x64-artifacts/hurl-${{ needs.set-context.outputs.release_version }}-x86_64-pc-windows-msvc-installer.exe.sha256 \
                artifacts/release-windows-x64-artifacts/hurl-${{ needs.set-context.outputs.release_version }}-x86_64-pc-windows-msvc.zip \
                artifacts/release-windows-x64-artifacts/hurl-${{ needs.set-context.outputs.release_version }}-x86_64-pc-windows-msvc.zip.sha256 && gh_exit_code=0 || gh_exit_code=$?
            if [ ${gh_exit_code} -eq 0 ] ; then
              echo "  - ✅ GitHub release ${{ needs.set-context.outputs.release_version }} created."
            else
               echo "  - ❌ A problem occurs when attempting to create GitHub release ${{ needs.set-context.outputs.release_version }}."
               exit 1
            fi
          echo "::endgroup::"

      - name: Check sha256 for published packages
        run: |
          .github/workflows/bin/check_release_assets_sha.sh \
              --release ${{ needs.set-context.outputs.release_version }} \
              --github-repo "${{ github.repository }}" \
              --github-token $GITHUB_TOKEN

      - name: Create new pull request
        run: |
          GITHUB_TOKEN=${{ secrets.HURL_BOT_TOKEN }}
          {
          echo "⚠ This is a GitHub releasing PR."
          echo "- Please use \`/accept\` as usual then run the \`update-branch-version\` github workflow if you want to automatically update master branch to next SNAPSHOT version"
          } > file-body.txt
          gh pr create \
            --title "Merge GitHub ${{ needs.set-context.outputs.release_branch }} into ${{ github.ref_name }}" \
            --body-file file-body.txt \
            --base master \
            --label bot && gh_exit_code=0 || gh_exit_code=$?
          if [ ${gh_exit_code} -eq 0 ] ; then
            new_pr_number=$(gh pr list --repo "${{ github.repository }}" --head "${{ needs.set-context.outputs.release_branch }}" --state "open" --json number --jq .[].number)
            echo "  - ✅ Creation of pull request n°${new_pr_number} succeeds."
          else
            echo "  - ❌ A problem occurs when attempting to create new pull request."
            exit 1
          fi
