This document describes the GitHub Actions workflows used in this repository and explains the recent improvements made for better performance and maintainability.
The repository uses four main workflows:
- CI (
ci.yml) - Continuous Integration for code quality and deployment - Version Bump (
version-bump.yml) - Automatic or manual version updates with changelog - Create Version Tag (
create-version-tag.yml) - Creates release tags for merged version bump PRs - Release (
release.yml) - Build and publish releases
Trigger: Push to main, Pull Requests, Manual dispatch
- Lint - Code linting with Deno
- Format - Code formatting check with Deno
- Type Check - TypeScript type checking for all entry points
- Test - Run test suite with coverage; coverage artifact uploaded on both PRs and main push
- Security - Trivy vulnerability scanning
- Frontend Lint & Test (
frontend-lint-test) - Angular frontend lint and test - Frontend Build (
frontend-build) - Angular frontend build and artifact upload - Validate Cloudflare Schema - Runs
deno task schema:cloudflareand verifies thatdocs/api/cloudflare-schema.yaml(Cloudflare API Shield schema generated from the OpenAPI spec) is up to date
- Verify Deploy - Cloudflare Worker build dry-run (
deno task wrangler:verify); runs on PRs only, waits for thefrontend-buildartifact but otherwise runs in parallel with the quality checks above
- CI Gate - Python script verifying all upstream jobs passed or were acceptably skipped; blocks publish and deploy
- Publish - Publish to JSR (main only, after CI gate passes)
- Deploy - Deploy
adblock-compilerbackend Worker to Cloudflare (main only, when enabled, after CI gate passes) - Deploy Frontend - Deploy
adblock-frontendSSR Worker to Cloudflare; downloads thefrontend-distartifact, runsscripts/build-worker.shto inject/remove theCF_WEB_ANALYTICS_TOKENplaceholder, then runspnpm run deploy. Triggered on main push (afterci-gate+frontend-buildpass); also deployed on tag push viarelease.ymldeploy-frontendjob (fullpnpm run build+ token injection + deploy)
All composite actions live in .github/actions/ and are called with uses: ./.github/actions/<name>.
| Action | Purpose | Used by |
|---|---|---|
deno-install |
3-attempt retry loop for deno install with DENO_TLS_CA_STORE=system |
setup-deno-env |
setup-deno-env |
Install Deno, cache ~/.cache/deno + ~/.deno, optionally run deno install |
lint-format, typecheck, test, validate-artifacts, check-slow-types, audit-public-surface, validate-migrations, verify-deploy, deploy, publish |
setup-env |
Load .env / .env.<branch> files into the runner environment |
test, verify-deploy, deploy |
setup-pnpm-node |
Setup pnpm, cache the pnpm store, and install Node.js | frontend-lint-test, frontend-build |
zta-checks |
Run all four ZTA security lint checks (wildcard CORS, hardcoded secrets, eval/new Function, string-interpolated SQL) | zta-lint |
validate-wrangler-toml |
Assert that wrangler.toml contains no placeholder binding IDs before deploying |
verify-deploy, deploy |
deploy-worker |
Run D1 migrations, generate version, set up queues/R2, deploy tail worker + main worker, record outcome | deploy |
- name: Setup pnpm and Node.js
uses: ./.github/actions/setup-pnpm-node
with:
node-version: '24.15' # optional, defaults to '24.15'- name: Run ZTA security checks
uses: ./.github/actions/zta-checks- name: Validate wrangler.toml
uses: ./.github/actions/validate-wrangler-toml- name: Deploy worker
uses: ./.github/actions/deploy-worker
with:
github-sha: ${{ github.sha }}Requires CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID, and CF_WEB_ANALYTICS_TOKEN to be set in the job-level env: (inherited automatically; no need to pass as inputs).
- ✅ Parallelization: Lint, format, typecheck, test, and security scans run simultaneously
- ✅ Proper Gating:
ci-gateblocks publish/deploy until lint, format, typecheck, test, security, frontend-build, and verify-deploy all pass - ✅ Worker Build Verified on PRs:
verify-deployruns a Cloudflare Worker dry-run on every PR so Worker build failures are caught before merge - ✅ Composite Actions: Repeated step sequences extracted to
.github/actions/— no duplication across jobs - ✅ Modular CI:
ci.ymlreduced from 783 → 609 lines (−22%) by delegating step logic to focused composite actions - ✅ Separate Frontend Jobs:
frontend-lint-test(lint + test) andfrontend-build(build + artifact upload) run as independent parallel jobs so a lint failure does not block the build artifact from being produced - ✅ Frozen Lockfile:
pnpm install --frozen-lockfileenforced — CI fails ifpnpm-lock.yamldrifts frompackage.json - ✅ Coverage on PRs: Test coverage artifact uploaded on pull requests, not just main push
- ✅ SHA-Pinned Actions: All third-party actions pinned to full commit SHAs with version comments (supply-chain hardening)
- ✅ Better Caching: Includes
deno.lockin cache key for more precise invalidation - ✅ Comprehensive Type Checking: Checks all entry points (index.ts, cli.ts, worker.ts, tail.ts)
- ✅ Consolidated Worker Deployment: Main and tail Cloudflare Workers deployed from a single CI deploy job (no separate Pages deployment)
- ✅ Frontend Worker CI Deployment:
deploy-frontendjob deploysadblock-frontendon every main push, after thefrontend-buildartifact is available;CF_WEB_ANALYTICS_TOKENis injected/removed byscripts/build-worker.shbeforewrangler deploy - ✅ Migration Error Handling: D1 migration retry loop distinguishes auth errors from transient failures and surfaces actionable remediation steps
- ✅ wrangler.toml Validation: Both
verify-deploy(PRs) anddeploy(main) validate that no placeholder binding IDs exist before any Cloudflare operation
- Before: ~5-7 minutes (sequential execution)
- After: ~2-3 minutes (parallel execution)
- Improvement: ~40-50% faster
Trigger: Push tags (v*), Manual dispatch with version input
- Validate - Run full CI suite before building anything
- Build Binaries - Build native binaries for all platforms (parallel matrix)
- Build Docker - Build and push multi-platform Docker images
- Create Release - Generate GitHub release with all artifacts
- Deploy Frontend - Deploy
adblock-frontendSSR Worker to Cloudflare aftervalidatepasses; fullpnpm run build+scripts/build-worker.shtoken injection +pnpm run deploy
- ✅ Pre-build Validation: Ensures code quality before expensive build operations
- ✅ Better Caching: Per-target caching for binary builds
- ✅ Simplified Asset Prep: Uses
findinstead of complex loop - ✅ Cleaner Structure: Removed verbose comments, organized logically
- Before: ~15-20 minutes (no validation, potential failures late)
- After: ~12-15 minutes (early validation prevents wasted builds)
- Improvement: Faster failure detection, ~20% reduction in failed build time
Trigger: Push to main, Manual dispatch
- Version Bump - Automatically analyze commits and bump version, or manually specify bump type
- Trigger Release - Optionally trigger release workflow (if requested via manual dispatch)
- ✅ Automatic Detection: Uses conventional commits to determine version bump type
- ✅ Manual Override: Can manually specify patch/minor/major bump
- ✅ Changelog Generation: Automatically generates changelog entries from commits
- ✅ PR-Based: Creates pull request with version changes for review
- ✅ Skip Logic: Skips if
[skip ci]or[skip version]in commit message
feat:→ minor bumpfix:→ patch bumpperf:→ patch bumpfeat!:orBREAKING CHANGE:→ major bump
- Consolidated: Merged
auto-version-bump.ymlandversion-bump.ymlinto single workflow - Simplified: Single workflow handles both automatic and manual triggers
- Improved: Better error handling and verification steps
Trigger: PR closed (for version bump PRs only)
- Create Tag - Creates release tag when version bump PR is merged
- ✅ Automatic Tagging: Creates
v<version>tag when version bump PR is merged - ✅ Idempotent: Checks if tag exists before creating
- ✅ Cleanup: Deletes version bump branch after tagging
- ✅ Release Trigger: Tag automatically triggers release workflow
All workflows now use an improved caching strategy:
key: deno-${{ runner.os }}-${{ hashFiles('deno.json', 'deno.lock') }}
restore-keys: |
deno-${{ runner.os }}-This ensures:
- Cache is invalidated when dependencies change
- Fallback to OS-specific cache if exact match not found
- Faster dependency installation
DENO_VERSION: '2.x'- Deno version used across all workflows
CLOUDFLARE_API_TOKEN- For Cloudflare deployments (optional)CLOUDFLARE_ACCOUNT_ID- For Cloudflare deployments (optional)
ENABLE_CLOUDFLARE_DEPLOY- Repository variable to enable/disable Cloudflare deployments
All workflows use minimal permissions following the principle of least privilege:
contents: read- For checking out codeid-token: write- For JSR publishing (publish job only)security-events: write- For uploading security scan results (security job only)
contents: write- For creating releases and tagspackages: write- For publishing Docker images
contents: write- For committing version changesactions: write- For triggering release workflow
All workflows use concurrency groups to prevent multiple runs on the same ref:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: trueThis ensures:
- Only one workflow runs per branch/PR at a time
- Outdated runs are automatically cancelled when new commits are pushed
- Saves CI minutes and prevents race conditions
- CI: Automatically runs on every push/PR - no manual intervention needed
- Version Bump: Run manually when you want to bump the version
- Release: Automatically triggered by version tags, or run manually for specific versions
- Make your changes on a feature branch
- Create a PR and wait for CI to pass
- Merge to main
- Version bump workflow automatically runs and creates a version bump PR
- Review and merge the version bump PR
- Create version tag workflow automatically creates the release tag
- Release workflow automatically builds and publishes the release
Or for manual version bump:
- Make your changes on a feature branch
- Create a PR and wait for CI to pass
- Merge to main
- Run "Version Bump" workflow manually with desired bump type
- Optionally check "Create a release after bumping" to skip the PR review step
This is expected and not an error. The workflow treats this as success to allow re-running the workflow.
Check that ENABLE_CLOUDFLARE_DEPLOY repository variable is set to 'true' (as a string).
The ARM64 Linux build uses cross-compilation. If it fails, check Deno's compatibility with the target platform in the Deno release notes.
If you're migrating from the old workflows:
- Version bump no longer runs automatically on PR open
- Example files are no longer automatically updated during version bump
- Deploy jobs now combined into single job
- All existing secrets and variables work the same way
- Workflow dispatch inputs are backwards compatible
- Release process is unchanged
Potential areas for further optimization:
- Add workflow to automatically create PRs for dependency updates
- Add scheduled security scanning (weekly)
- Consider splitting test job by test type (unit vs integration)
- Add benchmark tracking over time
- Add automatic changelog generation
- Add path-based filtering to skip frontend-build on backend-only PRs (currently blocked by verify-deploy's artifact dependency)