ci: gate typecheck/lint/test on ref so main merge commits skip work
Forgejo Actions doesn't consistently honor `on.push.branches` as a filter — the merge commit landing on main after a release PR was still triggering the full CI workflow on a SHA that had already passed on dev, burning ~1 minute of runner time for no reason. The `build` job already had a ref guard, so no duplicate images were being pushed, but typecheck/lint/test ran unconditionally. Add the same guard (`refs/heads/dev` or `refs/tags/v*`) to those three so main pushes trigger the workflow but every job skips immediately with zero runner time. Also tightened the build job's tag filter from `refs/tags/` to `refs/tags/v` for consistency with the new guards and to avoid ever building from a non-version tag. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,12 @@
|
|||||||
# CI runs first; build only proceeds if all checks pass.
|
# CI runs first; build only proceeds if all checks pass.
|
||||||
#
|
#
|
||||||
# Push to any branch: typecheck + lint + test
|
# Push to dev: typecheck + lint + test + build :dev + :<sha>
|
||||||
# Push to dev: gates + build :dev + :<sha>
|
# Tag v* (release): typecheck + lint + test + build :latest + :<sha> + :<version>
|
||||||
# Tag v* (release): gates + build :latest + :<sha> + :<version>
|
#
|
||||||
|
# main pushes are NOT gated here: a merge to main only happens after
|
||||||
|
# dev has already passed CI, and the release tag is the sole trigger
|
||||||
|
# for a production image. Re-running CI on the merge commit just burns
|
||||||
|
# runner time without changing the outcome.
|
||||||
#
|
#
|
||||||
# To cut a release:
|
# To cut a release:
|
||||||
# Create a release via the Forgejo UI on main with a v* tag name.
|
# Create a release via the Forgejo UI on main with a v* tag name.
|
||||||
@@ -11,6 +15,13 @@
|
|||||||
# PRs aren't triggered on purpose — this is a solo dev→main flow, so
|
# PRs aren't triggered on purpose — this is a solo dev→main flow, so
|
||||||
# gating on branch push is already enough.
|
# gating on branch push is already enough.
|
||||||
#
|
#
|
||||||
|
# NOTE on the `if:` guards below: Forgejo Actions does not consistently
|
||||||
|
# honor `on.push.branches` as a filter — merge commits landing on main
|
||||||
|
# still trigger the workflow, producing redundant runs on the same SHA
|
||||||
|
# that was already gated on dev. Every job therefore repeats the ref
|
||||||
|
# check so main pushes trigger the workflow but every job skips
|
||||||
|
# immediately (no runner time, no duplicate work).
|
||||||
|
#
|
||||||
# Required secrets (repo → Settings → Secrets → Actions):
|
# Required secrets (repo → Settings → Secrets → Actions):
|
||||||
# REGISTRY_USER — your Forgejo username
|
# REGISTRY_USER — your Forgejo username
|
||||||
# REGISTRY_TOKEN — Forgejo PAT with write:packages scope
|
# REGISTRY_TOKEN — Forgejo PAT with write:packages scope
|
||||||
@@ -18,7 +29,7 @@ name: CI & Build
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [dev, main]
|
branches: [dev]
|
||||||
tags: ["v*"]
|
tags: ["v*"]
|
||||||
paths:
|
paths:
|
||||||
- "src/**"
|
- "src/**"
|
||||||
@@ -51,6 +62,8 @@ env:
|
|||||||
jobs:
|
jobs:
|
||||||
typecheck:
|
typecheck:
|
||||||
name: TypeScript typecheck
|
name: TypeScript typecheck
|
||||||
|
# Skip on main merge-commit pushes — see workflow header comment.
|
||||||
|
if: github.ref == 'refs/heads/dev' || startsWith(github.ref, 'refs/tags/v')
|
||||||
runs-on: ci-runner
|
runs-on: ci-runner
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v6
|
||||||
@@ -77,6 +90,7 @@ jobs:
|
|||||||
|
|
||||||
lint:
|
lint:
|
||||||
name: Python lint
|
name: Python lint
|
||||||
|
if: github.ref == 'refs/heads/dev' || startsWith(github.ref, 'refs/tags/v')
|
||||||
runs-on: ci-runner
|
runs-on: ci-runner
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v6
|
||||||
@@ -88,6 +102,7 @@ jobs:
|
|||||||
|
|
||||||
test:
|
test:
|
||||||
name: Python tests
|
name: Python tests
|
||||||
|
if: github.ref == 'refs/heads/dev' || startsWith(github.ref, 'refs/tags/v')
|
||||||
runs-on: ci-runner
|
runs-on: ci-runner
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v6
|
||||||
@@ -118,11 +133,10 @@ jobs:
|
|||||||
name: Build & push image
|
name: Build & push image
|
||||||
needs: [typecheck, lint, test]
|
needs: [typecheck, lint, test]
|
||||||
# Build on dev branch pushes and version tag pushes only.
|
# Build on dev branch pushes and version tag pushes only.
|
||||||
# main branch pushes run the gates for safety but do not build —
|
# Mirrors the ref guard on the gate jobs above — main merge-commit
|
||||||
# the release tag (v*) is the sole trigger for a production image.
|
# pushes skip here too, so no production image is ever built from a
|
||||||
if: |
|
# raw main push (only from the v* tag the release creates).
|
||||||
github.event_name == 'push' &&
|
if: github.ref == 'refs/heads/dev' || startsWith(github.ref, 'refs/tags/v')
|
||||||
(github.ref == 'refs/heads/dev' || startsWith(github.ref, 'refs/tags/'))
|
|
||||||
runs-on: ci-runner
|
runs-on: ci-runner
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|||||||
Reference in New Issue
Block a user