name: Create Release

on:
  workflow_dispatch:

concurrency:
  group: publish-crates
  cancel-in-progress: false

jobs:
  publish:
    name: Publish crates
    runs-on: ubuntu-latest
    timeout-minutes: 30
    environment: release
    permissions:
      contents: write
      id-token: write

    steps:
      - name: Require a release branch
        shell: bash
        run: |
          if [[ "$GITHUB_REF" != "refs/heads/main" && ! "$GITHUB_REF_NAME" =~ ^releases/[0-9]+\.[0-9]+\.x$ ]]; then
            echo "Publishing must be run from main or a releases/<major>.<minor>.x branch; got $GITHUB_REF."
            exit 1
          fi

      - name: Check out repository
        uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
        with:
          fetch-depth: 0

      # Necessary as `cargo publish` builds crates as a check before publishing
      - name: Set up repository
        uses: ./.github/actions/setup
        with:
          mise-install-args: protoc

      - name: Read release metadata
        id: release
        shell: bash
        run: |
          metadata="$(cargo metadata --format-version 1 --no-deps)"
          version="$(jq -er '[.packages[] | select(.name == "temporalio-sdk") | .version] | if length == 1 then .[0] else error("expected one temporalio-sdk package") end' <<<"$metadata")"
          core_version="$(jq -er '[.packages[] | select(.name == "temporalio-sdk-core") | .version] | if length == 1 then .[0] else error("expected one temporalio-sdk-core package") end' <<<"$metadata")"

          if [[ "$GITHUB_REF_NAME" =~ ^releases/([0-9]+)\.([0-9]+)\.x$ ]]; then
            release_line="${BASH_REMATCH[1]}.${BASH_REMATCH[2]}"
            if [[ "$version" != "$release_line".* ]]; then
              echo "SDK version $version does not belong to release branch $GITHUB_REF_NAME."
              exit 1
            fi
          fi

          {
            echo "version=$version"
            echo "tag=v$version"
            echo "core_tag=core-v$core_version"
          } >>"$GITHUB_OUTPUT"

      - name: Generate release notes
        run: |
          previous_tag="$(git describe --tags --match 'v[0-9]*' --abbrev=0 HEAD)"
          cargo run -p changelog-release-notes -- \
            --from "$previous_tag" \
            --to HEAD \
            --changelog rust \
            >"$RUNNER_TEMP/sdk-release-notes.md"

          if ! previous_core_tag="$(git describe --tags --match 'core-v[0-9]*' --abbrev=0 HEAD 2>/dev/null)"; then
            previous_core_tag="$previous_tag"
          fi
          cargo run -p changelog-release-notes -- \
            --from "$previous_core_tag" \
            --to HEAD \
            --changelog core \
            >"$RUNNER_TEMP/core-release-notes.md"

      - name: Plan crate publication
        id: publish-plan
        run: cargo run --quiet -p changelog-release-notes --bin plan-release-publish >>"$GITHUB_OUTPUT"

      - name: Authenticate to crates.io
        if: steps.publish-plan.outputs.packages != '[]'
        id: auth
        uses: rust-lang/crates-io-auth-action@c6f97d42243bad5fab37ca0427f495c86d5b1a18 # v1

      - name: Publish crates
        if: steps.publish-plan.outputs.packages != '[]'
        env:
          CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
          PUBLISH_PACKAGES: ${{ steps.publish-plan.outputs.packages }}
        shell: bash
        run: |
          jq -e 'type == "array" and length > 0 and all(.[]; type == "string" and length > 0)' \
            <<<"$PUBLISH_PACKAGES" >/dev/null
          mapfile -t packages < <(jq -r '.[]' <<<"$PUBLISH_PACKAGES")
          publish_args=()
          for package in "${packages[@]}"; do
            publish_args+=(--package "$package")
          done
          cargo publish "${publish_args[@]}"

      - name: Create draft SDK GitHub release
        env:
          GH_TOKEN: ${{ github.token }}
          RELEASE_TAG: ${{ steps.release.outputs.tag }}
          RELEASE_TITLE: temporalio-sdk ${{ steps.release.outputs.tag }}
        run: |
          gh release create "$RELEASE_TAG" \
            --target "$GITHUB_SHA" \
            --draft \
            --title "$RELEASE_TITLE" \
            --notes-file "$RUNNER_TEMP/sdk-release-notes.md"

      - name: Create draft Core GitHub release
        env:
          GH_TOKEN: ${{ github.token }}
          RELEASE_TAG: ${{ steps.release.outputs.core_tag }}
          RELEASE_TITLE: temporalio-sdk-core ${{ steps.release.outputs.core_tag }}
        run: |
          gh release create "$RELEASE_TAG" \
            --target "$GITHUB_SHA" \
            --draft \
            --title "$RELEASE_TITLE" \
            --notes-file "$RUNNER_TEMP/core-release-notes.md"
