From 905ea0dc15449aa39cd5bed8a35de3256c7e115d Mon Sep 17 00:00:00 2001 From: Christopher Goulart Date: Sat, 13 Jun 2026 12:20:24 -0400 Subject: [PATCH 1/3] ci: bump actions to Node 24 majors; skip publish for .github-only pushes Future-proofing ahead of the 2026-06-16 Node 20 forced migration: bump all CI actions to their latest Node-24 majors -- checkout v4->v6, setup-python v5->v6, setup-buildx v3->v4, login v3->v4, build-push v6->v7. Also add ^\.github/ to the 'changes' filter so workflow/CI-config-only pushes skip the image build + Pi redeploy, consistent with the existing .md/.claude exclusions (all are baked into the image via 'COPY . .' but are inert at runtime). Mixed pushes that also touch real code still build, so no redeploy that changes runtime behavior is suppressed. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/ci.yml | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6c7892b..2beab86 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,21 +7,21 @@ on: branches: [master] jobs: - changes: # flag doc-only pushes so we can skip publish for them + changes: # flag doc/CI-only pushes (md, .claude/, .github/) so we can skip publish for them runs-on: ubuntu-latest outputs: code: ${{ steps.filter.outputs.code }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: fetch-depth: 0 - id: filter - name: Did anything outside docs change? + name: Did anything outside docs/CI config change? run: | base="${{ github.event.before }}" if [ "${{ github.event_name }}" != "push" ] || ! git cat-file -e "${base}^{commit}" 2>/dev/null; then echo "code=true" >> "$GITHUB_OUTPUT" - elif git diff --name-only "$base" "${{ github.sha }}" | grep -qvE '(\.md$|^\.claude/)'; then + elif git diff --name-only "$base" "${{ github.sha }}" | grep -qvE '(\.md$|^\.claude/|^\.github/)'; then echo "code=true" >> "$GITHUB_OUTPUT" else echo "code=false" >> "$GITHUB_OUTPUT" @@ -30,8 +30,8 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - uses: actions/checkout@v6 + - uses: actions/setup-python@v6 with: python-version: "3.12" cache: pip @@ -49,8 +49,8 @@ jobs: audit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - uses: actions/checkout@v6 + - uses: actions/setup-python@v6 with: python-version: "3.12" cache: pip @@ -67,9 +67,9 @@ jobs: contents: read packages: write steps: - - uses: actions/checkout@v4 - - uses: docker/setup-buildx-action@v3 - - uses: docker/login-action@v3 + - uses: actions/checkout@v6 + - uses: docker/setup-buildx-action@v4 + - uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.actor }} @@ -77,7 +77,7 @@ jobs: - id: vars run: echo "sha=${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT" - name: Build & push API image - uses: docker/build-push-action@v6 + uses: docker/build-push-action@v7 with: context: . file: ./Dockerfile.api @@ -90,7 +90,7 @@ jobs: cache-from: type=gha cache-to: type=gha,mode=max - name: Build & push web app image - uses: docker/build-push-action@v6 + uses: docker/build-push-action@v7 with: context: . file: ./Dockerfile.app From d765a889fa292bbbe1592ee2704875c7215792a1 Mon Sep 17 00:00:00 2001 From: Christopher Goulart Date: Sat, 13 Jun 2026 12:44:32 -0400 Subject: [PATCH 2/3] docs: cover the .github/ filter exclusion and the auto-review workflow Our ci.yml change added ^\.github/ to the 'changes' gate, so update the CLAUDE.md + README descriptions of the docs-only skip to include .github/ (CI-config-only pushes now skip publish/redeploy too). Also add a CLAUDE.md note documenting the new claude-review.yml auto-review workflow: CLAUDE_CODE_OAUTH_TOKEN auth, comments-only, and the merge-first caveat for workflow edits. Co-Authored-By: Claude Opus 4.8 --- CLAUDE.md | 10 ++++++++-- README.md | 4 ++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 0c70c88..0ffec26 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -175,8 +175,14 @@ anymore (GPUH now deploys only GBot). - **Build (CI):** on push to `master`, the `publish` job in `.github/workflows/ci.yml` builds native **arm64** images and pushes them to **GHCR** — `ghcr.io/cgoulart35/halloweenevent-{api,webapp}` (`:latest` + `:`). Packages are **public**, so the Pi pulls anonymously (no `docker login`). - A `changes` job gates `publish`: pushes touching only docs (`**.md` / `.claude/`) still run - `test`+`audit` but skip the build, so docs/skills changes don't publish or redeploy. + A `changes` job gates `publish`: pushes touching only docs/CI config (`**.md` / `.claude/` / + `.github/`) still run `test`+`audit` but skip the build, so docs/skills/CI-config changes don't + publish or redeploy. +- **PR review (CI):** `.github/workflows/claude-review.yml` runs Claude (`anthropics/claude-code-action@v1`) + on every PR, posting inline findings; authed by the `CLAUDE_CODE_OAUTH_TOKEN` repo secret (a Claude + **Pro** subscription, not API billing). Comments only — never approves or blocks. Editing this + workflow makes a PR fail its own review (the action requires the workflow to match `master`), so + merge workflow changes first. - **Deploy (Pi):** `scripts/deploy-watcher.sh`, started at boot from `/etc/rc.local` via `scripts/start.sh`, polls GHCR every `DEPLOY_POLL_INTERVAL`s (default 120) and — when a new image digest appears — runs `scripts/deploy.sh`: `git fetch` + `git checkout -f master` + diff --git a/README.md b/README.md index 05d137f..519bf8b 100644 --- a/README.md +++ b/README.md @@ -218,8 +218,8 @@ CI/CD is **self-contained** (no external deploy service). On push to `master`, G (`ghcr.io/cgoulart35/halloweenevent-{api,webapp}`). On the Pi, `scripts/deploy-watcher.sh` (started at boot from `/etc/rc.local`) polls GHCR and, when a new image is published, runs `scripts/deploy.sh` — `git reset --hard origin/master` then `docker compose -f docker-compose-prod.yml pull && up -d`. The -trigger is the **published image, not the commit**, so a deploy never races the build. Doc-only pushes -(`**.md` / `.claude/`) are skipped by a `changes` gate, so they don't build or deploy. +trigger is the **published image, not the commit**, so a deploy never races the build. Doc/CI-config-only +pushes (`**.md` / `.claude/` / `.github/`) are skipped by a `changes` gate, so they don't build or deploy. `api.env` / `app.env` / `serviceAccountKey.json` are gitignored and live **persistently in the repo dir on the Pi** — injected at runtime (`env_file:` + a volume mount), never baked into the image, and From 88d92761b2969c5577e5451ea2d11563ff18d689 Mon Sep 17 00:00:00 2001 From: Christopher Goulart Date: Sat, 13 Jun 2026 13:02:15 -0400 Subject: [PATCH 3/3] ci: skip auto-review on draft PRs Add 'if: !github.event.pull_request.draft' to the review job so draft PRs don't spend Pro usage on WIP; add 'ready_for_review' to the triggers so a review fires when a draft is marked ready (opened/synchronize already ran while it was a draft and were skipped). Docs: note drafts are skipped, and sharpen the 'fails its own review' explanation to attribute it to the action's backend workflow-validation (401), since a reviewer misread the prior wording as a GitHub execution-model claim. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/claude-review.yml | 4 +++- CLAUDE.md | 7 ++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/claude-review.yml b/.github/workflows/claude-review.yml index 4dd0dc2..6e50e12 100644 --- a/.github/workflows/claude-review.yml +++ b/.github/workflows/claude-review.yml @@ -12,7 +12,7 @@ name: Claude Code Review # Honors CLAUDE.md. Comments only; never approves or blocks the PR. on: pull_request: - types: [opened, synchronize] + types: [opened, synchronize, ready_for_review] # One review per PR at a time; a fresh push cancels an in-flight review (saves usage). concurrency: @@ -27,6 +27,8 @@ permissions: jobs: review: + # Skip draft PRs (saves Pro usage on WIP); a review runs when the PR is marked ready for review. + if: ${{ !github.event.pull_request.draft }} runs-on: ubuntu-latest timeout-minutes: 20 steps: diff --git a/CLAUDE.md b/CLAUDE.md index 0ffec26..b342e40 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -179,10 +179,11 @@ anymore (GPUH now deploys only GBot). `.github/`) still run `test`+`audit` but skip the build, so docs/skills/CI-config changes don't publish or redeploy. - **PR review (CI):** `.github/workflows/claude-review.yml` runs Claude (`anthropics/claude-code-action@v1`) - on every PR, posting inline findings; authed by the `CLAUDE_CODE_OAUTH_TOKEN` repo secret (a Claude + on every non-draft PR (drafts get reviewed once marked ready), posting inline findings; authed by the `CLAUDE_CODE_OAUTH_TOKEN` repo secret (a Claude **Pro** subscription, not API billing). Comments only — never approves or blocks. Editing this - workflow makes a PR fail its own review (the action requires the workflow to match `master`), so - merge workflow changes first. + workflow makes a PR fail its own review — the action's **backend** rejects a PR whose workflow + differs from `master`'s (`401 Workflow validation failed`, not a GitHub-side rule) — so merge + workflow changes on their own first. - **Deploy (Pi):** `scripts/deploy-watcher.sh`, started at boot from `/etc/rc.local` via `scripts/start.sh`, polls GHCR every `DEPLOY_POLL_INTERVAL`s (default 120) and — when a new image digest appears — runs `scripts/deploy.sh`: `git fetch` + `git checkout -f master` +