GitHub Actions (GHA) - Featurevisor
Featurevisor

Integrations

GitHub Actions

Two GitHub Actions workflows run your project: one checks every branch, and one builds and publishes the datafiles when a change reaches main. With both in place, merging a pull request is how a change is released.

Create a project

If you do not have one yet:

Commands
mkdir my-featurevisor-project && cd my-featurevisor-project
npx @featurevisor/cli@latest init
npm install

Add a .nvmrc file containing the Node.js version used by the project:

.nvmrc
24

Checks

This workflow runs for pull requests and for pushes to any branch but main or master, so problems show up before a merge:

.github/workflows/checks.yml
name: Checks
on:
pull_request:
push:
branches-ignore:
- main
- master
permissions:
contents: read
jobs:
ci:
name: Checks
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
with:
node-version-file: .nvmrc
cache: npm
- name: Install dependencies
run: npm ci
- name: Lint
run: npx featurevisor lint
- name: Test specs
run: npx featurevisor test
- name: Build
run: npx featurevisor build

Make this workflow a required status check in your branch protection rules, so a pull request cannot merge until lint, tests and the build pass.

Publish

This workflow runs on every push to main or master. It checks again, builds, commits the state files and uploads the datafiles, in the order Deployment explains:

.github/workflows/publish.yml
name: Publish
on:
push:
branches:
- main
- master
permissions:
contents: write
concurrency:
group: featurevisor-publish
cancel-in-progress: false
jobs:
ci:
name: Publish
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v7
with:
ref: ${{ github.ref_name }}
- uses: actions/setup-node@v7
with:
node-version-file: .nvmrc
cache: npm
- name: Install dependencies
run: npm ci
- name: Lint
run: npx featurevisor lint
- name: Test specs
run: npx featurevisor test
- name: Build
run: npx featurevisor build
- name: Git configs
run: |
git config user.name "${{ github.actor }}"
git config user.email "${{ github.actor }}@users.noreply.github.com"
- name: Push back to origin
run: |
git add -A .featurevisor
if ! git diff --cached --quiet; then
git commit -m "[skip ci] Revision $(cat .featurevisor/REVISION)"
fi
git push origin "HEAD:${{ github.ref_name }}"
- name: Upload datafiles
run: echo "Uploading..."
# Replace this with your CDN upload command for the datafiles directory.

Replace the last step with your host's upload command. GitHub Pages and Cloudflare Pages show complete ones.

  • If the push is rejected because another merge landed first, run the workflow again from the latest main. Never force push.
  • If the upload fails after the state was pushed, keep that state and run the upload again.
  • The checks workflow only reads. The publish workflow asks for contents: write to push the state, and your organization must allow workflows to ask for it.

Sequential builds

Two publish runs at once would start from the same state, so the concurrency group runs them one at a time:

  • Use the same group in every workflow that writes state, and publish from one branch. Each run checks out that branch only once its turn comes.
  • The group does not stop people pushing, and does not promise that a run builds the very latest commit.
  • GitHub keeps one waiting run per group, and a newer one replaces it, even with cancel-in-progress: false. Several quick merges can be published by one run. See GitHub's concurrency reference.
  • Branch protection and rulesets must allow the workflow's token to push the state commit. contents: write alone does not get past them.
Previous
Datasource