changesette 0.1.1

A version and changelog manager for single-package applications, 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@6a1bd70eaac3c8bdf093356838d7ee09fda951cf # v2.85.5
        with:
          tool: cargo-edit@0.13.13

      - name: Bump version
        id: version
        run: |
          next="$(cargo run --release -- version)"
          echo "next=$next" >> "$GITHUB_OUTPUT"
          if [[ -n "$next" ]]; then
            cargo set-version "$next"
            cargo update -w
            delim="$(openssl rand -hex 16)"
            {
              echo "changelog<<$delim"
              cargo run --release -- changelog "$next"
              echo "$delim"
            } >> "$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
        uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
        with:
          token: ${{ steps.generate-token.outputs.token }}
          branch: changesette/release
          commit-message: Release v${{ steps.version.outputs.next }}
          title: Release v${{ steps.version.outputs.next }}
          body: ${{ steps.version.outputs.changelog }}
          delete-branch: true

      - name: Determine the version to release
        id: release
        if: steps.version.outputs.next == ''
        run: |
          v="$(cargo run --release -- current)"
          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 }}