Skip to content

Prevent oversized GitHub release failures#4714

Open
justin808 wants to merge 1 commit into
mainfrom
fix/github-release-notes-limit
Open

Prevent oversized GitHub release failures#4714
justin808 wants to merge 1 commit into
mainfrom
fix/github-release-notes-limit

Conversation

@justin808

@justin808 justin808 commented Jul 17, 2026

Copy link
Copy Markdown
Member

Why

The 17.0.0 registry packages and tag published successfully, but GitHub rejected the final release description because the changelog section was 149,693 characters, over GitHub's 125,000-character limit. Rerunning the full release would risk republishing artifacts that already exist.

What changed

  • Prepare and validate GitHub release notes before release confirmation and publication.
  • Compact same-repository PR/issue links and contributor profile links to GitHub-native short forms.
  • When compacted notes still exceed GitHub's limit, retain Markdown-safe beginning/end excerpts plus a tag-pinned link to the complete changelog.
  • Apply the same bounded preparation to sync_github_release and fail closed if a prepared body is still oversized.
  • On a GitHub-only publication failure, print the idempotent sync_github_release[VERSION] recovery command and warn against rerunning registry publication.
  • Document the preflight and recovery behavior.

This exact implementation reduces the 17.0.0 body from 149,693 to 121,773 characters without dropping its changelog entries; that output matches the repaired live release.

Verification

  • bundle exec rspec spec/react_on_rails/release_rake_helpers_spec.rb — 743 examples, 0 failures
  • .agents/bin/lint — passed
  • changed-file RuboCop — passed
  • git diff --check — passed
  • pre-commit and pre-push hooks, including online Markdown link checks — passed
  • iterative codex review --uncommitted — clean after resolving all findings
  • live v17.0.0 release — non-draft, non-prerelease, 121,773-character body

The broad .agents/bin/validate --changed run reached and passed docs, lint, build, ESLint, Prettier, type-checking, and the release-helper suite, but its RBS-enabled all-gem RSpec phase produced unrelated Ruby 4.0.5/RBS dependency failures. As a control, an unrelated failing example passed standalone outside that RBS environment; the focused release suite remained green inside the broad run.

Changelog

No user-facing changelog entry: this changes maintainer release tooling and internal release documentation.

Summary by CodeRabbit

  • Release Process

    • GitHub release notes are now automatically compacted or safely truncated when they exceed platform limits.
    • Release confirmation displays the prepared note size before publication.
    • If GitHub release creation fails after publishing, recovery guidance now supports retrying only the GitHub synchronization step.
  • Documentation

    • Updated release instructions and troubleshooting guidance for oversized notes and failed GitHub publication.

@justin808

Copy link
Copy Markdown
Member Author

+ci-status

@justin808

Copy link
Copy Markdown
Member Author

+ci-run-hosted

@github-actions

Copy link
Copy Markdown
Contributor

CI Status

Head SHA: 57915e607d76
Changed files: 3
Docs-only heuristic (matches ci-changes-detector metadata paths): no
ready-for-hosted-ci label: absent
force-full-hosted-ci label: absent
Current hosted-CI waiver: not present for this SHA

Only the required gate is active unless hosted CI is requested.

@github-actions github-actions Bot added the ready-for-hosted-ci Run optimized hosted GitHub CI for this PR label Jul 17, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Hosted CI Requested

Triggered 9 workflow(s) for 57915e607d76.
Mode: optimized hosted CI (path-selected by script/ci-changes-detector).
Added ready-for-hosted-ci, so future commits will keep running optimized hosted CI until +ci-stop-hosted is used.

View progress in the Actions tab.

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The release task now bounds GitHub release bodies by compacting links and truncating oversized changelog content. It reports prepared-body sizes before publication, centralizes GitHub failure recovery, and documents the GitHub-only synchronization path.

Changes

GitHub release body flow

Layer / File(s) Summary
Release note preparation
rakelib/release.rake, react_on_rails/spec/react_on_rails/release_rake_helpers_spec.rb
GitHub release notes are compacted and safely truncated to the configured 125,000-character limit, with coverage for multibyte text, code fences, excerpts, and oversized entries.
Confirmation and recovery flow
rakelib/release.rake, react_on_rails/spec/react_on_rails/release_rake_helpers_spec.rb, internal/contributor-info/releasing.md
Release confirmation reports prepared-body character counts, GitHub failures provide an idempotent synchronization command, and release documentation describes the recovery procedure.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ReleaseTask
  participant NotesPipeline
  participant GitHub
  participant SyncCommand
  ReleaseTask->>NotesPipeline: Prepare changelog notes
  NotesPipeline->>ReleaseTask: Return bounded release body
  ReleaseTask->>GitHub: Publish release
  GitHub-->>ReleaseTask: Report failure
  ReleaseTask->>SyncCommand: Retry GitHub synchronization
Loading

Suggested reviewers: ihabadham

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: preventing GitHub release failures caused by oversized release descriptions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/github-release-notes-limit

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ast-grep (0.44.1)
react_on_rails/spec/react_on_rails/release_rake_helpers_spec.rb

ast-grep timed out on this file


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jul 17, 2026

Copy link
Copy Markdown

Greptile Summary

This PR prevents oversized changelogs from blocking GitHub release publication. The main changes are:

  • Compacts same-repository issue, pull request, and contributor links.
  • Produces bounded, Markdown-safe excerpts when notes remain oversized.
  • Runs release-note preparation before confirmation and in recovery flows.
  • Prints an idempotent GitHub-only recovery command after publication failures.
  • Documents and tests the updated release workflow.

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code.

Important Files Changed

Filename Overview
rakelib/release.rake Adds deterministic release-note compaction, bounded excerpt generation, preflight reporting, and GitHub-only recovery guidance.
react_on_rails/spec/react_on_rails/release_rake_helpers_spec.rb Covers link compaction, Unicode limits, escaped excerpts, size budgeting, preflight output, and recovery commands.
internal/contributor-info/releasing.md Documents oversized-note handling and the idempotent GitHub release recovery path.

Reviews (1): Last reviewed commit: "Prevent oversized GitHub release failure..." | Re-trigger Greptile

Comment thread rakelib/release.rake
ERROR
end

report_github_release_notes_preflight!(version:, changelog_notes: has_changelog)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: report_github_release_notes_preflight! calls github_release_notes(notes: changelog_notes, tag:) purely to print the before/after character counts, and then prepare_github_release_context (called later during actual publish) re-extracts the changelog section from disk and calls github_release_notes again with the same inputs. Not a correctness bug (the computation is a pure function and cheap), but it does double the compaction/truncation work and re-reads CHANGELOG.md a second time. Could thread the already-prepared notes through instead, if you want to avoid the duplicate work.

Comment thread rakelib/release.rake
compacted_notes = compacted_notes.gsub(
%r{\[(?:Issue|issue) (\d+)\]\(https://github\.com/shakacode/react_on_rails/issues/\1\)}
) { "##{Regexp.last_match(1)}" }
compacted_notes.gsub(%r{\[([A-Za-z0-9](?:[A-Za-z0-9-]{0,38}))\]\(https://github\.com/\1\)}) do

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: this pattern will compact any [text](https://github.com/text) link whose text matches the trailing URL segment — not just real profile links — including things like [shakacode](https://github.com/shakacode) (an org page) or a coincidental repo-name link. That's likely fine in practice (relative links resolve the same way), but the char class also doesn't enforce GitHub's username rules (no leading/trailing/consecutive hyphens), so it'll happily "compact" some strings that aren't valid usernames at all. Worth a comment noting this is a best-effort heuristic, not a validator, if that's intentional.

@claude

claude Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Review: Prevent oversized GitHub release failures

Overview

This PR fixes a real incident (17.0.0's release body exceeded GitHub's 125,000-char limit) by adding a preflight/prepare step for GitHub release bodies: compact same-repo PR/issue/profile links to short forms, and if still oversized, fall back to a Markdown-safe beginning/end excerpt with a tag-pinned link to the full changelog. The same preparation is applied to both release and sync_github_release, and a publish failure now prints the idempotent recovery command instead of risking a re-run of registry publication.

Code quality

  • The implementation is cleanly decomposed into small, single-purpose functions (compact_github_release_notes, truncate_github_release_notes, github_release_escaped_excerpt, etc.), consistent with the rest of release.rake's style (keyword args, shorthand hash punning, abort for fail-closed behavior).
  • The binary search in github_release_escaped_excerpt to find the max substring whose escaped length fits a budget is a nice touch — it correctly accounts for CGI.escapeHTML potentially expanding length (e.g. <, >, & in code blocks), and the predicate is monotonic so the binary search is valid.
  • The 3/4 (beginning) / 1/4 (ending) budget split favors keeping more context at the top, which seems like a reasonable default, though it's a bit of a magic ratio — a named constant would make the intent self-documenting.
  • Wrapping truncated excerpts in escaped <pre> blocks is a good defensive choice: it prevents a truncation cut mid-code-fence or mid-markdown-link from corrupting the rendered page, since the content becomes inert text rather than live Markdown.

Correctness

  • Verified the budget math can't cause beginning/ending excerpts to overlap (the sum of their actual budgets is always less than available_characters, which is always less than the oversized notes.length that triggers this path).
  • compact_github_release_notes replacements are always length-reducing or neutral, so it can't make an in-limit body larger.
  • The <= boundary in github_release_body_within_limit? matches the stated 125,000 limit inclusively, consistent with the PR's own validation against the live v17.0.0 release.
  • ensure_github_release_body_within_limit! gives a fail-closed safety net if the budget math is ever wrong (e.g. constant changes), which is good defensive design.
  • Left two minor inline nits: (1) prepare_github_release_context re-extracts the changelog and recomputes github_release_notes even though confirm_release!'s preflight already computed it once — harmless but duplicate work; (2) the profile-link compaction regex is a broad heuristic (matches any [x](.../x) link, not just validated GitHub usernames) — likely fine in practice but worth a comment if intentional.

Test coverage

Very thorough — covers compaction with 800 entries, max-length (39-char) usernames, multibyte content near the limit (char vs byte length), balanced <pre> tags across the omission boundary, single oversized entry, and the exact fallback-wrapper budget edge case. This gives good confidence in the binary-search/budget math specifically.

Security

No concerns — this only touches release-body text prepared for gh release create/edit --notes-file (via tempfile, not shell interpolation), and escaping via CGI.escapeHTML is appropriately used for the raw excerpt fallback.

Risk/Blast radius

Low — this is maintainer-only release tooling, gated behind a manual rake release / sync_github_release invocation, with a fail-closed abort if the prepared body still doesn't fit. No user-facing runtime code is touched.

Overall: solid, well-tested fix for a real release-blocking bug. Only minor nits noted inline; nothing blocking.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
rakelib/release.rake (1)

6738-6750: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Chain gsub calls using string backreferences.

You can make this method more concise and idiomatic by chaining the gsub calls and using string backreferences ('\1') instead of blocks with Regexp.last_match(1).

♻️ Proposed refactor
 def compact_github_release_notes(notes)
-  compacted_notes = notes.gsub(
-    %r{\[PR (\d+)\]\(https://github\.com/shakacode/react_on_rails/pull/\1\)}
-  ) { "##{Regexp.last_match(1)}" }
-  compacted_notes = compacted_notes.gsub(
-    %r{\[(?:Issue|issue) (\d+)\]\(https://github\.com/shakacode/react_on_rails/issues/\1\)}
-  ) { "##{Regexp.last_match(1)}" }
-  compacted_notes.gsub(%r{\[([A-Za-z0-9](?:[A-Za-z0-9-]{0,38}))\]\(https://github\.com/\1\)}) do
-    username = Regexp.last_match(1)
-    "[#{username}](/#{username})"
-  end
+  notes
+    .gsub(%r{\[PR (\d+)\]\(https://github\.com/shakacode/react_on_rails/pull/\1\)}, '#\1')
+    .gsub(%r{\[(?:Issue|issue) (\d+)\]\(https://github\.com/shakacode/react_on_rails/issues/\1\)}, '#\1')
+    .gsub(%r{\[([A-Za-z0-9](?:[A-Za-z0-9-]{0,38}))\]\(https://github\.com/\1\)}, '[\1](/\1)')
 end
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rakelib/release.rake` around lines 6738 - 6750, Refactor
compact_github_release_notes to chain the three gsub transformations directly
and replace the PR and issue blocks’ Regexp.last_match(1) usage with string
backreferences such as '\1'. Preserve the existing regex patterns and
username-link replacement behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@rakelib/release.rake`:
- Around line 6738-6750: Refactor compact_github_release_notes to chain the
three gsub transformations directly and replace the PR and issue blocks’
Regexp.last_match(1) usage with string backreferences such as '\1'. Preserve the
existing regex patterns and username-link replacement behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6802d841-3b2a-4f3a-a4ff-371bd78be062

📥 Commits

Reviewing files that changed from the base of the PR and between e9b1e35 and 57915e6.

📒 Files selected for processing (3)
  • internal/contributor-info/releasing.md
  • rakelib/release.rake
  • react_on_rails/spec/react_on_rails/release_rake_helpers_spec.rb

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-hosted-ci Run optimized hosted GitHub CI for this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant