Skip to content

Migrate doc-site to Astro + eliminate build duplication - #11

Merged
nathanialhenniges merged 22 commits into
mainfrom
claude/homebrew-tap-cleanup-387fe8
Jul 26, 2026
Merged

nathanialhenniges merged 22 commits into
mainfrom
claude/homebrew-tap-cleanup-387fe8

Conversation

@nathanialhenniges

Copy link
Copy Markdown
Member

Summary

  • Migrates the hand-rolled bash-templated doc-site (scripts/build-site.sh, site/*.html) to an Astro static site (src/), preserving the exact server-rendered DOM/ARIA contract so JS-disabled pages and existing accessibility behavior are unchanged.
  • Consolidates duplicated .rb-metadata parsing and stability-detection logic (previously 4 independent parsers + a bash/JS stability duplicate with a parity test) into single-source src/lib/{catalog,stability,releases,serialize}.mjs, reused by the site, scripts/verify-checksums.mjs, scripts/check-release-freshness.mjs, and the test suite.
  • Tests now build the site once for the whole run (tests/global-setup.js) instead of racing on a shared site/output.css write across worker-local builds.
  • Adds scripts/verify-site.mjs, which checks the actual deployed _site artifact in CI before upload.
  • Repo-wide leftover audit (52-agent adversarial review, 23 confirmed / 23 refuted) removed dead DOM ids, unreachable code paths, a stale pre-migration UI/UX review doc, an unused test helper set, a stale lockfile entry, and a missing Node setup step in the brew CI job — while landing the review doc's one real open item (aria-hidden on 13 decorative SVGs) before deleting it.

Test plan

  • npm ci clean, npm audit --audit-level=high 0 vulnerabilities
  • npm test — 79/79 passing, single build per run
  • npx astro build (online, strict) — 3 pages built
  • node scripts/verify-site.mjs _site passes
  • node scripts/verify-checksums.mjs — both formula/cask artifact checksums match
  • node scripts/check-release-freshness.mjs — both packages current
  • Manual browser check: index + formula + cask detail pages render pixel-identical to pre-migration (dark theme no-flash, Cmd+K search, copy buttons, scroll-spy sidebar all functional)
  • CI green on this PR (test + brew + deploy-gate jobs)

🤖 Generated with Claude Code

nathanialhenniges and others added 21 commits July 23, 2026 13:46
- Update the v0.4.0 SHA-256 to the correct checksum.
- Declare the formula macOS-only and Apple-Silicon-only via depends_on
  :macos and depends_on arch: :arm64, placed before the platform blocks.
- Replace the inline Hardware::CPU.arm? conditional with nested
  on_macos/on_arm DSL blocks.
- Assert against version.to_s in the test instead of a literal "0.4.0".
- Mirror the dependency/architecture structure in the README formula
  template.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ds_on

- Update cask to version 2.0.1 with its SHA-256 (based on the
  origin/wolfwave-v2.0.1 bump).
- Add verified: "github.com/MrDemonWolf/wolfwave/" to the download URL
  since the homepage (mrdemonwolf.github.io) is on a different domain.
- Replace the deprecated depends_on macos: ">= :tahoe" with the
  supported depends_on macos: :tahoe.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Bump vitest to ^3.2.7 (resolved 3.2.7).
- Refresh package-lock.json; resolve advisories in vite, rollup, postcss,
  undici, picomatch, and esbuild via compatible non-breaking upgrades.
- npm audit now reports 0 vulnerabilities.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Security & reliability:
- Route release-history data through server-side escaping and HTML-escape
  the item name in <title>/<meta>/breadcrumb; add U+2028/U+2029 handling to
  json_escape (bash-3.2-safe octal) so no untrusted value can break out of a
  <script> block.
- Add a safe_url() scheme allowlist (http/https/mailto) for homepage and
  release-notes links.
- fetch_releases now uses curl connect/read timeouts + bounded retries,
  matches release tags with or without a leading "v", and paginates.
- Honor OFFLINE=1 (skip network) and STRICT_RELEASES/CI (fail rather than
  silently publish pages with version history removed).
- Run Tailwind via `npx --no-install` so the build never downloads a package.

Server-rendering:
- Render name, version, description, install command, homepage, caveats,
  stability, and the full version-history table into HTML at build time via
  new template placeholders. Detail pages are now fully useful with
  JavaScript disabled; the inline script only enhances (search/copy/theme/
  active-section tracking).
- Add an OUT_DIR knob so builds can target an isolated directory.

Also resolve the lone ShellCheck warning and document the Python 3 / offline
build requirements in the README.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Search dialog: visible close button, combobox/listbox semantics
  (role, aria-expanded, aria-activedescendant, aria-selected), an
  aria-live result-count announcer, and a real focus trap that cycles
  through every control instead of forcing focus back to the input.
  Focus still restores to the trigger on close.
- escapeHtml also neutralizes U+2028/U+2029; add a safeUrl() scheme
  allowlist used for search-result hrefs.
- Clipboard writes feature-detect navigator.clipboard and fall back to
  execCommand without throwing; theme localStorage reads/writes are
  wrapped so private-mode contexts don't break theme init.
- Remove the now-dead initDetailPage/stabilityBadge client renderer
  (content is server-rendered); detectStability stays as the tested
  reference classifier.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Homebrew audits description length; the previous 85-char desc would fail
brew audit --strict. Trim to 75 chars and update the README cask table.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- runBuild() now builds into an isolated temp dir (never reuses or deletes
  a user's _site) and runs OFFLINE for deterministic, network-free tests;
  bump vitest hookTimeout to match the build time.
- Derive expected metadata from Formula/*.rb and Casks/*.rb instead of
  hard-coding package names and versions; data-drive the build-output and
  html-content suites.
- Assert essential detail-page content is server-rendered (present before
  any script runs) and that NO {{...}} placeholder survives in any page.
- Add cask-validation.test.js (mirrors formula validation, incl. the
  verified-url rule) and validation-negative.test.js (missing/invalid
  required fields are detected).
- Add xss.test.js: builds a throwaway tap from a hostile formula and
  asserts </script> breakouts, javascript: URLs, and U+2028/U+2029 are
  neutralized in the output and embedded JSON.
- Add stability-parity.test.js: runs the same fixtures through the real
  bash detect_stability and JS detectStability and asserts they agree,
  preventing drift between the two implementations.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a test that fails when a README formula/cask row is missing or its
version/description drifts from the Formula/*.rb or Casks/*.rb source of
truth, keeping the hand-maintained tables honest.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Consolidate build/test/deploy into one workflow: the site is built and
  tested once, uploaded as the Pages artifact, and the deploy job (gated on
  both test and brew jobs succeeding, main pushes only) deploys that exact
  artifact. Removes the separate deploy-site.yml that could publish an
  untested, independently-rebuilt site.
- Build runs strict in CI (CI=true), so a GitHub API failure fails the run
  instead of silently shipping pages without version history.
- Add ShellCheck and `npm audit --audit-level=high` steps.
- New macos-latest brew job: brew style, readall, audit --strict --online
  (formulae + casks), livecheck, a real artifact-checksum verification
  (scripts/verify-checksums.sh downloads each asset and compares sha256),
  and a formula install/test smoke check.
- Pin every action to a full commit SHA with a version comment.
- Add a weekly scheduled release-freshness workflow
  (scripts/check-release-freshness.mjs) that flags packages behind their
  latest GitHub release.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
brew style <tap> also lints shell scripts under the tap with Homebrew's
shfmt/shellcheck style (prefers [[ ]] and ${var}), which failed on the build
tooling. Point brew style at the .rb files so it validates the packages it is
meant to; build/CI scripts are already covered by the ShellCheck step.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- iconwolf: order symbol deps (:macos, arch:) before the named "node" dep
  per FormulaAudit/DependencyOrder.
- wolfwave: alphabetize the zap trash array per Cask/ArrayAlphabetization.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
FormulaAudit/DependencyOrder wants `depends_on arch:` before
`depends_on :macos`. Reorder and mirror the README template.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A url/sha256 nested only inside on_macos/on_arm leaves the formula with no
stable url when Homebrew loads it in other OS/arch contexts, so brew readall
rejects it as invalid. Since only an Apple-Silicon macOS binary is published,
move url + sha256 to the top level and rely on depends_on arch: :arm64 +
depends_on :macos to restrict installation. Update the README template to
match (nested per-platform blocks are for formulae with multiple binaries).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add astro + @tailwindcss/vite, configure static output at base
/homebrew-den with outDir _site (keeps the existing Pages artifact
contract). Prep step for migrating the hand-rolled bash-templated
site to Astro.
Single source of truth for what used to be duplicated four times
(build-site.sh, verify-checksums.sh, check-release-freshness.mjs,
tests/helpers.js):

- catalog.mjs: the one .rb metadata parser
- stability.mjs: the one detectStability classifier
- releases.mjs: GitHub Releases fetch (offline/strict/token/retry)
- serialize.mjs: script-safe JSON + safeUrl (XSS helpers)
Ports the bash-templated site/*.html + site/partials/*.html 1:1 into
Astro: Base layout, Nav/SearchModal/Footer/PackageTable/StabilityBadge/
VersionHistory/DetailPage components, and index/formulae/[name]/
casks/[name] routes. Preserves the exact DOM/ARIA contract (ids,
classes, data-attrs) so client JS and tests still bind correctly.
Moves site/input.css -> src/styles/global.css and site/favicon.svg ->
public/favicon.svg unchanged (Tailwind v4 syntax already in place).
Everything server-renders at build time; pages work with JS disabled.
site/shared.js -> src/scripts/site.js, imported by the Base layout.
Same theme/search/copy/section-tracking behavior, same DOM hooks;
drops the dead detectStability copy (stability is computed once at
build time in src/lib/stability.mjs) and reads the embedded
package-data JSON + import.meta.env.BASE_URL instead of an inline
const data = {{PACKAGES_JSON}} template substitution.
- Delete scripts/build-site.sh (superseded by astro build).
- verify-checksums.sh -> verify-checksums.mjs, now sourcing url/
  version/sha256 from the shared catalog parser instead of its own
  grep/sed field extractor.
- check-release-freshness.mjs now imports loadCatalog instead of
  duplicating the same field/repoFrom parsing.
- Add verify-site.mjs: checks the real built _site artifact (index +
  a detail page per catalog package, bundled assets, parseable
  embedded search data) before it is deployed.
- ci.yml: build via `npx astro build` (strict), run verify-site.mjs
  before uploading the Pages artifact, drop the ShellCheck step (no
  .sh files remain), switch verify-checksums invocation to node, and
  add a Node setup step to the brew job (it runs a .mjs script but
  never had Node available).
- global-setup.js: one offline astro build for the whole run, path
  handed to every test file via provide/inject. Replaces the old
  worker-local runBuild() cache, which let build-output.test.js and
  html-content.test.js each trigger their own full build and race on
  a shared site/output.css write.
- helpers.js: re-exports loadCatalog/parseField from src/lib/
  catalog.mjs instead of a fourth parser; drops runBuild,
  loadSharedFunction, callBashFunction, and the now-dead
  FORMULA_DIR/CASKS_DIR/expectNoUnresolvedPlaceholders/listBuiltHtml
  helpers.
- stability.test.js imports detectStability from src/lib/
  stability.mjs; deletes stability-parity.test.js (nothing to keep in
  parity once there is one implementation).
- cask-validation.test.js sources fields from the catalog instead of
  its own divergent regex parser.
- build-output/xss tests drop two now-vacuous {{PLACEHOLDER}}
  assertions (the bash template engine they guarded is gone) and
  retarget assertions at Astro's output shape (bundled _astro/ assets,
  base-prefixed hrefs, embedded package-data JSON).
Build/run commands (astro dev/build/preview), repository structure
tree, test file list, and env knobs; drop bash/python3 build
references.
UIUX-REVIEW.md reviewed the deleted bash-templated site/ tree (every
path it cited no longer exists) and its findings were already
implemented in the ported code. Its one open item — aria-hidden on
decorative SVGs — was landed in the components it would have pointed
at before deleting it.
@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@nathanialhenniges, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 37 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

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.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: bfe9357c-c86b-40d6-8f92-39a2c12247c7

📥 Commits

Reviewing files that changed from the base of the PR and between 54c6484 and cf3d4e5.

⛔ Files ignored due to path filters (2)
  • package-lock.json is excluded by !**/package-lock.json
  • public/favicon.svg is excluded by !**/*.svg
📒 Files selected for processing (44)
  • .github/workflows/ci.yml
  • .github/workflows/deploy-site.yml
  • .github/workflows/release-freshness.yml
  • .gitignore
  • CLAUDE.md
  • Casks/wolfwave.rb
  • Formula/iconwolf.rb
  • README.md
  • UIUX-REVIEW.md
  • astro.config.mjs
  • package.json
  • scripts/build-site.sh
  • scripts/check-release-freshness.mjs
  • scripts/verify-checksums.mjs
  • scripts/verify-site.mjs
  • site/detail-template.html
  • src/components/DetailPage.astro
  • src/components/Footer.astro
  • src/components/Nav.astro
  • src/components/PackageTable.astro
  • src/components/SearchModal.astro
  • src/components/StabilityBadge.astro
  • src/components/VersionHistory.astro
  • src/layouts/Base.astro
  • src/lib/catalog.mjs
  • src/lib/releases.mjs
  • src/lib/serialize.mjs
  • src/lib/stability.mjs
  • src/pages/casks/[name].astro
  • src/pages/formulae/[name].astro
  • src/pages/index.astro
  • src/scripts/site.js
  • src/styles/global.css
  • tests/build-output.test.js
  • tests/cask-validation.test.js
  • tests/formula-validation.test.js
  • tests/global-setup.js
  • tests/helpers.js
  • tests/html-content.test.js
  • tests/readme-tables.test.js
  • tests/stability.test.js
  • tests/validation-negative.test.js
  • tests/xss.test.js
  • vitest.config.js
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/homebrew-tap-cleanup-387fe8

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.

The earlier --package-lock-only resync (done on macOS, after moving
tailwindcss into "dependencies") omitted @emnapi/runtime and other
platform-specific optional deps, so `npm ci` failed in CI with
"Missing: @emnapi/runtime@1.11.3 from lock file". A clean
node_modules + package-lock.json + full `npm install` regenerates it
correctly.
@nathanialhenniges
nathanialhenniges merged commit 5f4ecd2 into main Jul 26, 2026
5 checks passed
@nathanialhenniges
nathanialhenniges deleted the claude/homebrew-tap-cleanup-387fe8 branch July 26, 2026 11:40
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