changesette 3.0.0

A version and changelog manager using the changesets file format
name: Version

on:
  push:
    branches:
      - main

permissions: {}

defaults:
  run:
    shell: bash

concurrency:
  group: ${{ github.workflow }}

jobs:
  version:
    runs-on: ubuntu-latest

    timeout-minutes: 30

    steps:
      - name: Checkout
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
        with:
          persist-credentials: false

      - name: Install cargo-edit
        uses: taiki-e/install-action@7f4eb899022d8fe70b20c4f3de697aa85c309026 # v2.85.11
        with:
          tool: cargo-edit@0.13.13

      - name: Bump version
        id: version
        run: |
          cargo run --release -- version --output "$RUNNER_TEMP/plan.json"
          if release="$(jq -e '[.releases[] | select(.type != "none")][0]' "$RUNNER_TEMP/plan.json")"; then
            version="$(jq -re '.newVersion' <<< "$release")"
            echo "title=Release v$version" >> "$GITHUB_OUTPUT"
            delim="$(openssl rand -hex 16)"
            {
              echo "body<<$delim"
              jq -re '.changelogEntry' <<< "$release"
              echo "$delim"
            } >> "$GITHUB_OUTPUT"
            cargo set-version "$version"
            cargo update -w
          else
            echo "title=Consume changesets" >> "$GITHUB_OUTPUT"
          fi

      - name: Generate token
        id: generate-token
        uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
        with:
          client-id: ${{ vars.BOT_CLIENT_ID }}
          private-key: ${{ secrets.BOT_PRIVATE_KEY }}
          permission-contents: write
          permission-pull-requests: write

      - name: Create pull request
        id: pr
        uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
        with:
          token: ${{ steps.generate-token.outputs.token }}
          branch: changesette/release
          commit-message: ${{ steps.version.outputs.title }}
          title: ${{ steps.version.outputs.title }}
          body: ${{ steps.version.outputs.body }}
          delete-branch: true
          sign-commits: true

      - name: Determine the version to release
        id: release
        if: steps.pr.outputs.pull-request-number == ''
        run: |
          v="$(jq -re .version package.json)"
          if [[ -z "$(git ls-remote origin "refs/tags/changesette-v$v")" ]]; then
            echo "version=$v" >> "$GITHUB_OUTPUT"
          fi

    outputs:
      release-version: ${{ steps.release.outputs.version }}

  release:
    needs: version

    if: needs.version.outputs.release-version != ''

    runs-on: ubuntu-latest

    permissions:
      id-token: write # crates.io Trusted Publishing (OIDC)

    timeout-minutes: 30

    steps:
      - name: Checkout
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
        with:
          persist-credentials: false

      - name: Authenticate with crates.io
        id: auth
        uses: rust-lang/crates-io-auth-action@c6f97d42243bad5fab37ca0427f495c86d5b1a18 # v1.0.5

      - name: Publish to crates.io
        run: |
          if curl -fsS https://index.crates.io/ch/an/changesette \
              | jq -e --arg v "$VERSION" 'select(.vers == $v)' >/dev/null; then
            echo "changesette $VERSION already on crates.io; skipping publish" >&2
          else
            cargo publish
          fi
        env:
          VERSION: ${{ needs.version.outputs.release-version }}
          CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}

      - name: Generate token
        id: generate-token
        uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
        with:
          client-id: ${{ vars.BOT_CLIENT_ID }}
          private-key: ${{ secrets.BOT_PRIVATE_KEY }}
          permission-contents: write

      - name: Push release tag
        run: |
          git tag "changesette-v$VERSION"
          git -c credential.helper='!gh auth git-credential' \
            push origin "changesette-v$VERSION"
        env:
          GH_TOKEN: ${{ steps.generate-token.outputs.token }}
          VERSION: ${{ needs.version.outputs.release-version }}