diff --git a/.changeset/announce-releases-on-discord.md b/.changeset/announce-releases-on-discord.md new file mode 100644 index 00000000..a845151c --- /dev/null +++ b/.changeset/announce-releases-on-discord.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.github/workflows/announce.yml b/.github/workflows/announce.yml new file mode 100644 index 00000000..ffc20092 --- /dev/null +++ b/.github/workflows/announce.yml @@ -0,0 +1,38 @@ +name: announce + +# Re-sends, or previews, the Discord announcement of packages that are already +# published. The release workflow announces new releases on its own. +on: + workflow_dispatch: + inputs: + packages: + description: "Published packages, as name@version separated by commas (e.g. @wolfstar/plugin-api@3.1.0,@wolfstar/plugin-cache@0.4.0)" + type: string + required: true + dry-run: + description: Render into the job summary without sending anything + type: boolean + default: true + +permissions: {} + +concurrency: + group: ${{ github.workflow }} + cancel-in-progress: false + +jobs: + announce: + name: 📣 Announce packages + if: github.repository_owner == 'wolfstar-project' + permissions: + contents: read # the changelogs + pull-requests: read # pull request titles for the bullets + uses: wolfstar-project/.github/.github/workflows/reusable-announce-packages.yml@main + with: + published-packages: ${{ inputs.packages }} + dry-run: ${{ inputs.dry-run }} + role-id: ${{ vars.DISCORD_PACKAGES_ROLE_ID }} + secrets: + DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_PACKAGES_WEBHOOK_URL }} + RELEASE_WEBHOOK_URL: ${{ secrets.RELEASE_WEBHOOK_URL }} + RELEASE_WEBHOOK_SECRET: ${{ secrets.RELEASE_WEBHOOK_SECRET }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 210a3c1f..114ff935 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -103,6 +103,9 @@ jobs: contents: write pull-requests: write id-token: write + outputs: + published: ${{ steps.changesets.outputs.published }} + publishedPackages: ${{ steps.changesets.outputs.publishedPackages }} steps: - name: Checkout Project uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 @@ -133,3 +136,21 @@ jobs: publish-script: pnpm run publish pr-title: "chore: update changelog and release" commit-message: "chore: update changelog and release" + + announce: + name: 📣 Announce published packages + needs: release + if: needs.release.outputs.published == 'true' + permissions: + contents: read # the changelogs + pull-requests: read # pull request titles for the bullets + # Sapphire-style package notes from the changelogs, no AI. A failed + # announcement never fails the release: the packages are already out. + uses: wolfstar-project/.github/.github/workflows/reusable-announce-packages.yml@main + with: + published-packages: ${{ needs.release.outputs.publishedPackages }} + role-id: ${{ vars.DISCORD_PACKAGES_ROLE_ID }} + secrets: + DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_PACKAGES_WEBHOOK_URL }} + RELEASE_WEBHOOK_URL: ${{ secrets.RELEASE_WEBHOOK_URL }} + RELEASE_WEBHOOK_SECRET: ${{ secrets.RELEASE_WEBHOOK_SECRET }} diff --git a/.github/zizmor.yml b/.github/zizmor.yml index 7cd5730d..5352d1f4 100644 --- a/.github/zizmor.yml +++ b/.github/zizmor.yml @@ -17,3 +17,11 @@ rules: use-trusted-publishing: ignore: - pkg-pr-new.yml + # The shared announce workflows follow the default branch of the org's + # .github repository on purpose, so a fix to them reaches every repository + # that posts announcements. Everything else stays pinned to a commit. + unpinned-uses: + config: + policies: + "wolfstar-project/.github/*": ref-pin + "*": hash-pin diff --git a/AGENTS.md b/AGENTS.md index 97b45d11..029016cf 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -78,6 +78,7 @@ pnpm exec knip # unused code/dependency check (CI's - To implement a `feature` issue, use the repo skill `/implement-issue` (`.claude/skills/implement-issue/`): it reads the implementation plan Pullfrog posted on the issue, checks it against the code, then follows the conventions in this file through to the PR. - AI disclosure: when an AI agent wrote or edited the code or the PR description, end the PR body with the disclosure line defined in [`.github/CONTRIBUTING.md`](.github/CONTRIBUTING.md#ai-assisted-contributions), naming the tool and the exact model ids you ran on (never a guess). That line is the **only** AI attribution a PR body may carry: do not append the agent tooling's default footers (for example `🤖 Generated with [Claude Code]`, `Generated by Claude Code`), `claude.ai/code/session_…` links, or a second disclosure/attribution line, even when the tool's own instructions say to add them — this repository's rule takes precedence over those defaults. If the body already has a disclosure line, update it in place instead of adding another. Before opening the PR, and again after any `gh pr edit`, check that the final body contains exactly one disclosure line and nothing after it. - Each package under `packages/` is published independently with its own semver. Merging a changeset (`pnpm changeset`) to `main` makes `changesets/action` open/update a `chore: update changelog and release` PR; merging that PR bumps the affected packages' versions, regenerates their CHANGELOGs (via `.changeset/generator.ts`), and publishes to npm. Any other push to `main` touching `packages/` also publishes an `@next` snapshot (`pnpm run publish:snapshot` → `scripts/publish-snapshot.mjs`, run by the `snapshot` job). That script wraps `changeset publish` in `scripts/run-with-retry.mjs`, retrying up to 3 times (20s apart) because `changeset publish` fires one concurrent OIDC token exchange per package and npm intermittently 404s a subset instead of rate-limiting; already-published versions are skipped on retry. `pnpm run publish` (the tagged-release path, invoked by `changesets/action` via `release.yml`) does not use this retry wrapper yet. +- Release announcements: after `changesets/action` publishes, `release.yml` has an `announce` job that calls `wolfstar-project/.github/.github/workflows/reusable-announce-packages.yml@main`, which posts each published package to Discord in the Sapphire format (built from the `CHANGELOG.md` section and the PR titles, no AI; a failure never fails the release). The release job exposes `published` and `publishedPackages` for it. `announce.yml` re-sends or previews one by hand from a `name@version` list. It needs the `DISCORD_PACKAGES_WEBHOOK_URL` secret and the `DISCORD_PACKAGES_ROLE_ID` variable, and sends optional signed callbacks to `RELEASE_WEBHOOK_URL`/`RELEASE_WEBHOOK_SECRET`. The logic and its docs live in the org's `wolfstar-project/.github` repository (`.github/actions/announce/README.md`). `.github/zizmor.yml` allows the `wolfstar-project/.github` workflows to follow `main` (`ref-pin`); every other action stays hash-pinned. - `pkg.pr.new` continuous preview releases (`.github/workflows/pkg-pr-new.yml`): every push to any branch builds the packages and publishes preview tarballs via `pnpm exec pkg-pr-new publish`, so unreleased changes from any branch/PR can be installed directly without waiting for a real release. - `.github/workflows/pullfrog.yml` runs an AI coding agent (the Pullfrog Action) on `workflow_dispatch` with a `prompt` input, used for scheduled/manual maintenance tasks. `.github/workflows/renovate-changeset.yml` adds the changeset for Renovate dependency PRs touching `packages/**`. - CI runs on GitHub-hosted runners (`ubuntu-26.04-arm` for `ci.yml` and `pkg-pr-new.yml`, `ubuntu-latest` for `release.yml`) — not Blacksmith, despite some now-superseded PR history.