Skip to content

GitHub Action

Coming soon. reflow-io/reflow-action@v1 is the launch target. The public Action repository has not been published yet.

The Action runs flows against pull-request previews and reports the result as GitHub checks plus one sticky PR comment. On a default-branch push, it syncs which configured flow files are present in the repository.

name: Reflow
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
checks: write
pull-requests: write
jobs:
reflow:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: reflow-io/reflow-action@v1
with:
api-token: ${{ secrets.REFLOW_API_TOKEN }} # PAT with run scope
target-url: ${{ steps.preview.outputs.url }}
github-token: ${{ github.token }}

Available personal access token scopes are admin, run, and read. CI only needs run. The GitHub token needs checks: write and pull-requests: write for reporting.

target-url is required in pull-request mode and ignored during push-mode presence sync. Flow selection, check mode, and optional DAG behavior can come from .reflow/config.yml; Action inputs override the corresponding settings.

InputContract
api-tokenRequired Reflow PAT. Use the run scope for CI.
target-urlRequired in pull-request mode; the deployed preview origin to test.
api-urlReflow API origin. Defaults to https://app.reflow.io.
flowsFlow paths or single-directory *.md globs, separated by commas or newlines.
browserchromium, firefox, or webkit.
github-tokenToken used for the PR comment and check runs; defaults to GITHUB_TOKEN.
checksrollup or per-flow; defaults to rollup.
dashboard-urlLink target for View runs in the PR comment.
timeout-minutesRollup wait before cancellation. Defaults to 20.
dag-modetrue or false; overrides the config file’s dag value.

The supported .reflow/config.yml keys are flows, target_url, checks, dag, and always_run. Pull-request mode still requires the target-url Action input.

flows:
- .reflow/flows/*.md
target_url: https://preview.example.com
checks: per-flow
dag: true
always_run:
- pnpm-lock.yaml
- .github/workflows/**
  1. Resolve flow files from the flows input, .reflow/config.yml, or .reflow/flows/.
  2. Submit an idempotent rollup for the repository, PR number, and head SHA, then poll until every run is terminal.
  3. Post one rollup check by default, or one check per flow with checks: per-flow. Create or update one PR comment containing each flow’s status and summary.
  4. Exit non-zero unless the rollup succeeds. A timeout requests cancellation from Reflow before exiting.

For changed-file DAG selection, keep full git history with actions/checkout’s fetch-depth: 0. If the base commit is unavailable, the Action safely runs every flow instead of selecting from an incomplete diff.

Set dag: true in .reflow/config.yml or pass dag-mode: true. Each flow’s needs lists upstream flow slugs, and covers lists the repository paths it exercises:

# .reflow/flows/add-todo.md frontmatter
needs:
- create-account
covers:
- src/todos/**
- src/components/TodoList.tsx

Reflow runs upstreams before their dependents. Files changed since the PR’s base commit taint matching flows; downstream flows are also affected when an upstream is affected. An unchanged flow reuses its last green result. A changed path matching an always_run pattern forces every flow to run.

Use capture to pass a value from a successful upstream flow:

### Capture the new account
```rfl
capture account_email = text of testid=account-email
```

The dependent flow reads it with the upstream slug and output name:

fill label="Email" ${needs.create-account.outputs.account_email}

If Git cannot produce a complete base-to-head diff, the Action falls back to a full run. This is why DAG workflows should keep fetch-depth: 0 on actions/checkout.

On a push, the Action compares the pushed ref with the repository’s default branch. A default-branch push sends Reflow the configured flow paths that still exist; another branch exits successfully without syncing. This mode needs no preview URL or GitHub write token.

Use a concurrency guard so a newer PR update stops the stale workflow job:

concurrency:
group: reflow-pr-${{ github.event.pull_request.number }}
cancel-in-progress: true

The current Action explicitly cancels the Reflow rollup when its own polling timeout expires. GitHub cancelling the workflow process does not yet send that explicit cancellation request, so the remote run may still settle normally.