chore(release): append en.dev sponsor blurb to release notes#431
Conversation
Adds a "Sponsor fnox" section at the bottom of each GitHub Release body after communique generates the narrative notes, so readers who land on a release see how fnox is funded and where to sponsor. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
|
Note Gemini is unable to generate a review for this pull request due to the file types involved not being currently supported. |
Greptile SummaryThis PR adds a sponsor blurb append step to the Confidence Score: 5/5Safe to merge — only one P2 style finding in event.rs; all logic is functionally correct. The workflow change is correct and the Rust refactors are functionally equivalent. The single flagged issue (side effects in match guards in event.rs) does not affect runtime behavior and is a style concern only. src/tui/event.rs — the match-guard side-effect pattern warrants a second look, though it is not a bug today. Important Files Changed
Sequence DiagramsequenceDiagram
participant GH as GitHub Tag Push
participant BB as build-binaries
participant CR as create-release
participant ER as enhance-release
GH->>BB: trigger on push/tag
BB-->>CR: artifacts uploaded
CR->>CR: extract CHANGELOG notes
CR->>CR: gh release create (with assets)
CR-->>ER: release created
ER->>ER: communique generate (AI-enhanced notes)
ER->>ER: gh release view (fetch body)
ER->>ER: append sponsor blurb via heredoc
ER->>GH: gh release edit (write final notes)
Reviews (3): Last reviewed commit: "[autofix.ci] apply automated fixes (atte..." | Re-trigger Greptile |
| { | ||
| gh release view "$TAG_NAME" --json body --jq .body | ||
| cat <<'EOF' |
There was a problem hiding this comment.
Non-idempotent append on workflow re-run
The step always appends the sponsor blurb to whatever gh release view returns at that moment. If the enhance-release job (or just this step) is re-run — due to a transient failure, a manual retry, or a re-triggered release — the section will be appended a second time. Adding an idempotency guard prevents this:
| { | |
| gh release view "$TAG_NAME" --json body --jq .body | |
| cat <<'EOF' | |
| BODY=$(gh release view "$TAG_NAME" --json body --jq .body) | |
| if echo "$BODY" | grep -qF '## 💚 Sponsor fnox'; then | |
| echo "Sponsor blurb already present, skipping." | |
| exit 0 | |
| fi | |
| { | |
| echo "$BODY" | |
| cat <<'EOF' |
The provider codegen in build/generate_providers.rs sorted providers by category only. Stable sort preserves input order for equal keys, and fs::read_dir returns entries in OS-dependent order, so providers within the same category were ordered by whatever the filesystem produced. That non-determinism flowed into the generated ProviderConfig enum and then into docs/public/schema.json, causing autofix.ci to produce schema diffs that flip 100+ lines back and forth between runs (see #431 where three autofix passes kept reshuffling the same oneOf variants). Add a secondary sort by provider name so within-category ordering is deterministic, and regenerate docs/public/schema.json. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
## Summary - Providers within a category were ordered by `fs::read_dir` (OS/filesystem-dependent). - That non-determinism flowed into the generated `ProviderConfig` enum and then into [docs/public/schema.json](docs/public/schema.json), causing [autofix.ci](https://github.com/jdx/fnox/blob/main/.github/workflows/autofix.yml) to keep reshuffling 100+ lines between runs. You can see this on [#431](#431) — three autofix passes each re-ordered the same `oneOf` variants without converging. - Adds a secondary sort by provider name in [`build/generate_providers.rs`](build/generate_providers.rs) so within-category ordering is fully deterministic, then regenerates [docs/public/schema.json](docs/public/schema.json) with the stable ordering. ## Root cause ```rust // before — stable sort on category only; within-category order = read_dir order providers.sort_by(|a, b| cat_order(&a.1.category).cmp(&cat_order(&b.1.category))); ``` Stable sort preserves input order on ties, and input order comes from `fs::read_dir`, which is not guaranteed to be sorted. Fix is a secondary `.then_with(|| a.0.cmp(&b.0))` on name. ## Test plan - [x] `mise run render:schema` locally - [x] Running `fnox schema` twice produces byte-identical output - [ ] `autofix.ci` on this PR does not re-touch `docs/public/schema.json` - [ ] Future PRs that don't touch provider definitions should not see schema churn 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk: only changes provider sorting in a build-time codegen script and regenerates `docs/public/schema.json`; no runtime logic or security-sensitive behavior is modified. > > **Overview** > Ensures provider definitions are loaded in a *fully deterministic* order during schema/code generation by sorting first by category and then by provider name (avoiding OS/filesystem-dependent `read_dir` ordering). > > Regenerates `docs/public/schema.json` so the `ProviderConfig` `oneOf` variants appear in stable order, eliminating cross-machine/CI churn in the generated schema output. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 291cd31. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
### 🚀 Features - **(library)** top-level Fnox::discover() / get / list convenience API by [@bglusman](https://github.com/bglusman) in [#442](#442) ### 🐛 Bug Fixes - **(docs)** stack banner and pin close button on mobile by [@jdx](https://github.com/jdx) in [#437](#437) - **(set)** fall back to current provider when updating secrets by [@rpendleton](https://github.com/rpendleton) in [#439](#439) ### 📚 Documentation - **(site)** show release version and github stars by [@jdx](https://github.com/jdx) in [#443](#443) - add cross-site announcement banner by [@jdx](https://github.com/jdx) in [#434](#434) - respect banner expires field by [@jdx](https://github.com/jdx) in [#436](#436) ### 🛡️ Security - **(build)** deterministic provider ordering in generated schema by [@jdx](https://github.com/jdx) in [#432](#432) ### 🔍 Other Changes - **(release)** append en.dev sponsor blurb to release notes by [@jdx](https://github.com/jdx) in [#431](#431) ### 📦️ Dependency Updates - bump communique to 1.0.3 by [@jdx](https://github.com/jdx) in [#435](#435) - bump communique 1.0.3 → 1.0.4 by [@jdx](https://github.com/jdx) in [#438](#438) ### New Contributors - @bglusman made their first contribution in [#442](#442)
### 🚀 Features - **(library)** top-level Fnox::discover() / get / list convenience API by [@bglusman](https://github.com/bglusman) in [#442](#442) ### 🐛 Bug Fixes - **(docs)** stack banner and pin close button on mobile by [@jdx](https://github.com/jdx) in [#437](#437) - **(set)** fall back to current provider when updating secrets by [@rpendleton](https://github.com/rpendleton) in [#439](#439) ### 📚 Documentation - **(site)** show release version and github stars by [@jdx](https://github.com/jdx) in [#443](#443) - add cross-site announcement banner by [@jdx](https://github.com/jdx) in [#434](#434) - respect banner expires field by [@jdx](https://github.com/jdx) in [#436](#436) ### 🛡️ Security - **(build)** deterministic provider ordering in generated schema by [@jdx](https://github.com/jdx) in [#432](#432) ### 🔍 Other Changes - **(release)** append en.dev sponsor blurb to release notes by [@jdx](https://github.com/jdx) in [#431](#431) ### 📦️ Dependency Updates - bump communique to 1.0.3 by [@jdx](https://github.com/jdx) in [#435](#435) - bump communique 1.0.3 → 1.0.4 by [@jdx](https://github.com/jdx) in [#438](#438) - bump communique to 1.1.2 by [@jdx](https://github.com/jdx) in [#444](#444) ### New Contributors - @bglusman made their first contribution in [#442](#442)
## Summary - Appends a **Sponsor fnox** section to every GitHub Release body, run after `communique generate` in the `enhance-release` job in [`.github/workflows/release.yml`](.github/workflows/release.yml). - Same pattern as [mise#9272](jdx/mise#9272), adapted for fnox. ## What it looks like Rendered at the bottom of each release body: > ## 💚 Sponsor fnox > > fnox is maintained by [@jdx](https://github.com/jdx) under [**en.dev**](https://en.dev) — a small independent studio building developer tooling like [mise](https://mise.jdx.dev/), [aube](https://aube.en.dev/), hk, and more. Keeping fnox secure, maintained, and free is funded by sponsors. > > If fnox is handling secrets or config for you or your team, please consider [sponsoring at en.dev](https://en.dev). Sponsorships are what let fnox stay independent and the project keep moving. ## Test plan - [x] \`actionlint\` + \`yamllint\` pass on the modified workflow - [ ] Next tagged release produces a GitHub Release whose body ends with the sponsor section 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
) ## Summary - Providers within a category were ordered by `fs::read_dir` (OS/filesystem-dependent). - That non-determinism flowed into the generated `ProviderConfig` enum and then into [docs/public/schema.json](docs/public/schema.json), causing [autofix.ci](https://github.com/jdx/fnox/blob/main/.github/workflows/autofix.yml) to keep reshuffling 100+ lines between runs. You can see this on [jdx#431](jdx#431) — three autofix passes each re-ordered the same `oneOf` variants without converging. - Adds a secondary sort by provider name in [`build/generate_providers.rs`](build/generate_providers.rs) so within-category ordering is fully deterministic, then regenerates [docs/public/schema.json](docs/public/schema.json) with the stable ordering. ## Root cause ```rust // before — stable sort on category only; within-category order = read_dir order providers.sort_by(|a, b| cat_order(&a.1.category).cmp(&cat_order(&b.1.category))); ``` Stable sort preserves input order on ties, and input order comes from `fs::read_dir`, which is not guaranteed to be sorted. Fix is a secondary `.then_with(|| a.0.cmp(&b.0))` on name. ## Test plan - [x] `mise run render:schema` locally - [x] Running `fnox schema` twice produces byte-identical output - [ ] `autofix.ci` on this PR does not re-touch `docs/public/schema.json` - [ ] Future PRs that don't touch provider definitions should not see schema churn 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk: only changes provider sorting in a build-time codegen script and regenerates `docs/public/schema.json`; no runtime logic or security-sensitive behavior is modified. > > **Overview** > Ensures provider definitions are loaded in a *fully deterministic* order during schema/code generation by sorting first by category and then by provider name (avoiding OS/filesystem-dependent `read_dir` ordering). > > Regenerates `docs/public/schema.json` so the `ProviderConfig` `oneOf` variants appear in stable order, eliminating cross-machine/CI churn in the generated schema output. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 291cd31. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
### 🚀 Features - **(library)** top-level Fnox::discover() / get / list convenience API by [@bglusman](https://github.com/bglusman) in [jdx#442](jdx#442) ### 🐛 Bug Fixes - **(docs)** stack banner and pin close button on mobile by [@jdx](https://github.com/jdx) in [jdx#437](jdx#437) - **(set)** fall back to current provider when updating secrets by [@rpendleton](https://github.com/rpendleton) in [jdx#439](jdx#439) ### 📚 Documentation - **(site)** show release version and github stars by [@jdx](https://github.com/jdx) in [jdx#443](jdx#443) - add cross-site announcement banner by [@jdx](https://github.com/jdx) in [jdx#434](jdx#434) - respect banner expires field by [@jdx](https://github.com/jdx) in [jdx#436](jdx#436) ### 🛡️ Security - **(build)** deterministic provider ordering in generated schema by [@jdx](https://github.com/jdx) in [jdx#432](jdx#432) ### 🔍 Other Changes - **(release)** append en.dev sponsor blurb to release notes by [@jdx](https://github.com/jdx) in [jdx#431](jdx#431) ### 📦️ Dependency Updates - bump communique to 1.0.3 by [@jdx](https://github.com/jdx) in [jdx#435](jdx#435) - bump communique 1.0.3 → 1.0.4 by [@jdx](https://github.com/jdx) in [jdx#438](jdx#438) ### New Contributors - @bglusman made their first contribution in [jdx#442](jdx#442)
### 🚀 Features - **(library)** top-level Fnox::discover() / get / list convenience API by [@bglusman](https://github.com/bglusman) in [jdx#442](jdx#442) ### 🐛 Bug Fixes - **(docs)** stack banner and pin close button on mobile by [@jdx](https://github.com/jdx) in [jdx#437](jdx#437) - **(set)** fall back to current provider when updating secrets by [@rpendleton](https://github.com/rpendleton) in [jdx#439](jdx#439) ### 📚 Documentation - **(site)** show release version and github stars by [@jdx](https://github.com/jdx) in [jdx#443](jdx#443) - add cross-site announcement banner by [@jdx](https://github.com/jdx) in [jdx#434](jdx#434) - respect banner expires field by [@jdx](https://github.com/jdx) in [jdx#436](jdx#436) ### 🛡️ Security - **(build)** deterministic provider ordering in generated schema by [@jdx](https://github.com/jdx) in [jdx#432](jdx#432) ### 🔍 Other Changes - **(release)** append en.dev sponsor blurb to release notes by [@jdx](https://github.com/jdx) in [jdx#431](jdx#431) ### 📦️ Dependency Updates - bump communique to 1.0.3 by [@jdx](https://github.com/jdx) in [jdx#435](jdx#435) - bump communique 1.0.3 → 1.0.4 by [@jdx](https://github.com/jdx) in [jdx#438](jdx#438) - bump communique to 1.1.2 by [@jdx](https://github.com/jdx) in [jdx#444](jdx#444) ### New Contributors - @bglusman made their first contribution in [jdx#442](jdx#442)
Summary
communique generatein theenhance-releasejob in.github/workflows/release.yml.What it looks like
Rendered at the bottom of each release body:
Test plan
🤖 Generated with Claude Code