Skip to content

Repository files navigation

voidflow

Semi-opinionated GitHub Actions workflows for my personal sites and consultancy shop RavenFlight Industries, LLC

Usage

Point uses in your configuration to a workflow, e.g. in your .github/workflows/ci.yml

name: CI
on:
  pull_request:
    branches: [main, next, live]
    types: [opened, synchronize, reopened, ready_for_review]
  workflow_dispatch:

jobs:
  validate:
    uses: taraxvoid/voidflow/.github/workflows/site-ci.yml@main

Non-GitHub / self-hosted runners

Pass runner (defaults to GitHub runner ubuntu-latest)

jobs:
  validate:
    uses: taraxvoid/voidflow/.github/workflows/site-ci.yml@main
    with:
      runner: my-hosted-runner

Workflow Types

Validation / Checks

Runs lint, typecheck, check for GPL licenses, e2e with Playwright

Unlighthouse (performance / SEO budgets)

site-ci.yml runs bun run test:e2e:lighthouse on PRs into live. Sites implement that script with the shared runner here, which serves the built static directory on a free port and runs Unlighthouse against it, reusing Playwright's Chromium. It exits non-zero if a category budget in the site's config fails.

In the site's package.json (pin the tag):

"test:e2e:lighthouse": "bun run build && bunx --package @taraxvoid/voidflow@0.6.0 unlighthouse-runner --dir dist"

Options: --dir (default dist, use dist/client for Cloudflare adapter builds), --config (default unlighthouse.config.ts), --version (pinned Unlighthouse version). Start from scripts/unlighthouse/unlighthouse.config.example.ts and add .unlighthouse/ to the site's .gitignore.

Playwright preview config

Shared playwright.config for Astro sites that run e2e against astro preview. It picks a free port outside CI, sets ASTRO_PREVIEW_BACKGROUND=false (Astro backgrounds preview in agent environments, which makes Playwright think the server exited), and drops the webServer when PLAYWRIGHT_BASE_URL is set.

bun add -d @taraxvoid/voidflow   # or: pnpm add -D @taraxvoid/voidflow
// playwright.config.js
import { definePreviewConfig } from '@taraxvoid/voidflow/playwright'

export default definePreviewConfig({ ciPort: 4141 })

The same release is also published unscoped as voidflow (identical contents and version), so bun add -d voidflow and import ... from 'voidflow/playwright' work too. @taraxvoid/voidflow is the canonical name.

Options: ciPort (required in CI), runner (default bun, e.g. pnpm), timeout (default 30000), projects (default Pixel 7 and Desktop Chrome), testDir (default ./test/e2e). Requires @playwright/test in the site.

Deployments

Example deployment job added to your workflow above. resolve-env maps the branch to dev/staging/prod once, up front, so its output can be used both to drive the deploy and to label the job (Deploy [dev], Deploy [staging], Deploy [prod]) — a job's name: can reference needs.<job>.outputs.* but not a step output from within itself, hence the split:

jobs:
  resolve-env:
    needs: validate
    if: github.event_name == 'push'
    uses: taraxvoid/voidflow/.github/workflows/resolve-env.yml@main

  deploy:
    name: Deploy [${{ needs.resolve-env.outputs.env }}]
    needs: resolve-env
    if: github.event_name == 'push'
    environment: ${{ needs.resolve-env.outputs.env }}
    steps:
      - uses: actions/checkout@v7.0.1
      - uses: taraxvoid/voidflow/actions/cloudflare-deploy@main
        with:
          env: ${{ needs.resolve-env.outputs.env }}
          cloudflare-api-token: ${{ secrets.CLOUDFLARE_API_TOKEN }}

Versioning

This project uses semver, released with release-please (release-please.yml). It keeps a standing chore(release): X.Y.Z PR open against main, updated as commits land. Merging it bumps package.json and CHANGELOG.md, tags vX.Y.Z, creates the GitHub release, and publishes to npm. The PR is opened with the org's release-bot GitHub App token (RELEASE_BOT_CLIENT_ID / RELEASE_BOT_APP_PRIVATE_KEY) so CI runs on it.

Commit messages should follow Conventional Commits — enforced loosely, as an advisory commit-msg hint (see scripts/check-commit-msg.sh), not a blocking check. They drive the version bump and generated changelog.

Treat @main as unstable. Consumers should pin to an exact release tag, e.g. @v0.3.0 — there is no floating major-version tag (@v1) to track yet.

Self-validation

This repo validates its own workflows and composite actions (.github/workflows/ci.yml):

  • actionlint — workflow schema/logic; also shellchecks run: steps in .github/workflows/*.yml automatically (shellcheck ships on ubuntu-latest)
  • check-jsonschema — schema-checks actions/**/action.yml and the workflow files against SchemaStore's github-action.json / github-workflow.json
  • shellcheck (scripts/shellcheck-actions.sh) — checks run: steps inside actions/**/action.yml, which actionlint doesn't reach
  • zizmor — security audit (unpinned refs, script injection via ${{ }} in run:, excess permissions, etc.)

Local dev setup

brew install just lefthook actionlint shellcheck yq act uv
lefthook install
  • just validate — run everything CI runs, locally
  • just lint-workflows / lint-actions / lint-shell / security — run one check at a time
  • just dry-run — full local run of ci.yml via act (needs Docker running); pass extra args, e.g. just dry-run -j validation
  • lefthook runs the fast checks (lint-workflows, lint-actions, lint-shell) on pre-commit, and zizmor on pre-push

Colima users: .actrc already disables the docker-socket mount (--container-daemon-socket -) — act binds /var/run/docker.sock by default, which doesn't exist under Colima and fails with operation not supported. None of these workflow steps need docker-in-docker, so this is safe.

Run just dry-run from a normal checkout, not a linked git worktree. act copies the working tree via docker cp rather than a real clone, so a worktree's .git pointer back to the parent repo doesn't resolve inside the container — git ls-files-based steps (schema validation, scripts/shellcheck-actions.sh) silently see zero files instead of erroring. Verified clean end-to-end (🏁 Job succeeded) from a plain clone.

YMMV, caveat emptor, your satisfaction not guaranteed

Releases

Contributors

Languages