Skip to content

feat: AI-generated release illustrations (PR 3/3)#56

Merged
znat merged 2 commits into
mainfrom
feat/release-images
May 18, 2026
Merged

feat: AI-generated release illustrations (PR 3/3)#56
znat merged 2 commits into
mainfrom
feat/release-images

Conversation

@znat
Copy link
Copy Markdown
Owner

@znat znat commented May 17, 2026

Summary

Closes the three-part image pipeline. PR 1 added the storage abstraction, PR 2 added per-feature illustrations, this PR adds release-edition illustrations using the same provider abstraction and the same opt-in gating.

  • Generator: port the editorial "Special Edition" prompt from gitsky (generic template only — Flux variant skipped to match PR 2's scope; theme color passed in as hex, no name lookup). The orchestrator hydrates top story details from the matched draft so the prompt gets the full story + technicalDescription per top PR, not just the denormalized headline.
  • Lifecycle: generate after assembleRelease. Preserve the existing imageUrl when the release's inputsHash is unchanged. Backfill when an existing release has no image. Regenerate when the edition's content changed. Same non-blocking contract as feature images — failures log image:failed(...) and the release JSON still writes.
  • Storage: key shape releases/<encodeFilename(tag)>.<ext> (mirrors the on-disk JSON filename).
  • Site: SpecialEditionCard renders the illustration between the hero text and the stats strip; ReleaseEditionHero un-defers the hero illustration block on the detail page. Both use the gitsky vignette + gold-accent treatment.
  • Refactor: extract extensionFromMimeType to cli/src/image/mime.ts so feature and release orchestrators share one normalizer (the per-PR-comment fix from PR feat: AI-generated images for features (PR 2/3) #54 lived only in generate-feature-image.ts).

Test plan

  • cd cli && yarn typecheck && yarn test — 85/85 (was 79, +6 release prompt tests).
  • cd site && yarn typecheck && yarn test — green.
  • cd cli && GITHUB_TOKEN=… GITPULSE_RELEASES_CAP=3 yarn analyze — observe [ … | image:stored] per release; verify uploaded releases/<tag>.{png,jpg} URLs and that each release JSON gained an imageUrl.
  • Re-run analyze with no content changes — releases log as skipped, images preserved (no extra Gemini calls).
  • Delete imageUrl from a single release JSON, re-run analyze — observe backfill (one new image, others unchanged).
  • cd site && yarn dev and visit /SpecialEditionCard shows the illustration between the quip block and stats; /releases/<tag> shows the hero illustration above the release story.

Out of scope

  • gitpulse image <release-URL> subcommand — feature stories have it (PR 2), releases don't yet. Easy follow-up if useful.
  • OpenAI / fal image providers — provider abstraction supports them, no implementation in this PR.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • AI-generated “Special Edition” release illustrations can be generated, stored, and served.
    • Release cards and hero sections display auto-generated editorial artwork when present.
    • Releases now include an optional image URL so illustrations persist with releases.
  • Bug Fixes

    • Improved generation/upload error handling with graceful fallbacks.
  • Tests

    • Added unit tests for the release-image prompt generation.

Review Change Stack

Closes out the three-part image pipeline. PR 1 added pluggable storage,
PR 2 added per-feature illustrations; this PR adds release-edition
illustrations using the same provider abstraction and the same gating.

CLI:
- cli/src/image/release-prompt.ts — port the editorial "Special Edition"
  prompt from gitsky. Generic template only; Flux variant skipped to
  match PR 2's scope. Theme color passed in as hex (no name lookup).
- cli/src/image/generate-release-image.ts — orchestrator. Hydrates top
  story details from the matched draft so the prompt gets full
  story+technicalDescription, not just the denormalized headline.
- cli/src/image/mime.ts — extracted extension lookup so feature and
  release orchestrators share one normalizer.
- cli/src/index.ts → processOneRelease — generate after assembleRelease,
  preserve the existing imageUrl when inputsHash is unchanged, backfill
  when missing, regenerate when the edition changed. Same non-blocking
  contract as feature images: failures log `image:failed(...)` and the
  release JSON still writes.
- types/schema: add `imageUrl?: string` to Release.

Site:
- SpecialEditionCard renders the illustration between the hero text and
  the stats strip, with the gitsky vignette + gold-accent treatment.
- ReleaseEditionHero un-defers the hero illustration block on the
  release detail page.
- site Release type mirrors the optional imageUrl field.

Tests:
- 6 unit tests for the release prompt builder (substitution, top-stories
  rendering, releaseNotes truncation, null fallbacks). 85/85 pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

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

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 17, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ddb19e33-009d-48f0-85c9-65df11ffb7a7

📥 Commits

Reviewing files that changed from the base of the PR and between c2464c5 and 9c0cdc7.

📒 Files selected for processing (3)
  • site/src/components/ReleaseEditionHero.tsx
  • site/src/components/ReleaseIllustration.tsx
  • site/src/components/SpecialEditionCard.tsx

📝 Walkthrough

Walkthrough

Adds AI-generated "Special Edition" release illustrations: prompt construction and tests, image generation/upload with MIME→extension utility, CLI integration to conditionally generate and preserve images, type/schema updates, and frontend components that render illustrations when release.imageUrl exists.

Changes

Release Image Generation Feature

Layer / File(s) Summary
Type and schema definitions
cli/src/types.ts, cli/src/schemas.ts, site/src/lib/releases.ts
Release type and validation schema are extended with an optional imageUrl field.
MIME-to-extension utility extraction
cli/src/image/mime.ts, cli/src/image/generate-feature-image.ts
Shared extensionFromMimeType helper is introduced and reused by the feature-image generator, replacing its inline implementation.
Release image prompt building
cli/src/image/release-prompt.ts, cli/src/image/release-prompt.test.ts
Prompt builder constructs editorial AI illustration prompts from release metadata with style constraints and color theming; tests verify placeholder substitution, story rendering, empty states, and note truncation.
Release image generation and upload
cli/src/image/generate-release-image.ts
New module exports generateReleaseImage, converting release metadata to prompt entries, building the prompt, generating the image, deriving file extension from MIME, uploading to storage with an encoded tag key, and returning the storage URL.
CLI release pipeline integration
cli/src/index.ts
Release processing pipeline accepts optional image-generation config, preserves existing image URLs when LLM output is reused, conditionally generates new images, writes image-enhanced release objects, and updates skip/logging logic.
Frontend release image display
site/src/components/ReleaseIllustration.tsx, site/src/components/ReleaseEditionHero.tsx, site/src/components/SpecialEditionCard.tsx
New EditionIllustration and HeroIllustration components render Next.js Image with overlays; hero and card components conditionally render these when release.imageUrl is present.

Sequence Diagram

sequenceDiagram
  participant CLI as Release Pipeline
  participant Prompt as Prompt Builder
  participant ImageGen as Image Generator
  participant Storage as Storage
  participant Frontend as Frontend Renderer

  CLI->>Prompt: pass release metadata (quip, story, notes, topStories, themeColor)
  Prompt->>Prompt: format top stories, truncate notes, apply theme color
  Prompt-->>ImageGen: full prompt text
  ImageGen->>ImageGen: generate image buffer (returns mimeType + buffer)
  ImageGen->>Storage: upload buffer with key `releases/{encodedTag}.{ext}`
  Storage-->>ImageGen: storage URL
  ImageGen-->>CLI: imageUrl
  CLI->>CLI: write Release including imageUrl
  Frontend->>Storage: request imageUrl
  Storage-->>Frontend: image bytes
  Frontend->>Frontend: render `EditionIllustration` / `HeroIllustration`
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • znat/gitpulse#54: Refactors the feature-image code by moving extensionFromMimeType into cli/src/image/mime.ts, directly supporting the shared MIME utility introduced in this PR.
  • znat/gitpulse#7: Earlier work on Special Edition frontend components that this PR extends by conditionally rendering illustrations from release.imageUrl.

Poem

🐰 I hopped through prompts, then painted a scene,

From quip and notes to a glossy sheen,
Buffer uploaded, a golden line drawn,
Release cards now glow at the break of dawn,
Hooray — the pipeline's art is reborn!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% 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 'feat: AI-generated release illustrations (PR 3/3)' clearly and directly summarizes the main objective of this changeset: adding AI-generated release illustrations as the final part of a multi-part feature.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 feat/release-images

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.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


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 and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 17, 2026

Vercel preview — built from 9c0cdc7b0d4504832c89fa1451ec6e88e6e462f5

https://gitpulse-demo-ez4v6twhn-znats-projects.vercel.app

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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 `@site/src/components/ReleaseEditionHero.tsx`:
- Around line 35-56: HeroIllustration’s Image has no load-failure handling; add
an onError handler on the Image in the HeroIllustration component (and
optionally render a fallback element) so broken URLs don’t leave a broken image:
locate function HeroIllustration and the Image props and add an onError callback
that hides or replaces the failed image (e.g., set display none or swap to a
local fallback src or show a visually appropriate placeholder element) and
ensure the alt remains meaningful for accessibility.

In `@site/src/components/SpecialEditionCard.tsx`:
- Around line 37-57: EditionIllustration currently uses Next.js Image with
unoptimized and no error handling; verify whether the image host is included in
next/image remotePatterns or remove unoptimized to allow Next to optimize (check
Image usage in EditionIllustration and remotePatterns config referenced in
ReleaseEditionHero), and add a lightweight onError handler on the Image (e.g.,
in EditionIllustration using the url/tag props) to swap to a fallback image or
set a local error state to render an alternative UI so failed loads don't break
the card.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4c647e59-3a52-40ef-83b5-38b5d76e0925

📥 Commits

Reviewing files that changed from the base of the PR and between 9e0bc88 and c2464c5.

📒 Files selected for processing (11)
  • cli/src/image/generate-feature-image.ts
  • cli/src/image/generate-release-image.ts
  • cli/src/image/mime.ts
  • cli/src/image/release-prompt.test.ts
  • cli/src/image/release-prompt.ts
  • cli/src/index.ts
  • cli/src/schemas.ts
  • cli/src/types.ts
  • site/src/components/ReleaseEditionHero.tsx
  • site/src/components/SpecialEditionCard.tsx
  • site/src/lib/releases.ts

Comment thread site/src/components/ReleaseEditionHero.tsx Outdated
Comment thread site/src/components/SpecialEditionCard.tsx Outdated
Extract the EditionIllustration and HeroIllustration helpers from
SpecialEditionCard / ReleaseEditionHero into a single client component
file. Each tracks a 'failed' state and unmounts the whole vignette+
gold-accent container on the Image's onError — without the wrapper, a
broken URL would leave a framed broken-image icon. Keeping the parent
card and hero as server components avoids hydrating presentational
markup that doesn't need it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

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

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@znat znat merged commit a862a27 into main May 18, 2026
8 checks passed
This was referenced May 17, 2026
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.

1 participant