feather-reader 0.4.0

A minimalist, atproto-native RSS/Atom reader in Rust — your feed subscriptions live in your own PDS.
Documentation
name: Release crate (crates.io)

# Publishes feather-reader to crates.io on a version tag using crates.io
# TRUSTED PUBLISHING (OIDC) — no long-lived API token stored in the repo. This
# workflow exchanges a short-lived GitHub OIDC token for a temporary, scoped
# crates.io token via rust-lang/crates-io-auth-action, then runs `cargo publish`.
#
# ── ONE-TIME SETUP (Justin) ───────────────────────────────────────────────────
#   1. crates.io → the `feather-reader` crate → Settings → Trusted Publishing →
#      add a GitHub publisher:  owner `justin-stanley`, repo `feather-reader`,
#      workflow `release-crate.yml` (environment optional).
#   2. Once the first OIDC publish succeeds, REVOKE the manually-created API
#      token that claimed v0.1.0 — it's no longer needed.
#
# ── RELEASING ─────────────────────────────────────────────────────────────────
#   Bump `version` in Cargo.toml, commit, then push a matching tag:
#     git tag v0.2.0 && git push origin v0.2.0
#   The tag must equal Cargo.toml's version (enforced below) so a mistagged push
#   can't publish the wrong version.

# ── ORDER ─────────────────────────────────────────────────────────────────────
#   This runs AFTER release-image succeeds for the same tag, not alongside it.
#   release-image holds the upgrade-boot gate; publishing a crate whose image
#   cannot start against an existing database is how 0.3.9 shipped (and had to
#   be yanked). A failed gate now publishes nothing anywhere.
#
#   `workflow_run` fires from the DEFAULT branch's copy of this file, so the
#   tag comes from `workflow_run.head_branch` and the commit from `head_sha` —
#   not from github.ref, which is main here. Trusted Publishing keys on this
#   file's name, which is unchanged.

on:
  workflow_run:
    workflows: [release-image]
    types: [completed]
  workflow_dispatch:

permissions:
  contents: read
  id-token: write   # REQUIRED: mint the OIDC token for crates.io Trusted Publishing

concurrency:
  group: release-crate-${{ github.event.workflow_run.head_branch || github.ref }}
  cancel-in-progress: false

jobs:
  publish:
    name: cargo publish (OIDC)
    # GitHub-hosted: OIDC needs GitHub's token endpoint, and hosted Actions are
    # free once the repo is public. Skip while private so a stray tag can't burn
    # minutes / fail before Trusted Publishing is configured.
    #
    # Also require a version-TAG ref: this job publishes a release, so it only
    # makes sense on `refs/tags/vX.Y.Z`. Without this, `workflow_dispatch` from a
    # branch (e.g. main) would reach the "Verify tag matches Cargo.toml" step with
    # GITHUB_REF_NAME=main -> tag "vmain" -> a confusing hard failure. Gating here
    # makes a branch dispatch a clean no-op; dispatch against the tag still works.
    #
    # Under workflow_run: only a SUCCESSFUL release-image run that was itself
    # triggered by a version tag. Under workflow_dispatch: only against a tag.
    if: >-
      ${{ github.event.repository.private == false && (
        (github.event_name == 'workflow_run'
          && github.event.workflow_run.conclusion == 'success'
          && github.event.workflow_run.event == 'push'
          && startsWith(github.event.workflow_run.head_branch, 'v'))
        || (github.event_name == 'workflow_dispatch' && startsWith(github.ref, 'refs/tags/v'))
      ) }}
    runs-on: ubuntu-latest
    env:
      RELEASE_TAG: ${{ github.event.workflow_run.head_branch || github.ref_name }}
      RELEASE_SHA: ${{ github.event.workflow_run.head_sha || github.sha }}
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
        with:
          ref: ${{ env.RELEASE_SHA }}

      - name: Install stable toolchain
        uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable
        with:
          toolchain: stable

      - name: Verify tag matches Cargo.toml version
        run: |
          set -euo pipefail
          tag="${RELEASE_TAG#v}"
          crate="$(cargo metadata --no-deps --format-version 1 | jq -r '.packages[0].version')"
          echo "tag=v$tag  Cargo.toml=$crate"
          if [ "$tag" != "$crate" ]; then
            echo "::error::tag v$tag does not match Cargo.toml version $crate"
            exit 1
          fi

      - name: Authenticate to crates.io (Trusted Publishing / OIDC)
        id: auth
        uses: rust-lang/crates-io-auth-action@c6f97d42243bad5fab37ca0427f495c86d5b1a18 # v1.0.5

      - name: cargo publish
        env:
          CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
        run: cargo publish --locked