Skip to content

fix(changelog-site): retry the GitHub tag fetch and fail instead of degrading - #645

Merged
balajinvda merged 2 commits into
mainfrom
fix/changelog-github-tag-fetch
Aug 13, 2026
Merged

fix(changelog-site): retry the GitHub tag fetch and fail instead of degrading#645
balajinvda merged 2 commits into
mainfrom
fix/changelog-github-tag-fetch

Conversation

@balajinvda

@balajinvda balajinvda commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Why

The published changelog flapped: services appeared and disappeared between half-hourly rebuilds, and always all of them together.

fetchGitHubTags runs git ls-remote and git fetch against GitHub with no retry, and the caller only warned on failure:

// Degrade gracefully: an unreachable mirror must not fail the build.
fmt.Fprintf(os.Stderr, "changelog-site: github tags unavailable (%v)\n", err)

So one transient network failure dropped the entire GitHub tag set, and the site republished with every GitHub-only release missing, overwriting a good deployment with a worse one. The next successful run restored it. Nothing reported an error, because the job exits zero either way.

That "degrade gracefully" is wrong for a publisher. Serving a stale-but-complete site is strictly better than serving a fresh-but-half-empty one, and the failure is invisible in the output.

What changed

  • Retry both network calls three times with a short backoff, so a blip does not decide the contents of the site.
  • An unavailable GitHub tag set is now fatal. Nothing is written, so Pages keeps serving the last good deployment. --allow-missing-github-tags opts back into the old behaviour deliberately.

Testing

Run against a full GitLab clone plus the GitHub mirror, both paths:

path result
GitHub reachable 37 services, exit 0, {gitlab: 1058, both: 36, github: 960}
GitHub unreachable exits non-zero, writes no output at all

Spot-checked the services that were reported flapping:

container-cache:  0.26.4 both, 0.27.0 github, 0.28.0 github
http-invocation:  0.8.8 github, 0.8.9 github, 0.9.0 github

Notes

Two things found while testing, neither fixed here:

  1. Running the tool twice against the same checkout mislabels origins as both. The first run fetches GitHub tags into the clone, so the second run's git tag -l baseline already contains them. CI is unaffected because it clones fresh, but it makes local iteration misleading.
  2. Every Java service is absent from the changelog. The generator reads tools/ci/subproject-validations.yaml from the frozen GitLab umbrella, which lists no Java subprojects because they were added after the freeze. That needs a decision about where the service list should live and is not addressable in this repo alone.

tools/changelog-site/changelog-site is a compiled binary committed by accident in #554. Left untouched here rather than committing a rebuilt one.

Summary by CodeRabbit

  • Bug Fixes

    • Improved reliability when discovering and fetching release tags with bounded retries, timeouts, and backoff.
    • Disabled interactive credential prompts during tag retrieval.
    • Builds now clearly fail when release tag information cannot be retrieved, preventing incomplete releases by default.
  • New Features

    • Added an option to continue publishing without GitHub-only releases when tag information is unavailable.

…egrading

The published changelog flapped: services appeared and disappeared between
half-hourly rebuilds, all of them together.

fetchGitHubTags runs git ls-remote and git fetch against GitHub with no
retry, and the caller only warned on failure. One transient network failure
therefore dropped the entire GitHub tag set, and the site republished with
every GitHub-only release missing -- overwriting a good deployment with a
worse one. The next successful run restored it. Nothing reported an error,
because the job exits zero either way.

Retry both network calls three times with a short backoff so a blip does not
decide the contents of the site, and make an unavailable GitHub tag set fatal
so a degraded build is never published and Pages keeps serving the last good
deployment. --allow-missing-github-tags opts back into publishing without
them.

Verified locally against a full GitLab clone plus the GitHub mirror:
  happy path   37 services, exit 0, github-origin releases present
  failure path exits non-zero, writes no output at all

Co-authored-by: Balaji Ganesan <bganesan@nvidia.com>
@balajinvda
balajinvda requested a review from a team as a code owner August 3, 2026 23:14
@balajinvda
balajinvda requested a review from apartha-nv August 3, 2026 23:14
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The changelog site retrieves GitHub tags with timeout-bound retries and incremental backoff. Tag retrieval failures stop the build by default. The --allow-missing-github-tags flag permits publishing without GitHub-only releases.

Changes

GitHub tag retrieval

Layer / File(s) Summary
GitHub tag retrieval retries
tools/changelog-site/main.go, tools/changelog-site/main_test.go
GitHub tag commands use two-minute attempt timeouts, noninteractive execution, up to three retries, incremental backoff, and scrubbed errors. Tests verify these limits.
Missing-tag failure policy
tools/changelog-site/main.go
The --allow-missing-github-tags option permits publishing when GitHub tag retrieval fails. Without the option, the build aborts.

Estimated code review effort: 3 (Moderate) | ~15–30 minutes

Suggested reviewers: apartha-nv

Sequence Diagram(s)

sequenceDiagram
  participant ChangelogSite
  participant GitCommands
  participant GitHub
  ChangelogSite->>GitCommands: Run timeout-bound tag discovery or fetch
  GitCommands->>GitHub: Retrieve GitHub tags
  GitHub-->>GitCommands: Return tags or error
  GitCommands-->>ChangelogSite: Return result
  ChangelogSite->>GitCommands: Retry failed command up to three times
  ChangelogSite-->>ChangelogSite: Abort or publish based on --allow-missing-github-tags
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title uses the required Conventional Commits format and accurately describes the retry and failure behavior change.
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 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/changelog-github-tag-fetch

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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.

Inline comments:
In `@tools/changelog-site/main.go`:
- Around line 453-474: Update the local git command runner around run to use
exec.CommandContext with a per-attempt timeout, canceling each context after the
attempt completes. Set GIT_TERMINAL_PROMPT=0 on every command so credential
prompts cannot block, while preserving the existing retry, stderr capture, and
error-reporting behavior.
- Around line 453-474: Update fetchGitHubTags to fetch GitHub tag refs into a
dedicated, non-canonical namespace rather than refs/tags/*, preventing stale
refs from contaminating the checkout. Update buildReleases to read GitHub tags
explicitly from that isolated namespace while leaving gitlabTags sourced only
from canonical tags; preserve --allow-missing-github-tags behavior without
promoting stale GitHub refs.
- Around line 453-474: Extend TestFetchGitHubTagsLabelsOrigin with focused
coverage for retry recovery, retry exhaustion, token scrubbing, failure modes,
output preservation, and --allow-missing-github-tags using an injectable or fake
Git runner. Update the GitHub tag synchronization flow around the run helper and
its refspec so deleted remote tags are pruned or isolated before releases are
built, and add a two-run test verifying deletion is reflected.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: df16f37a-8ec8-407c-a04b-b417ca46bee8

📥 Commits

Reviewing files that changed from the base of the PR and between 3d76cd5 and e51b8c0.

📒 Files selected for processing (1)
  • tools/changelog-site/main.go

Comment thread tools/changelog-site/main.go
fetchGitHubTags runs two network-facing git commands through exec.Command
with no deadline. A hung connection or a credential prompt blocks until the
CI job times out an hour later, and the retry loop added in this PR never
gets to run, so the retry does not help in the case it was written for.

Give each attempt its own context with a two-minute timeout, and report a
timeout distinctly from a git error so the cause is visible in the log.
Three attempts plus backoff still finish well inside a CI job.

Set GIT_TERMINAL_PROMPT=0 on the command rather than relying on the
environment. The publishing job does export it, but this tool is also run
by hand, and a prompt waiting on a closed stdin is the exact stall the
deadline then has to clean up.

Raised by CodeRabbit on !645.

Co-authored-by: Balaji Ganesan <bganesan@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
tools/changelog-site/main_test.go (1)

324-334: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Test command behavior instead of scanning source text.

The assertions at Lines 329-333 search the entire main.go file. They can pass when GIT_TERMINAL_PROMPT=0 or exec.CommandContext appears in unrelated code. They do not verify that both Git commands receive the environment setting and a deadline.

Run fetchGitHubTags with a fake git executable or an injected command runner. Assert the child environment and cancellation behavior for ls-remote and fetch. The supplied tools/changelog-site/main.go implementation places these guarantees in the shared run closure.

🤖 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 `@tools/changelog-site/main_test.go` around lines 324 - 334, Replace the
source-text assertions in TestFetchGitHubTagsDisablesCredentialPrompt with
behavioral coverage of fetchGitHubTags, using a fake git executable or injected
command runner. Verify both ls-remote and fetch receive GIT_TERMINAL_PROMPT=0
and are executed through the shared run closure with cancellation/deadline
behavior from exec.CommandContext.
🤖 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.

Inline comments:
In `@tools/changelog-site/main_test.go`:
- Around line 315-317: Update the retry-budget test around gitNetworkTimeout to
assert it equals exactly 2*time.Minute, then calculate the worst-case budget for
both retry sequences used by fetchGitHubTags: ls-remote and fetch, each with its
full retry schedule. Keep the existing 30-minute CI budget assertion while
ensuring both fetchGitHubTags call paths are represented.

---

Nitpick comments:
In `@tools/changelog-site/main_test.go`:
- Around line 324-334: Replace the source-text assertions in
TestFetchGitHubTagsDisablesCredentialPrompt with behavioral coverage of
fetchGitHubTags, using a fake git executable or injected command runner. Verify
both ls-remote and fetch receive GIT_TERMINAL_PROMPT=0 and are executed through
the shared run closure with cancellation/deadline behavior from
exec.CommandContext.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 25907577-3e03-46cc-8af1-4b9787c38ad2

📥 Commits

Reviewing files that changed from the base of the PR and between e51b8c0 and 0040be3.

📒 Files selected for processing (3)
  • tools/changelog-site/changelog-site
  • tools/changelog-site/main.go
  • tools/changelog-site/main_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • tools/changelog-site/main.go

Comment thread tools/changelog-site/main_test.go
@balajinvda
balajinvda added this pull request to the merge queue Aug 13, 2026
Merged via the queue into main with commit 9cbd231 Aug 13, 2026
20 of 21 checks passed
@balajinvda
balajinvda deleted the fix/changelog-github-tag-fetch branch August 13, 2026 04:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants