Skip to content

Latest commit

 

History

History
259 lines (209 loc) · 8.16 KB

github-action.md

File metadata and controls

259 lines (209 loc) · 8.16 KB
title GitHub Action
section Integrations
order 1

Run SpecSync in CI with zero setup. Auto-detects OS/arch, downloads the binary, runs validation.


Basic Usage

- uses: CorvidLabs/spec-sync@v6.1.2
  with:
    version: '6.1.2'
    strict: 'true'
    require-coverage: '100'

The stable GitHub 6.1.2 binary is published. The immutable @v6.1.2 examples explicitly select it because that tag's embedded default remains 6.1.1.

Inputs

Input Default Description
version 6.1.2 Release version to download. Pin an exact release for gates; latest follows the newest release and can change underneath you. The published @v6.0.0 Action tag still defaults to 6.0.0-rc.14; always pass version: '6.0.0' when using that tag.
download-base-url '' Optional trusted release mirror URL for enterprise mirrors and release validation
strict false Treat warnings as errors
require-coverage 0 Minimum file coverage % (0–100)
root . Project root directory
args '' Extra whitespace-separated CLI arguments passed to specsync check; shell quoting is not supported
lifecycle-enforce false Run lifecycle enforcement after the strict spec check
require-archived false Run the archive gate first. Fails before downloading or running anything when an SDD change under .specsync/changes/ is still open. Repositories without .specsync/changes/ pass. Needs python3 on the runner
archive-gate-only false Run only the archive gate (implies require-archived) and skip the download, spec check and comment. Use it in a first job that every other job needs:
comment false Post spec drift results as a PR comment. Requires pull_request event and write permissions
token ${{ github.token }} GitHub token for posting PR comments. Override if using a PAT for cross-repo access

Full Workflow

name: Spec Check
on: [push, pull_request]

jobs:
  specsync:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
        with:
          fetch-depth: 0
      - uses: CorvidLabs/spec-sync@v6.1.2
        with:
          version: '6.1.2'
          strict: 'true'
          require-coverage: '100'

Release archives and their .sha256 files are both fetched from the selected source. A missing or mismatched checksum fails before extraction. Treat download-base-url as a trust boundary and configure it only with an organization-controlled mirror.

Pin both the Action ref and its binary version. Candidate YAML examples pin @v6.1.2 with version: '6.1.2'. This separately verified main wrapper defaults to the published 6.1.2 binary; the immutable @v6.1.2 tag retains default 6.1.1.

- uses: CorvidLabs/spec-sync@v6.1.2
  with:
    version: '6.1.2'
    strict: 'true'

Always pass version: '6.0.0' with @v6.0.0. That tag's composite Action still embeds default 6.0.0-rc.14 (the last RC with assets when the tag was cut). Omitting version on that tag downloads the RC binary. Immutable @v6.1.2 retains default 6.1.1; explicitly pass version: '6.1.2' with it for the new stable binary. This later main wrapper defaults to 6.1.2 after actual stable asset and supported-platform Action checks. Floating @v6 advances only after consumer checks of this exact wrapper commit. Neither immutable @v6.1.2 nor @v6.0.0 is retargeted.


Archive Gate: Nothing Runs Until Every Change Is Archived

Every SDD change must be archived (specsync change ship) before a pull request merges. The archive gate makes that the first thing CI checks: one cheap job runs the gate, and every other job depends on it, so a commit with an open change under .specsync/changes/ stops in seconds and nothing else runs.

name: CI
on: [push, pull_request]

jobs:
  archive:
    name: Archive
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
        with:
          ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
      # The archive gate inputs are newer than v6.1.1, which ignores them. 6.1.2 is the
      # first release that includes them.
      - uses: CorvidLabs/spec-sync@v6.1.2
        with:
          version: '6.1.2'
          archive-gate-only: 'true'

  specsync:
    needs: archive
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
        with:
          fetch-depth: 0
      - uses: CorvidLabs/spec-sync@v6.1.2
        with:
          version: '6.1.2'
          strict: 'true'
          require-coverage: '100'

  test:
    needs: archive
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - run: echo "your tests"

Make a job that depends on everything the required status check. GitHub treats a skipped job as passing, so a required check on a job that archive skipped would let the pull request merge. Use an aggregate job with if: always() that fails unless archive and the others succeeded.

The gate needs no SpecSync binary. It prints the same sentence as the Archive check, naming the change to archive first and the command to run (for example specsync change ship <id>). The step also sets the archived output to true or false.

To gate a single job instead, add require-archived: 'true' to an ordinary invocation. The gate then runs before the download and the spec check.

The @v6.1.1 and earlier tags predate these inputs. On those tags GitHub warns about an unexpected input and skips nothing, so archive-gate-only would pass without gating anything. Use @v6.1.2 or later.

With the gate in place, the lifecycle runs locally up to ship: change check <id> --commit, fledge lanes run verify, change review, then change ship. Push the archived tip, and CI runs the full lane on it.


PR Comments

Post spec drift results directly on pull requests. SpecSync runs specsync comment and posts (or updates) a check-summary comment.

name: Spec Check
on:
  pull_request:
    types: [opened, synchronize]

jobs:
  specsync:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
    steps:
      - uses: actions/checkout@v5
        with:
          fetch-depth: 0
      - uses: CorvidLabs/spec-sync@v6.1.2
        with:
          version: '6.1.2'
          strict: 'true'
          comment: 'true'

How it works:

  • Runs specsync check --force (always validates all specs — the hash cache is not committed to git)
  • If comment: 'true', also runs specsync comment
  • Posts the markdown output as a PR comment (or updates an existing SpecSync comment)
  • Requires pull-requests: write permission and the pull_request event trigger

Custom token (e.g., for private registries or cross-repo refs):

- uses: CorvidLabs/spec-sync@v6.1.2
  with:
    version: '6.1.2'
    comment: 'true'
    token: ${{ secrets.MY_PAT }}

Multi-Platform Matrix

jobs:
  specsync:
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest]
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v5
        with:
          fetch-depth: 0
      - uses: CorvidLabs/spec-sync@v6.1.2
        with:
          version: '6.1.2'
          strict: 'true'

Monorepo

- uses: CorvidLabs/spec-sync@v6.1.2
  with:
    version: '6.1.2'
    root: './packages/backend'
    strict: 'true'

Manual CI (without the action)

- name: Install specsync
  run: |
    curl -sL https://github.com/CorvidLabs/spec-sync/releases/download/v6.1.2/specsync-linux-x86_64.tar.gz | tar xz
    sudo mv specsync-linux-x86_64 /usr/local/bin/specsync

- name: Spec check
  run: specsync check --strict --require-coverage 100

Available Binaries

Platform Binary
Linux x86_64 specsync-linux-x86_64
Linux x86_64 (static musl, any distro) specsync-linux-x86_64-musl
Linux aarch64 specsync-linux-aarch64
macOS x86_64 specsync-macos-x86_64
macOS aarch64 (Apple Silicon) specsync-macos-aarch64

Windows is not a supported target as of 6.0 — no Windows binary is published. Run SpecSync under WSL, or build it from source with cargo install specsync.