name: Release
on:
  push:
    branches:
      - 17.x.x
permissions: {}
jobs:
  check-publish:
    name: Check for publish need and prepare artifacts
    # Keep this guard on every job for defense-in-depth in case job dependencies are refactored.
    if: ${{ !github.event.repository.fork && github.repository == 'graphql/graphql-js' && github.ref_name == '17.x.x' }}
    runs-on: ubuntu-latest
    outputs:
      should_publish: ${{ steps.release_metadata.outputs.should_publish }}
      tag: ${{ steps.release_metadata.outputs.tag }}
      dist_tag: ${{ steps.release_metadata.outputs.dist_tag }}
      latest: ${{ steps.release_metadata.outputs.latest }}
      prerelease: ${{ steps.release_metadata.outputs.prerelease }}
    concurrency:
      group: ${{ github.workflow }}-${{ github.ref_name }}
      cancel-in-progress: true
    permissions:
      contents: read # for actions/checkout
    steps:
      - name: Checkout repo
        uses: actions/checkout@v6
        with:
          # Keep checkout fast: we should only need to scroll back a few
          # commits for release notes. If the release commit is older than
          # this depth, release:metadata will emit empty release notes.
          fetch-depth: 10
          persist-credentials: false

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          cache: npm
          node-version-file: '.node-version'

      - name: Install Dependencies
        run: npm ci --ignore-scripts

      - name: Read release metadata
        id: release_metadata
        run: |
          release_metadata_json="$(npm run --silent release:metadata)"
          jq -r '
            "version=\(.version)",
            "tag=\(.tag)",
            "dist_tag=\(.distTag)",
            "latest=\(.latest)",
            "prerelease=\(.prerelease)",
            "package_spec=\(.packageSpec)",
            "should_publish=\(.shouldPublish)"
          ' <<< "${release_metadata_json}" >> "${GITHUB_OUTPUT}"
          jq -r '.releaseNotes' <<< "${release_metadata_json}" > ./release-notes.md

      - name: Log publish decision
        run: |
          if [ "${{ steps.release_metadata.outputs.should_publish }}" = "true" ]; then
            echo "${{ steps.release_metadata.outputs.package_spec }} is not published yet."
          else
            echo "${{ steps.release_metadata.outputs.package_spec }} is already published."
          fi

      - name: Build NPM package
        if: steps.release_metadata.outputs.should_publish == 'true'
        run: npm run build:npm

      - name: Upload npmDist package
        if: steps.release_metadata.outputs.should_publish == 'true'
        uses: actions/upload-artifact@v7
        with:
          name: npmDist
          path: ./npmDist

      - name: Build Deno package
        if: steps.release_metadata.outputs.should_publish == 'true'
        run: npm run build:deno

      - name: Upload denoDist package
        if: steps.release_metadata.outputs.should_publish == 'true'
        uses: actions/upload-artifact@v7
        with:
          name: denoDist
          path: ./denoDist

      - name: Upload release notes
        if: steps.release_metadata.outputs.should_publish == 'true'
        uses: actions/upload-artifact@v7
        with:
          name: release-notes
          path: ./release-notes.md

  publish-npm:
    name: Publish npm package
    needs: check-publish
    # Keep this guard on every job for defense-in-depth in case job dependencies are refactored.
    if: ${{ !github.event.repository.fork && github.repository == 'graphql/graphql-js' && github.ref_name == '17.x.x' && needs.check-publish.outputs.should_publish == 'true' }}
    runs-on: ubuntu-latest
    environment: release
    permissions:
      contents: read # for actions/checkout
      id-token: write # for npm trusted publishing via OIDC
    steps:
      - name: Checkout repo
        uses: actions/checkout@v6
        with:
          persist-credentials: false

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version-file: '.node-version'

      - name: Download npmDist package
        uses: actions/download-artifact@v8
        with:
          name: npmDist
          path: ./npmDist

      - name: Publish to npm
        working-directory: ./npmDist
        run: |
          npm publish --provenance --tag "${{ needs.check-publish.outputs.dist_tag }}"

  publish-jsr:
    name: Publish JSR package
    needs: check-publish
    # Keep this guard on every job for defense-in-depth in case job dependencies are refactored.
    if: ${{ !github.event.repository.fork && github.repository == 'graphql/graphql-js' && github.ref_name == '17.x.x' && needs.check-publish.outputs.should_publish == 'true' }}
    runs-on: ubuntu-latest
    environment: release
    permissions:
      contents: read # for actions/download-artifact
      id-token: write # for JSR trusted publishing via OIDC
    steps:
      - name: Download denoDist package
        uses: actions/download-artifact@v8
        with:
          name: denoDist
          path: ./denoDist

      - name: Setup Deno
        uses: denoland/setup-deno@v2
        with:
          deno-version: v2.x

      - name: Publish to JSR
        working-directory: ./denoDist
        run: deno publish

  create-release:
    name: Create release
    needs: check-publish
    # Keep this guard on every job for defense-in-depth in case job dependencies are refactored.
    if: ${{ !github.event.repository.fork && github.repository == 'graphql/graphql-js' && github.ref_name == '17.x.x' && needs.check-publish.outputs.should_publish == 'true' }}
    runs-on: ubuntu-latest
    environment: release
    permissions:
      contents: write # for creating GitHub release
    steps:
      - name: Checkout repo
        uses: actions/checkout@v6
        with:
          persist-credentials: false

      - name: Download release notes
        uses: actions/download-artifact@v8
        with:
          name: release-notes
          path: ./artifacts

      - name: Create release
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          tag="${{ needs.check-publish.outputs.tag }}"

          if gh release view "${tag}" > /dev/null 2>&1; then
            echo "GitHub release ${tag} already exists. Skipping release creation."
            exit 0
          fi

          if git ls-remote --exit-code --tags origin "refs/tags/${tag}" > /dev/null; then
            echo "Tag ${tag} already exists on origin."
          else
            git config user.name "github-actions[bot]"
            git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
            git tag -a "${tag}" "${GITHUB_SHA}" -m "${tag}"
            gh auth setup-git
            git push origin "refs/tags/${tag}"
            echo "Created annotated tag ${tag} at ${GITHUB_SHA}."
          fi

          release_notes_file="./artifacts/release-notes.md"

          if [ "${{ needs.check-publish.outputs.prerelease }}" = "true" ]; then
            gh release create "${tag}" \
              --verify-tag \
              --title "${tag}" \
              --notes-file "${release_notes_file}" \
              --prerelease
          else
            latest_flag="--latest=false"
            if [ "${{ needs.check-publish.outputs.latest }}" = "true" ]; then
              latest_flag="--latest"
            fi

            gh release create "${tag}" \
              --verify-tag \
              --title "${tag}" \
              --notes-file "${release_notes_file}" \
              "${latest_flag}"
          fi