fix: populate first-release editions and simplify URL#22
Conversation
The first release on a repo rendered an empty edition page because processOneRelease short-circuited the SHA list to [] when there was no predecessor, cascading to prCount=0 and empty top-stories/changelog. Walk the full history reachable from the release tag instead, so the first edition spans every PR/commit since the beginning of the repo. Also collapse the route from /releases/tag/<tag>/<slug>/ to /releases/<tag>/. The /tag/ infix and slug segment add no SEO value — tags are already stable, distinctive identifiers. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Caution Review failedPull request was closed or merged during review Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughAdds a git helper to list commit SHAs reachable from a release tag and uses it for first-release SHA lists; removes the release URL slug segment across the site so release routes and URL helpers are tag-only (e.g., /releases//), and adds a legacy redirector for old slugged URLs. ChangesAction: Git Log Enumeration for First Releases
Site: Release URL Structure Simplification
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Review rate limit: 9/10 reviews remaining, refill in 6 minutes. Comment |
|
| Filename | Overview |
|---|---|
| action/src/git.ts | Adds listReachableShas using spawnSync (safe from injection) with proper error/stderr handling and a 10 MB buffer; addresses the previous security comment. |
| action/src/index.ts | Calls listReachableShas for the first-release case instead of short-circuiting to [], fixing empty first editions. |
| site/src/app/releases/tag/[tag]/[slug]/page.tsx | Converted from full content page to a meta-refresh legacy redirect; relative URL ../../../<tag>/ resolves correctly for all tag shapes including encoded slashes. |
| site/src/app/releases/[tag]/page.tsx | New canonical release detail page at simplified /releases/<tag>/ path; logic is unchanged from the old page, just moved and slug segment removed. |
| site/src/lib/urls.ts | Removed releaseSlug and simplified releasePath/releaseOgImagePath to a single encodeURIComponent(tag) segment. |
| site/src/app/releases/[tag]/opengraph-image.tsx | Moved from the old slug-based path and simplified generateStaticParams to emit only { tag } without slug. |
| site/src/lib/urls.test.ts | Updated tests for new URL shape; removed releaseSlug tests, added concise tests for releasePath and releaseOgImagePath. |
| action/src/release-builder.test.ts | Minor test description rename to better reflect the zero-match case; no logic change. |
Sequence Diagram
sequenceDiagram
participant Browser
participant LegacyPage as "Legacy /releases/tag/tag/slug/"
participant NewPage as "/releases/tag/"
participant Action as "GitHub Action"
participant Git as "git log (spawnSync)"
participant GH as "GitHub Compare API"
Browser->>LegacyPage: "GET (old bookmarked URL)"
LegacyPage-->>Browser: "200 + meta refresh to ../../../tag/"
Browser->>NewPage: "GET /releases/tag/"
NewPage-->>Browser: "200 Release Edition"
Action->>GH: "fetchCompareShas (predecessor exists)"
GH-->>Action: "SHA list"
Action->>Git: "listReachableShas (first release, no predecessor)"
Git-->>Action: "full history SHA list"
Action->>Action: "matchStoriesForRelease(allStories, shaList)"
Reviews (4): Last reviewed commit: "fix: apply CodeRabbit auto-fixes" | Re-trigger Greptile
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@action/src/git.ts`:
- Around line 36-37: The catch block currently swallows errors and returns []
silently; change it to catch the error (e.g., catch (err)) and emit a warning
that includes the ref value and the caught error before returning []; update the
catch in the same function/block (the try/catch around the reachable-SHA lookup)
to call the repository logger or GitHub Actions core warning with a message like
"reachable-SHA lookup failed for ref <ref>: <err>" so degraded behavior is
visible in deploy logs, then return [] as before.
- Around line 30-35: The code currently interpolates ref into a shell string
passed to execSync which opens a command-injection vector; replace the
string-based call to execSync with an argument-based child_process invocation
(e.g., execFileSync or spawnSync) so git is invoked as a command with an args
array (['log', ref, '--pretty=format:%H']) rather than a single interpolated
string; keep existing options (cwd: repoDir, encoding: 'utf8', stdio) and then
continue to split the returned out value as before.
In `@site/src/app/releases/`[tag]/page.tsx:
- Around line 1-3: Add a compatibility route component named LegacyReleasePage
that accepts params (tag and slug), extracts/awaits the tag, and issues a
server-side redirect to the new path; implement it using next/navigation's
redirect inside a new page component (export default async function
LegacyReleasePage({ params }) { const { tag } = await params;
redirect(`/releases/${encodeURIComponent(tag)}/`); }) so old
/releases/tag/<tag>/<slug>/ URLs are redirected to /releases/<tag>/.
🪄 Autofix (Beta)
❌ Autofix failed (check again to retry)
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: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: ddfd6c06-954b-4db1-866c-f66a5c0a347c
📒 Files selected for processing (7)
action/src/git.tsaction/src/index.tsaction/src/release-builder.test.tssite/src/app/releases/[tag]/opengraph-image.tsxsite/src/app/releases/[tag]/page.tsxsite/src/lib/urls.test.tssite/src/lib/urls.ts
Use spawnSync with an args array instead of execSync with an interpolated string, so a tag containing shell metacharacters can't be re-interpreted as a command. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Shallow clones don't make `git log` fail — the command succeeds and just returns fewer commits. The [] fallback only triggers on non-zero exit (e.g. ref not fetched). Spell out both behaviors so a future reader can tell them apart. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
♻️ Duplicate comments (1)
action/src/git.ts (1)
31-40:⚠️ Potential issue | 🟠 Major | ⚡ Quick winAdd warning logs when reachable-SHA enumeration fails.
listReachableShasstill fails silently at Line 37 and Line 39-40. That makes degraded first-release behavior hard to detect in deploy logs.Suggested patch
export function listReachableShas(repoDir: string, ref: string): string[] { try { const result = spawnSync( 'git', ['log', ref, '--pretty=format:%H'], { cwd: repoDir, encoding: 'utf8' }, ); - if (result.status !== 0) return []; + if (result.status !== 0) { + const stderr = + typeof result.stderr === 'string' + ? result.stderr.trim() + : String(result.stderr ?? '').trim(); + console.warn( + `[gitpulse] unable to enumerate reachable SHAs for ref "${ref}"${stderr ? `: ${stderr}` : ''}`, + ); + return []; + } return result.stdout.split('\n').map((s) => s.trim()).filter(Boolean); - } catch { + } catch (err) { + console.warn( + `[gitpulse] unable to enumerate reachable SHAs for ref "${ref}": ${err instanceof Error ? err.message : String(err)}`, + ); return []; } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@action/src/git.ts` around lines 31 - 40, The function listReachableShas silently returns [] on failures; update it to log warnings instead: when spawnSync (used as spawnSync('git', ['log', ref, '--pretty=format:%H'], { cwd: repoDir, encoding: 'utf8' })) yields a non-zero result.status, emit a warning (e.g., console.warn or your project logger) including repoDir, ref and result.stderr, then return []; likewise, in the catch block log the thrown error with context (repoDir/ref) before returning []; reference listReachableShas, spawnSync, result, repoDir and ref to find where to add these warnings.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@action/src/git.ts`:
- Around line 31-40: The function listReachableShas silently returns [] on
failures; update it to log warnings instead: when spawnSync (used as
spawnSync('git', ['log', ref, '--pretty=format:%H'], { cwd: repoDir, encoding:
'utf8' })) yields a non-zero result.status, emit a warning (e.g., console.warn
or your project logger) including repoDir, ref and result.stderr, then return
[]; likewise, in the catch block log the thrown error with context (repoDir/ref)
before returning []; reference listReachableShas, spawnSync, result, repoDir and
ref to find where to add these warnings.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 470a5f2b-2ba5-4e46-b185-82ac02e01f58
📒 Files selected for processing (1)
action/src/git.ts
- Surface degraded behavior in deploy logs: console.warn the ref + exit status / error before returning [], so a tag missing locally doesn't silently produce an empty edition again. - Re-add /releases/tag/<tag>/<slug>/ as a static legacy redirect page. output: 'export' rules out next/navigation's redirect(), so emit a meta refresh with a URL relative to the legacy path (../../../<tag>/) — the relative form preserves basePath without hard-coding it. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@action/src/git.ts`:
- Around line 34-40: The spawnSync call that runs 'git log' (the invocation
using spawnSync and the result variable) can exceed the default stdout/stderr
buffer and silently fail; fix it by adding a larger maxBuffer (e.g. 10MB or
configurable) to the options object passed to spawnSync and also defensively
check result.error and result.stderr before assuming result.stdout, returning []
only when an actual error/status indicates failure; update the options passed to
the git log spawnSync invocation and the subsequent checks on
result/status/error/stderr to ensure large-history outputs are not truncated.
🪄 Autofix (Beta)
✅ Autofix completed
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 12d80a3f-6371-4739-a2f1-a8427679d4b1
📒 Files selected for processing (1)
action/src/git.ts
|
Note Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it. Autofix skipped. No unresolved CodeRabbit review comments with fix instructions found. |
|
Note Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it. Fixes Applied SuccessfullyFixed 1 file(s) based on 1 unresolved review comment. Files modified:
Commit: The changes have been pushed to the Time taken: |
Fixed 1 file(s) based on 1 unresolved review comment. Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
Summary
Two fixes to release editions, surfaced by v0.1.0 being deployed empty.
First releases were rendering empty.
processOneReleaseshort-circuited the compare SHA list to[]whenever there was no predecessor release, soprCount=0, no top stories, no changelog — only the LLM hero quip survived. Walk the full history reachable from the release tag (git log <tag> --pretty=%H) instead, so the first edition spans every PR since the beginning of the repo. The cachedinputsHashwill mismatch on the next analyzer run, regeneratingquipandreleaseStorywith real PR context.URL collapsed from
/releases/tag/<tag>/<slug>/to/releases/<tag>/. The/tag/infix mirrored github.com but added nothing here, and the slug was redundant — tags are already stable, distinctive identifiers (unlike PR numbers or commit SHAs). Matches gitsky's/[owner]/[repo]/releases/<tag>/shape, scaled down for single-repo.Test plan
yarn workspace @gitpulse/action test(54/54)yarn workspace @gitpulse/site test(41/41)yarn workspace @gitpulse/action typecheckyarn workspace @gitpulse/site typecheckreleases: 1 fetched, 1 new/updated, 0 unchanged(was0 new/updated, 1 unchanged)https://znat.github.io/gitpulse/releases/v0.1.0/— confirm stat bar, top stories, and changelog are populatedNotes
/releases/tag/v0.1.0/v0-1-0/URL will 404 after deploy. Was live for ~minutes; not adding a redirect./pull/[number]/[slug]whenpublic/data/stories/is empty is unrelated — CI populates the data dir before building.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes
Tests