name: Publish Release

on:
  workflow_dispatch:
    inputs:
      branch:
        description: The branch to release from
        required: true
        default: master
      version:
        description: The version being published. This should be a valid semver version, such as `1.0.0`.
        required: true
        default: ''
        type: string
      dry-run:
        type: boolean
        description: Perform a publishing dry run. This will not publish the release, but will validate the release and log the commands that would be run.
        default: false

permissions:
  contents: read
  id-token: write # For publishing to NPM with provenance. Allows developers to run `npm audit signatures` and verify release signature of SDK. @see https://github.blog/2023-04-19-introducing-npm-package-provenance/

env:
  NODE_VERSION: 18
  NODE_ENV: development

jobs:
  configure:
    name: Validate input parameters
    runs-on: ubuntu-latest

    outputs:
      vtag: ${{ steps.vtag.outputs.vtag }} # The fully constructed release tag to use for publishing
      dry-run: ${{ steps.dry-run.outputs.dry-run }} # The dry-run flag to use for publishing, if applicable

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          ref: ${{ github.event.inputs.branch }}

      # Configure for dry-run, if applicable. @see https://docs.npmjs.com/cli/v9/commands/npm-publish#dry-run
      - id: dry-run
        if: ${{ github.event.inputs.dry-run == 'true' }}
        name: Configure for `--dry-run`
        run: |
          echo "dry-run=--dry-run" >> $GITHUB_ENV
          echo "dry-run=--dry-run" >> $GITHUB_OUTPUT

      # Build the tag string from package.json version and release suffix. Produces something like `1.0.0-beta.1` for a beta, or `1.0.0` for a stable release.
      - name: Build tag
        id: vtag
        run: |
          PACKAGE_VERSION="${{ github.event.inputs.version }}"
          echo "vtag=${PACKAGE_VERSION}" >> $GITHUB_ENV
          echo "vtag=${PACKAGE_VERSION}" >> $GITHUB_OUTPUT

      # Ensure tag does not already exist.
      - name: Validate version
        uses: actions/github-script@v6
        env:
          vtag: ${{ env.vtag }}
        with:
          script: |
            const releaseMeta = github.rest.repos.listReleases.endpoint.merge({
              owner: context.repo.owner,
              repo: context.repo.repo,
            });

            const releases = await github.paginate(releaseMeta);

            for (const release of releases) {
              if (release.name === process.env.vtag) {
                throw new Error(`${process.env.vtag} already exists`);
              }
            }

            console.log(`${process.env.vtag} does not exist. Proceeding with release.`)

  publish-npm:
    needs: configure

    name: Publish to NPM
    runs-on: ubuntu-latest
    environment: 'release'

    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          ref: ${{ github.event.inputs.branch }}

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: npm
          registry-url: 'https://registry.npmjs.org'

      - name: Install dependencies
        run: npm ci

      - name: Publish release to NPM
        run: npm publish --provenance ${{ needs.configure.outputs.dry-run }}
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
