Skip to content

#71 — ci: sticky-PR-comment workflow + consumer recipe + BDD doc-feature - #72

Merged
cmbays merged 3 commits into
mainfrom
infra-issue-71-sticky-comment-ci
May 27, 2026
Merged

cmbays merged 3 commits into
mainfrom
infra-issue-71-sticky-comment-ci

Conversation

@cmbays

@cmbays cmbays commented May 27, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Adds .github/workflows/report-preview.yml: on every PR, regenerates each committed example HTML against its fixture pair, uploads as a workflow artifact, and posts a single sticky PR comment (header: cute-dbt-report-preview) with clickable artifact download links. Structurally separate from example-report-check — that pair stays the byte-identity gate (required check); this is the human-validation affordance (if: always(), never blocks merge, NOT added to branch protection).
  • Adds a copyable consumer recipe at .github/workflows/examples/cute-dbt-report-preview.yml (subdirectory convention prevents auto-trigger inside this repo).
  • Adds a book recipe page at book/src/recipes/ci-sticky-comment.md walking through the workflow shape, the dbt parse-in-CI variation, fork-PR workarounds (pull_request_target / workflow_run split), and deferred follow-ups.
  • Pins the consumer contract as a doc-feature (features/consumer_report_contract.feature + thin step-def glue at tests/steps/consumer_report_contract.rs). 3 scenarios articulate the structural report properties that make the sticky-comment workflow useful — backed by existing assert_no_external_refs + embedded-payload parsing + std::fs::metadata. Feature-count gate bumps 8 → 9 atomically in ci.yml and lefthook.yml.

Fork-PR caveat (documented, intentional)

GitHub strips pull-requests: write from GITHUB_TOKEN on pull_request events from forks. Same-repo branches get the full affordance; fork PRs get the artifact upload only (sticky comment silently no-ops). Two well-trodden workarounds (pull_request_target for the comment-only job, or a workflow_run-triggered comment workflow) are documented for consumers in the recipe page. This matches the established crap-rs pattern.

Validation done locally

  • cargo fmt --all --check — clean
  • cargo clippy --all-targets --locked -- -D warnings — clean
  • cargo nextest run --locked — 364 passed, 2 skipped
  • cargo test --test bdd — 42 scenarios, 233 steps, all green (was 39 / ~210)
  • mdbook build book — clean
  • RUSTDOCFLAGS=-D warnings cargo doc --no-deps --document-private-items --locked — clean
  • cargo deny check — ok
  • actionlint .github/workflows/report-preview.yml .github/workflows/examples/cute-dbt-report-preview.yml — clean

Action SHA-pin choices

  • actions/checkout@34e1148… # v4.3.1 — matches existing ci.yml pin
  • dtolnay/rust-toolchain@29eef33… # stable — matches existing ci.yml pin
  • Swatinem/rust-cache@c193711… # v2.9.1 — matches existing ci.yml pin
  • actions/upload-artifact@ea165f8… # v4.6.2 — matches existing ci.yml pin (latest is v7.0.1; deferring the repo-wide bump to a separate consistency PR)
  • marocchino/sticky-pull-request-comment@0ea0beb… # v3.0.4 — NEW dependency; resolved to latest stable; verified header: + path: inputs supported in v3

Test plan (this PR validates itself live)

  • On first push: verify the sticky comment appears under header cute-dbt-report-preview with both playground-report.html and jaffle-shop-report.html rows + clickable artifact links.
  • On a follow-up push: verify the sticky comment updates in place (not a new comment per push).
  • Download one artifact via the link in the sticky comment; confirm the rendered HTML opens offline with the new Authoring YAML drawer (PR-E.1 / cute-dbt#69) visible.
  • Run with if: always() failing condition simulated (intentional bad fixture): confirm sticky comment still posts with status warning.
  • Confirm branch-protection.json is unchanged (this job is NOT a required check).

Deferred follow-ups

  • Pages preview per-PR (click-to-open instead of zip-download) — needs cleanup story for stale pr-<n>/ subdirs.
  • Real-dbt-install dogfood CI job (parse a bundled tiny dbt project; surface end-to-end consumer flow).
  • Reusable breezy-bays-labs/cute-dbt-action@v1 composite action.
  • Workflow-run-split for fork-PR sticky-comment coverage.
  • actions/upload-artifact bump v4.6.2 → v7.0.1 across all workflow files for consistency.

Closes #71

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores

    • Updated CI feature count tracking and pre-push hook validation thresholds.
  • Documentation

    • New recipe documenting a CI workflow for rendering and previewing reports on pull requests with sticky comments containing downloadable artifact links.
  • Tests

    • Added tests validating generated report output: external resource handling, embedded data payload structure, and file size constraints.

Review Change Stack

Adds .github/workflows/report-preview.yml: on every PR, regenerates each
committed example HTML against its fixture pair, uploads as a workflow
artifact, and posts a single sticky PR comment (header
`cute-dbt-report-preview`) with clickable artifact download links.
Structurally separate from `example-report-check` (the byte-identity
gate stays a required check; this new job is the human-validation
affordance — `if: always()`, never blocks merge, not added to branch
protection).

A copyable consumer template ships at
.github/workflows/examples/cute-dbt-report-preview.yml (subdirectory
convention prevents auto-trigger inside this repo). A book recipe page
at book/src/recipes/ci-sticky-comment.md walks through the workflow
shape, the dbt-parse-in-CI variation, the fork-PR workarounds
(pull_request_target / workflow_run split), and the deferred follow-ups
(Pages preview, reusable cute-dbt-action).

The BDD layer pins the consumer contract as a doc-feature
(features/consumer_report_contract.feature + thin step-def glue at
tests/steps/consumer_report_contract.rs). The 3 scenarios articulate
the structural report properties that make the sticky-comment workflow
useful — backed by existing test infrastructure
(common::assert_no_external_refs, embedded-payload parsing,
std::fs::metadata). Feature-count gate bumps 8 → 9 atomically in
.github/workflows/ci.yml and lefthook.yml (per the
lefthook-ci-gate-mirror-drift discipline).

Fork-PR caveat documented: GitHub strips pull-requests: write from
GITHUB_TOKEN on pull_request events from forks. Same-repo branches get
the full affordance; fork PRs get the artifact upload only. The recipe
page documents two well-trodden workarounds for consumers who need
fork-PR coverage.

Closes #71

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented May 27, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

@cmbays, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 38 minutes and 49 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 202d7954-1ab3-45ca-a2ad-b65f1ac163a7

📥 Commits

Reviewing files that changed from the base of the PR and between eefdf5d and 1058b72.

📒 Files selected for processing (3)
  • .github/workflows/examples/cute-dbt-report-preview.yml
  • .github/workflows/report-preview.yml
  • book/src/recipes/ci-sticky-comment.md
📝 Walkthrough

Walkthrough

This PR implements the sticky-comment report preview feature from issue #71: a GitHub Actions workflow that renders cute-dbt HTML reports on every PR, uploads them as workflow artifacts, and posts/updates a sticky PR comment with download links. The PR includes production and example workflows, a Gherkin feature spec and Rust step implementations that formalize the rendered report contract, documentation explaining the pattern, and administrative feature-count updates.

Changes

CI Sticky-Comment Report Preview Feature

Layer / File(s) Summary
Example report preview workflow template
.github/workflows/examples/cute-dbt-report-preview.yml
Template workflow demonstrates the sticky-comment pattern: on PR trigger, validate manifest paths, install cute-dbt, render HTML, upload artifact, query artifact list via GitHub CLI, format comment body, and post sticky PR comment via marocchino/sticky-pull-request-comment action.
Production report preview workflow
.github/workflows/report-preview.yml
Production workflow runs regenerate matrix job to render multiple example HTML reports and upload each as artifact, then sticky-comment job queries artifacts, formats markdown table with download links and regenerate status, and posts/updates sticky PR comment with pull-requests: write permission and if: always() to surface comments even on matrix failure.
Consumer report contract specification
features/consumer_report_contract.feature
Gherkin feature formalizes the CI contract for rendered HTML: zero external resource references, embedded cute-dbt-data JSON payload with non-empty models array, and file size under 10 MB (GitHub Actions artifact limit).
Consumer report contract test steps
tests/steps/consumer_report_contract.rs, tests/steps/mod.rs
Rust step implementations validate HTML output: assert exit code success and DOM contains no external refs, parse and JSON-decode embedded cute-dbt-data payload asserting non-empty models array, and verify rendered file size below hardcoded 10 MB budget constant.
Documentation and recipe guide
book/src/SUMMARY.md, book/src/recipes/ci-sticky-comment.md
Recipe doc explains sticky-comment pattern: manifest-pair generation via dbt parse, artifact+link approach required for GitHub's markdown-only comments, fork-PR permission handling options (pull_request_target or workflow_run-triggered comment job), and suggested follow-on extensions (Pages per-PR previews, reusable composite action, dbt-fusion smoke test).
Feature-count invariant coordination
.github/workflows/ci.yml, lefthook.yml
Updated feature-count guard from 8 to 9 to account for new consumer_report_contract.feature file, with updated inline comments documenting the invariant threshold and which feature file caused the bump.

Sequence Diagram

sequenceDiagram
  participant PR as Pull Request
  participant Regenerate as regenerate job
  participant Artifacts as Artifact Storage
  participant StickyJob as sticky-comment job
  participant GhCli as GitHub CLI
  participant PRComment as PR Comment
  PR->>Regenerate: Trigger on pull_request
  Regenerate->>Artifacts: Render and upload HTML reports
  Artifacts-->>Regenerate: Artifacts stored (success/failure)
  Regenerate->>StickyJob: Job complete (runs if always())
  StickyJob->>GhCli: Query run artifacts
  GhCli->>StickyJob: Return artifact list
  StickyJob->>StickyJob: Format markdown table with links
  StickyJob->>PRComment: Post/update sticky comment
  PRComment-->>PR: Comment visible to reviewers
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • breezy-bays-labs/cute-dbt#43: Related through the addition of new Cucumber step-definition modules (tests/steps/consumer_report_contract.rs) and their registration in tests/steps/mod.rs, which mirrors the step-harness wiring patterns established in that PR.
  • breezy-bays-labs/cute-dbt#63: Both PRs coordinate the feature-count invariant guard in ci.yml and lefthook.yml by incrementing the expected .feature file count to account for newly added Gherkin specs and their corresponding step modules.

Poem

🐰 A sticky comment hops into the PR,
With rendered reports for all to see—
HTML artifacts uploaded so bright,
No more must we build to validate the sight!
Nine features now dance, the contract is blessed,
CI smoke-tests our renders with manifest zest. ✨

🚥 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 changes: adding a sticky-PR-comment CI workflow, a consumer recipe, and a BDD doc-feature, which aligns with the changeset.
Linked Issues check ✅ Passed All coding requirements from issue #71 are met: sticky-comment workflow implemented with marocchino action SHA-pinned, artifact upload and posting on every PR, separate from byte-identity checks, runs if: always(), not a required check, correct permissions scoped, documentation and BDD tests added, feature count incremented to 9.
Out of Scope Changes check ✅ Passed All changes are within scope of issue #71: workflow implementation, documentation, BDD tests, feature-count updates, and a copyable consumer recipe. No unrelated changes detected.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch infra-issue-71-sticky-comment-ci

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.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces a new CI recipe and documentation for posting a sticky PR comment with a downloadable report preview. It also adds a corresponding Cucumber feature file (consumer_report_contract.feature) and Rust step definitions to formally assert that the rendered report remains self-contained, embeds the necessary payload, and stays under a 10MB size budget. Additionally, the feature count check in lefthook.yml was updated. Feedback is provided to use a generic version placeholder (e.g., v0.x) instead of a specific version (v0.1.0) in the documentation to prevent information rot.

Comment thread book/src/recipes/ci-sticky-comment.md Outdated
@github-actions

github-actions Bot commented May 27, 2026 •

Copy link
Copy Markdown
Contributor

📄 Rendered report preview

All examples regenerated cleanly.

Example Artifact
jaffle-shop-report.html Download
playground-report.html Download

Click Download to fetch the rendered HTML. Each artifact
is a zip containing the single-file report — extract and open
in any browser. Reports are fully self-contained (zero
external resource requests).

Alternative: GitHub CLI
# gh CLI >= 2.63 extracts into ./report-preview-playground/.
gh run download 26489582317 -R breezy-bays-labs/cute-dbt -n report-preview-playground
open report-preview-playground/playground-report.html

Posted by report-preview.yml for 1058b726b7ad7b9ccf0853483b5b062de9da71f4. Affordance only — never blocks merge.

@cmbays
cmbays marked this pull request as ready for review May 27, 2026 03:27
Replace `v0.1.0`-specific phrasing in the recipe page and consumer
template with event-anchored language ("once cute-dbt is available on
crates.io") so the docs don't rot past the first publish. Gemini medium-
priority finding on PR #72.

The substantive recipe content is unchanged — same install paths
(cargo install --git for pre-publish; cargo binstall cute4dbt
post-publish), same fork-PR caveat, same artifact + sticky comment
shape.

@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 @.github/workflows/examples/cute-dbt-report-preview.yml:
- Around line 33-35: The workflow's job "report-preview" needs the actions
permission so the GH API call (gh api
"/repos/${REPO}/actions/runs/${RUN_ID}/artifacts") using GITHUB_TOKEN can list
artifacts; update the job's permissions block (the existing permissions:
contents: read and pull-requests: write) to include actions: read so the "Build
comment body" step can successfully retrieve run-artifacts; apply the same
change for the other occurrences referenced (lines ~94-106) where artifact
lookup is performed.

In @.github/workflows/report-preview.yml:
- Around line 126-149: The workflow's "Build comment body" step uses the Actions
REST API to list artifacts (the gh api call that populates artifacts_json) which
requires the GITHUB_TOKEN to have actions: read permission; update the job
permissions block (for the sticky-comment job) to include "actions: read"
alongside existing permissions so the gh api call won't return an empty array.
Also update the reviewer CLI instructions that use "gh run download -n
report-preview-playground" to reference the extracted path when opening the
report (use report-preview-playground/playground-report.html instead of
playground-report.html) so the downloaded artifact is opened from the correct
directory.

In `@tests/steps/consumer_report_contract.rs`:
- Around line 30-43: Replace the static DOM check in then_zero_external_refs
with a real headless-browser network-block test: instead of calling
common::assert_no_external_refs(html) inside then_zero_external_refs, launch a
headless browser instance with network access disabled, open the generated
report HTML via its file:// URL (using world.report_html.as_ref()), subscribe
to/record any network requests made by the page, and fail the test if any
outbound requests occur (assert no requests). Ensure the browser is run
headless, properly closed on test completion, and integrate this logic into
then_zero_external_refs so the runtime network behavior (not just static
attributes) is validated.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: ef80748c-65b8-456e-8307-97fd81953783

📥 Commits

Reviewing files that changed from the base of the PR and between 79aa3a1 and eefdf5d.

📒 Files selected for processing (9)
  • .github/workflows/ci.yml
  • .github/workflows/examples/cute-dbt-report-preview.yml
  • .github/workflows/report-preview.yml
  • book/src/SUMMARY.md
  • book/src/recipes/ci-sticky-comment.md
  • features/consumer_report_contract.feature
  • lefthook.yml
  • tests/steps/consumer_report_contract.rs
  • tests/steps/mod.rs

Comment thread .github/workflows/examples/cute-dbt-report-preview.yml
Comment thread .github/workflows/report-preview.yml
Comment thread tests/steps/consumer_report_contract.rs
Two CodeRabbit findings on PR #72:

- `actions: read` added to the sticky-comment job in report-preview.yml
  and to the consumer-recipe job. The `gh api .../actions/runs/<id>/
  artifacts` lookup requires this permission under least-privilege
  GITHUB_TOKEN defaults — without it, the call can silently fail and
  the comment falls back to the placeholder link.
- gh CLI >= 2.63 extracts a single -n named artifact into a
  subdirectory named after the artifact. Updated the sticky comment's
  `Alternative: GitHub CLI` fallback hint to reference
  report-preview-playground/playground-report.html instead of just
  playground-report.html, matching the actual extraction layout.

Declined CR's third finding (replace static lint with headless
browser test in tests/steps/consumer_report_contract.rs) — AGENTS.md
establishes a two-tier zero-egress model: PRIMARY is
tests/headless_zero_egress.rs (real Chromium with network blocked);
SECONDARY is the static common::assert_no_external_refs lint. My
step mirrors tests/steps/zero_egress.rs:62-70 exactly, which uses
the same static stand-in for the same reason. Duplicating the
headless proof inside cucumber-rs would be redundant.
@cmbays
cmbays merged commit 41a1c90 into main May 27, 2026
28 checks passed
@cmbays
cmbays deleted the infra-issue-71-sticky-comment-ci branch May 27, 2026 03:59
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.

ci: sticky-PR-comment job posting the rendered HTML report as a visual smoke-test affordance

1 participant