Skip to content

ci: build dist on merge to main, publish to dedicated dist branch - #66

Merged
jackgranatowski merged 2 commits into
mainfrom
ci/publish-dist-branch
May 22, 2026
Merged

ci: build dist on merge to main, publish to dedicated dist branch#66
jackgranatowski merged 2 commits into
mainfrom
ci/publish-dist-branch

Conversation

@kiro-agent

@kiro-agent kiro-agent Bot commented May 22, 2026

Copy link
Copy Markdown

This pull request was created by @kiro-agent on behalf of @jackgranatowski 👻

Comment with /kiro fix to address specific feedback or /kiro all to address everything.
Learn about Kiro autonomous agent


Summary

Replaces the per-commit dist regeneration (via the .githooks/pre-commit hook) with a once-per-merge GitHub Action that publishes built CSS bundles to a dedicated orphan dist branch.

After this lands, the build runs exactly once per merge to main, not on every commit.

Architecture

main (clean source — no generated files)
   │  push to main
   ▼
.github/workflows/publish-dist.yml
   │  npm ci && npm run build
   ▼
dist branch (orphan — only built artifacts at root)
   │
   ▼
https://cdn.jsdelivr.net/gh/codeslash-dev/SLASHED@dist/slashed.essential.min.css

The dist branch:

  • is orphan (no shared history with main), so force-pushing it is safe — there's no way to accidentally rewrite main
  • contains only the 30 built artifacts plus a SOURCE.txt stamp recording the source commit/build timestamp
  • lives at the branch root (no dist/ prefix), so jsDelivr URLs are clean

Why this shape

Changes

File Change
.github/workflows/publish-dist.yml New. Runs on push: main, builds, force-pushes orphan dist branch with SOURCE.txt provenance stamp.
docs/demo.html Built-bundle link migrated @main/dist/...@dist/.... The optional/tokens.palette.css link stays on @main because it references a source file.

Sequencing relative to #65

  • revert: re-commit dist/ to unbreak jsDelivr @main CDN URLs #65 first — re-commits dist/ to main so existing @main/dist/... URLs in the wild stop being broken (they're currently surviving on jsDelivr edge cache that will expire within ~12h).
  • This PR second — adds the new flow. Both @main/dist/... (legacy) and @dist/... (new) work simultaneously while users migrate.
  • Follow-up PR third (not in this PR) — re-add dist/ to .gitignore and remove it from main, fully completing chore: clean up repo structure and gitignore #63's original cleanup. Safe to do once @dist is verified populated and consumers have moved.

Tested

  • YAML parses cleanly (js-yaml parse on the workflow), 6 well-named steps in expected order.
  • Concurrency block uses correct GitHub Actions schema.
  • cancel-in-progress: true is the safer default for force-push publishers — never lets an older build clobber a newer one.

Note

I did not configure the workflow to delete the existing .githooks/pre-commit rebuild block. Removing the pre-commit rebuild would be the natural next step (developers no longer need to rebuild locally for CDN consumers — only for their own testing) but I left it as a separate decision so anyone running with the hook installed isn't surprised by behaviour changes inside this PR.

Summary by CodeRabbit

  • Chores
    • Added an automated publish workflow to build and publish CSS bundles on updates to the main branch and via manual trigger.
    • Demo page updated to load the stylesheet from the published/dist location so it reflects the built artifacts.

Review Change Stack

Adds .github/workflows/publish-dist.yml: triggered on push to main, runs
`npm run build`, then force-pushes the dist/ tree (plus a SOURCE.txt
stamp recording the source commit) to a dedicated orphan `dist` branch.

The dist branch contains only built artifacts at its root, so jsDelivr
URLs become:

  https://cdn.jsdelivr.net/gh/codeslash-dev/SLASHED@dist/slashed.essential.min.css

This keeps main free of generated files (the original goal of #63)
without sacrificing the @main-style CDN distribution path. Build runs
once per merge instead of on every commit, and concurrency is set to
cancel-in-progress on the publish-dist group so racing merges don't
race force-pushes.

docs/demo.html migrated to @dist for the built bundle (line 8). The
optional/tokens.palette.css link stays on @main because it references
a source file that lives only on main.

Existing @main/dist/ URLs continue to work for now (dist/ is on main
courtesy of #65). After the dist branch is verified populated, a
follow-up PR can re-add dist/ to .gitignore and remove it from main,
completing the original cleanup safely.
@coderabbitai

coderabbitai Bot commented May 22, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds a GitHub Actions workflow that builds dist/ artifacts on pushes to main, stages them with source metadata, and force-publishes them to an orphan dist branch; demo HTML updated to reference the published dist stylesheet path.

Changes

Automated CSS publication to dist branch

Layer / File(s) Summary
Workflow triggers and permissions
.github/workflows/publish-dist.yml
Workflow configured to run on main pushes and manual dispatch, with concurrency control to cancel in-flight runs and contents: write permission for publishing.
Build and artifact staging
.github/workflows/publish-dist.yml
Checks out main (persist-credentials:false), sets up Node 22 with npm caching, runs npm ci and npm run build, stages dist/ to /tmp/sf-dist, and writes /tmp/sf-dist/SOURCE.txt containing GITHUB_SHA, GITHUB_REF, UTC timestamp, and workflow filename.
Dist branch publishing
.github/workflows/publish-dist.yml
Creates an orphan dist branch checkout, clears the working tree, copies staged artifacts from /tmp/sf-dist, commits them, and force-pushes dist using an x-access-token remote URL built from GITHUB_TOKEN (persist-credentials:false).
Demo stylesheet alignment
docs/demo.html
docs/demo.html updated to load dist/slashed.essential.css from the @dist CDN path and its inline comment updated to reference the publish workflow as the source of built bundles.

Sequence Diagram(s)

sequenceDiagram
  participant ComponentA
  participant ComponentB
  ComponentA->>ComponentB: observable interaction
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • codeslash-dev/SLASHED#64: Also changes the CDN stylesheet source in docs/demo.html (this PR switches to @dist/..., while #64 restores @main/...).
  • codeslash-dev/SLASHED#65: Related to how dist/ artifacts are published or committed back into the repository; addresses overlapping publishing strategies.
🚥 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 accurately describes the main change: implementing CI to build and publish distribution artifacts to a dedicated branch on merge to main.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci/publish-dist-branch

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

@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: 2

🧹 Nitpick comments (1)
.github/workflows/publish-dist.yml (1)

17-17: ⚡ Quick win

Restrict manual dispatch publishes to main only.

Line 17 allows dispatch from any selected ref; that can publish non-main artifacts to dist by mistake.

Suggested fix
 jobs:
   publish-dist:
+    if: github.ref == 'refs/heads/main'
     name: Build and force-push dist branch
🤖 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 @.github/workflows/publish-dist.yml at line 17, The workflow currently allows
manual dispatch from any ref via the workflow_dispatch trigger; modify the
workflow_dispatch configuration so manual runs are restricted to the main branch
only by adding a branches filter (e.g., set workflow_dispatch to include
branches: [main]) so only refs on main can trigger a manual publish; update the
workflow_dispatch entry in the publish-dist.yml accordingly.
🤖 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/publish-dist.yml:
- Line 34: Replace the mutable action tags with immutable commit SHAs: locate
the two occurrences "uses: actions/checkout@v4" and "uses:
actions/setup-node@v4" and change them to the corresponding pinned SHAs (e.g.,
"uses: actions/checkout@<commit-sha>" and "uses:
actions/setup-node@<commit-sha>") by copying the latest stable commit SHA from
each action's GitHub repository (or marketplace) and updating the workflow;
commit the change and verify the workflow runs successfully.
- Around line 33-36: The workflow's "Checkout main" step uses
actions/checkout@v4 which by default persists credentials to the repo git
config; change that checkout step to set persist-credentials: false to avoid
leaving GITHUB_TOKEN in the workspace, and instead add explicit authentication
only where you perform the push (e.g., pass the token to the push action or
configure git remote/auth in the specific push step). Update the "Checkout main"
step (actions/checkout@v4) to include persist-credentials: false and ensure the
subsequent push step uses an explicit token input for authentication.

---

Nitpick comments:
In @.github/workflows/publish-dist.yml:
- Line 17: The workflow currently allows manual dispatch from any ref via the
workflow_dispatch trigger; modify the workflow_dispatch configuration so manual
runs are restricted to the main branch only by adding a branches filter (e.g.,
set workflow_dispatch to include branches: [main]) so only refs on main can
trigger a manual publish; update the workflow_dispatch entry in the
publish-dist.yml accordingly.
🪄 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: CHILL

Plan: Pro Plus

Run ID: 77dffdb4-cb0f-4f42-967d-cbc3d8ee1ab2

📥 Commits

Reviewing files that changed from the base of the PR and between 444521e and 4662dc7.

📒 Files selected for processing (2)
  • .github/workflows/publish-dist.yml
  • docs/demo.html

Comment thread .github/workflows/publish-dist.yml
runs-on: ubuntu-latest
steps:
- name: Checkout main
uses: actions/checkout@v4

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE=".github/workflows/publish-dist.yml"
echo "== File: $FILE =="
if [ -f "$FILE" ]; then
  nl -ba "$FILE" | sed -n '1,160p'
else
  echo "Missing $FILE"
fi

echo
echo "== Extract uses: lines =="
rg -n '^\s*uses:\s*actions/(checkout|setup-node)@' .github/workflows/publish-dist.yml || true

Repository: codeslash-dev/SLASHED

Length of output: 173


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE=".github/workflows/publish-dist.yml"
echo "== File: $FILE =="

if [ -f "$FILE" ]; then
  # Print with line numbers without relying on `nl`
  awk '{printf "%5d\t%s\n", NR, $0}' "$FILE" | sed -n '1,220p'
else
  echo "Missing $FILE"
fi

echo
echo "== Extract uses: lines =="
rg -n '^\s*uses:\s*actions/(checkout|setup-node)@' "$FILE" || true

Repository: codeslash-dev/SLASHED

Length of output: 3307


Pin GitHub Actions to immutable SHAs.

.github/workflows/publish-dist.yml uses mutable tags:

  • uses: actions/checkout@v4 (line 34)
  • uses: actions/setup-node@v4 (line 39)
Suggested fix
-      - name: Checkout main
-        uses: actions/checkout@v4
+      - name: Checkout main
+        uses: actions/checkout@<full-length-commit-sha> # actions/checkout v4.x

-      - name: Setup Node
-        uses: actions/setup-node@v4
+      - name: Setup Node
+        uses: actions/setup-node@<full-length-commit-sha> # actions/setup-node v4.x
🧰 Tools
🪛 zizmor (1.25.2)

[error] 34-34: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 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 @.github/workflows/publish-dist.yml at line 34, Replace the mutable action
tags with immutable commit SHAs: locate the two occurrences "uses:
actions/checkout@v4" and "uses: actions/setup-node@v4" and change them to the
corresponding pinned SHAs (e.g., "uses: actions/checkout@<commit-sha>" and
"uses: actions/setup-node@<commit-sha>") by copying the latest stable commit SHA
from each action's GitHub repository (or marketplace) and updating the workflow;
commit the change and verify the workflow runs successfully.

Per the review on PR #66: actions/checkout@v4 defaults to
persist-credentials: true, which writes GITHUB_TOKEN into .git/config
and leaves it readable by every subsequent step (npm install, npm run
build, the build script itself). Combined with `contents: write` on
this job, that's a wider blast radius than the workflow needs — only
the final force-push step legitimately needs push credentials.

Flip persist-credentials to false on checkout, and authenticate
explicitly at push time via GITHUB_TOKEN scoped to that one step.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/publish-dist.yml (1)

68-90: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard publish-dist so workflow_dispatch can’t publish non-main builds.

workflow_dispatch can be started for any selected branch, and the run will use that branch’s ref as github.ref—so the force-push would overwrite dist with non-merged artifacts. Gate the job to refs/heads/main.

🔧 Suggested fix
 jobs:
   publish-dist:
+    if: github.ref == 'refs/heads/main'
     name: Build and force-push dist branch
🤖 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 @.github/workflows/publish-dist.yml around lines 68 - 90, The publish step
currently force-pushes whatever branch triggered the run; restrict it so only
runs on the main branch can publish by adding a guard like if: github.ref ==
'refs/heads/main' (placed on the publish-dist job or at least on the "Force-push
dist branch" step) so workflow_dispatch runs from other branches cannot
overwrite dist; update the workflow to check github.ref == 'refs/heads/main'
before executing the git checkout/orphan + git push sequence.
🤖 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.

Outside diff comments:
In @.github/workflows/publish-dist.yml:
- Around line 68-90: The publish step currently force-pushes whatever branch
triggered the run; restrict it so only runs on the main branch can publish by
adding a guard like if: github.ref == 'refs/heads/main' (placed on the
publish-dist job or at least on the "Force-push dist branch" step) so
workflow_dispatch runs from other branches cannot overwrite dist; update the
workflow to check github.ref == 'refs/heads/main' before executing the git
checkout/orphan + git push sequence.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8802cf36-69ea-4bba-8a0f-3f9689d17c70

📥 Commits

Reviewing files that changed from the base of the PR and between 4662dc7 and 3e753ee.

📒 Files selected for processing (1)
  • .github/workflows/publish-dist.yml

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.

2 participants