@ferrflow/doc 7.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs-en/ci/github-actions.md +120 -0
- package/docs-en/ci/gitlab-ci.md +90 -0
- package/docs-en/ci/hosted-bot.md +82 -0
- package/docs-en/ci/pipeline-triggers.md +287 -0
- package/docs-en/configuration/config-file.md +1259 -0
- package/docs-en/configuration/formats.md +220 -0
- package/docs-en/configuration/monorepo.md +390 -0
- package/docs-en/installation.md +56 -0
- package/docs-en/introduction.md +56 -0
- package/docs-en/quickstart.md +66 -0
- package/docs-en/reference/api.md +106 -0
- package/docs-en/reference/cli.md +483 -0
- package/docs-en/reference/conventional-commits.md +103 -0
- package/docs-en/reference/errors.md +508 -0
- package/docs-en/verifying-releases.md +97 -0
- package/docs-fr/ci/github-actions.md +109 -0
- package/docs-fr/ci/gitlab-ci.md +77 -0
- package/docs-fr/ci/hosted-bot.md +82 -0
- package/docs-fr/ci/pipeline-triggers.md +238 -0
- package/docs-fr/configuration/config-file.md +839 -0
- package/docs-fr/configuration/formats.md +163 -0
- package/docs-fr/configuration/monorepo.md +357 -0
- package/docs-fr/installation.md +56 -0
- package/docs-fr/introduction.md +54 -0
- package/docs-fr/quickstart.md +63 -0
- package/docs-fr/reference/api.md +106 -0
- package/docs-fr/reference/cli.md +407 -0
- package/docs-fr/reference/conventional-commits.md +103 -0
- package/docs-fr/reference/errors.md +378 -0
- package/docs-fr/verifying-releases.md +97 -0
- package/docs-fr-v4/ci/github-actions.md +106 -0
- package/docs-fr-v4/ci/gitlab-ci.md +77 -0
- package/docs-fr-v4/ci/pipeline-triggers.md +214 -0
- package/docs-fr-v4/configuration/config-file.md +769 -0
- package/docs-fr-v4/configuration/formats.md +128 -0
- package/docs-fr-v4/configuration/monorepo.md +324 -0
- package/docs-fr-v4/installation.md +48 -0
- package/docs-fr-v4/introduction.md +54 -0
- package/docs-fr-v4/legal/telemetry.md +65 -0
- package/docs-fr-v4/quickstart.md +63 -0
- package/docs-fr-v4/reference/cli.md +130 -0
- package/docs-fr-v4/reference/conventional-commits.md +67 -0
- package/docs-fr-v4/reference/errors.md +372 -0
- package/docs-fr-v5/ci/github-actions.md +109 -0
- package/docs-fr-v5/ci/gitlab-ci.md +77 -0
- package/docs-fr-v5/ci/hosted-bot.md +82 -0
- package/docs-fr-v5/ci/pipeline-triggers.md +238 -0
- package/docs-fr-v5/configuration/config-file.md +812 -0
- package/docs-fr-v5/configuration/formats.md +150 -0
- package/docs-fr-v5/configuration/monorepo.md +357 -0
- package/docs-fr-v5/installation.md +56 -0
- package/docs-fr-v5/introduction.md +54 -0
- package/docs-fr-v5/legal/telemetry.md +26 -0
- package/docs-fr-v5/quickstart.md +63 -0
- package/docs-fr-v5/reference/api.md +106 -0
- package/docs-fr-v5/reference/cli.md +356 -0
- package/docs-fr-v5/reference/conventional-commits.md +88 -0
- package/docs-fr-v5/reference/errors.md +378 -0
- package/docs-fr-v5/verifying-releases.md +97 -0
- package/docs-fr-v6/ci/github-actions.md +109 -0
- package/docs-fr-v6/ci/gitlab-ci.md +77 -0
- package/docs-fr-v6/ci/hosted-bot.md +82 -0
- package/docs-fr-v6/ci/pipeline-triggers.md +238 -0
- package/docs-fr-v6/configuration/config-file.md +813 -0
- package/docs-fr-v6/configuration/formats.md +150 -0
- package/docs-fr-v6/configuration/monorepo.md +357 -0
- package/docs-fr-v6/installation.md +56 -0
- package/docs-fr-v6/introduction.md +54 -0
- package/docs-fr-v6/quickstart.md +63 -0
- package/docs-fr-v6/reference/api.md +106 -0
- package/docs-fr-v6/reference/cli.md +356 -0
- package/docs-fr-v6/reference/conventional-commits.md +88 -0
- package/docs-fr-v6/reference/errors.md +378 -0
- package/docs-fr-v6/verifying-releases.md +97 -0
- package/docs-v0/ci/github-actions.md +77 -0
- package/docs-v0/ci/gitlab-ci.md +59 -0
- package/docs-v0/configuration/config-file.md +97 -0
- package/docs-v0/configuration/formats.md +86 -0
- package/docs-v0/configuration/monorepo.md +59 -0
- package/docs-v0/installation.md +48 -0
- package/docs-v0/introduction.md +34 -0
- package/docs-v0/legal/telemetry.md +63 -0
- package/docs-v0/quickstart.md +58 -0
- package/docs-v0/reference/cli.md +95 -0
- package/docs-v0/reference/conventional-commits.md +68 -0
- package/docs-v1/ci/github-actions.md +76 -0
- package/docs-v1/ci/gitlab-ci.md +58 -0
- package/docs-v1/configuration/config-file.md +515 -0
- package/docs-v1/configuration/formats.md +115 -0
- package/docs-v1/configuration/monorepo.md +246 -0
- package/docs-v1/installation.md +48 -0
- package/docs-v1/introduction.md +39 -0
- package/docs-v1/legal/telemetry.md +63 -0
- package/docs-v1/quickstart.md +62 -0
- package/docs-v1/reference/cli.md +128 -0
- package/docs-v1/reference/conventional-commits.md +67 -0
- package/docs-v2/ci/github-actions.md +117 -0
- package/docs-v2/ci/gitlab-ci.md +90 -0
- package/docs-v2/ci/pipeline-triggers.md +263 -0
- package/docs-v2/configuration/config-file.md +806 -0
- package/docs-v2/configuration/formats.md +98 -0
- package/docs-v2/configuration/monorepo.md +324 -0
- package/docs-v2/installation.md +48 -0
- package/docs-v2/introduction.md +40 -0
- package/docs-v2/legal/telemetry.md +66 -0
- package/docs-v2/quickstart.md +63 -0
- package/docs-v2/reference/cli.md +130 -0
- package/docs-v2/reference/conventional-commits.md +67 -0
- package/docs-v2/reference/errors.md +500 -0
- package/docs-v2/self-hosting.md +101 -0
- package/docs-v3/ci/github-actions.md +117 -0
- package/docs-v3/ci/gitlab-ci.md +90 -0
- package/docs-v3/ci/pipeline-triggers.md +263 -0
- package/docs-v3/configuration/config-file.md +806 -0
- package/docs-v3/configuration/formats.md +99 -0
- package/docs-v3/configuration/monorepo.md +324 -0
- package/docs-v3/installation.md +48 -0
- package/docs-v3/introduction.md +40 -0
- package/docs-v3/legal/telemetry.md +66 -0
- package/docs-v3/quickstart.md +66 -0
- package/docs-v3/reference/cli.md +161 -0
- package/docs-v3/reference/conventional-commits.md +67 -0
- package/docs-v3/reference/errors.md +502 -0
- package/docs-v3/self-hosting.md +137 -0
- package/docs-v4/ci/github-actions.md +117 -0
- package/docs-v4/ci/gitlab-ci.md +90 -0
- package/docs-v4/ci/pipeline-triggers.md +263 -0
- package/docs-v4/configuration/config-file.md +850 -0
- package/docs-v4/configuration/formats.md +182 -0
- package/docs-v4/configuration/monorepo.md +324 -0
- package/docs-v4/installation.md +48 -0
- package/docs-v4/introduction.md +56 -0
- package/docs-v4/legal/telemetry.md +65 -0
- package/docs-v4/quickstart.md +66 -0
- package/docs-v4/reference/cli.md +161 -0
- package/docs-v4/reference/conventional-commits.md +67 -0
- package/docs-v4/reference/errors.md +502 -0
- package/docs-v4/self-hosting.md +137 -0
- package/docs-v5/ci/github-actions.md +120 -0
- package/docs-v5/ci/gitlab-ci.md +90 -0
- package/docs-v5/ci/hosted-bot.md +82 -0
- package/docs-v5/ci/pipeline-triggers.md +287 -0
- package/docs-v5/configuration/config-file.md +1133 -0
- package/docs-v5/configuration/formats.md +206 -0
- package/docs-v5/configuration/monorepo.md +390 -0
- package/docs-v5/installation.md +56 -0
- package/docs-v5/introduction.md +56 -0
- package/docs-v5/legal/telemetry.md +26 -0
- package/docs-v5/quickstart.md +66 -0
- package/docs-v5/reference/api.md +106 -0
- package/docs-v5/reference/cli.md +431 -0
- package/docs-v5/reference/conventional-commits.md +88 -0
- package/docs-v5/reference/errors.md +508 -0
- package/docs-v5/verifying-releases.md +97 -0
- package/docs-v6/ci/github-actions.md +120 -0
- package/docs-v6/ci/gitlab-ci.md +90 -0
- package/docs-v6/ci/hosted-bot.md +82 -0
- package/docs-v6/ci/pipeline-triggers.md +287 -0
- package/docs-v6/configuration/config-file.md +1134 -0
- package/docs-v6/configuration/formats.md +206 -0
- package/docs-v6/configuration/monorepo.md +390 -0
- package/docs-v6/installation.md +56 -0
- package/docs-v6/introduction.md +56 -0
- package/docs-v6/quickstart.md +66 -0
- package/docs-v6/reference/api.md +106 -0
- package/docs-v6/reference/cli.md +431 -0
- package/docs-v6/reference/conventional-commits.md +88 -0
- package/docs-v6/reference/errors.md +508 -0
- package/docs-v6/verifying-releases.md +97 -0
- package/package.json +17 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Introduction
|
|
3
|
+
description: What FerrFlow is and why it exists.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
FerrFlow is a single binary that automates semantic versioning for any repository — monorepo or classic, any language.
|
|
7
|
+
|
|
8
|
+
It reads your commit history, determines the right version bump, updates your version files, writes a changelog, creates a git tag, and publishes a release. Zero runtime dependencies.
|
|
9
|
+
|
|
10
|
+
<div class="ferr-card-group" data-cols="2">
|
|
11
|
+
<div class="ferr-card"><p class="ferr-card__title">CLI-first</p><div class="ferr-card__body"><p>Everything happens from your terminal or your CI. No UI to click, no config server to babysit.</p>
|
|
12
|
+
</div></div>
|
|
13
|
+
<div class="ferr-card"><p class="ferr-card__title">Multi-forge</p><div class="ferr-card__body"><p>GitHub, GitLab, self-hosted — FerrFlow adapts to your forge. One tool, any platform.</p>
|
|
14
|
+
</div></div>
|
|
15
|
+
<div class="ferr-card"><p class="ferr-card__title">Conventional commits</p><div class="ferr-card__body"><p>Reads commit history to determine version bumps automatically. No manual changelog maintenance.</p>
|
|
16
|
+
</div></div>
|
|
17
|
+
<div class="ferr-card"><p class="ferr-card__title">Zero infra</p><div class="ferr-card__body"><p>A single binary with no daemon, no server, no database. Runs wherever your CI runs.</p>
|
|
18
|
+
</div></div>
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
## Why not semantic-release or changesets?
|
|
22
|
+
|
|
23
|
+
Most versioning tools are coupled to a specific ecosystem or require Node.js to be present in your CI.
|
|
24
|
+
|
|
25
|
+
| Tool | Monorepo | Multi-language | Runtime |
|
|
26
|
+
| ---------------- | ----------- | -------------- | -------- |
|
|
27
|
+
| semantic-release | via plugins | JS/Node only | Node.js |
|
|
28
|
+
| changesets | manual bump | JS only | Node.js |
|
|
29
|
+
| release-please | limited | partial | Node.js |
|
|
30
|
+
| cargo-release | no | Rust only | Rust |
|
|
31
|
+
| **FerrFlow** | **native** | **any** | **none** |
|
|
32
|
+
|
|
33
|
+
FerrFlow ships as a compiled binary. Drop it in any CI environment without installing a runtime. A WASM build (`@ferrflow/wasm`) is also available for browser-side usage.
|
|
34
|
+
|
|
35
|
+
For side-by-side latency, peak memory and install size against the JS ecosystem release tools, see [Performance](/performance) — numbers refresh on every FerrFlow release.
|
|
36
|
+
|
|
37
|
+
<aside class="ferr-aside ferr-aside--note"><p class="ferr-aside__title">Heads up</p><div class="ferr-aside__body"><p>FerrFlow is versioning only. Issue tracking, secrets, and AI agents live in separate FerrLabs products.</p>
|
|
38
|
+
</div></aside>
|
|
39
|
+
|
|
40
|
+
## How it works
|
|
41
|
+
|
|
42
|
+
1. **Reads commits** since the last git tag for each package
|
|
43
|
+
2. **Determines the bump** from [Conventional Commits](/docs/reference/conventional-commits) (`feat` → minor, `fix` → patch, breaking → major)
|
|
44
|
+
3. **Updates version files** — `Cargo.toml`, `package.json`, `pom.xml`, etc.
|
|
45
|
+
4. **Writes the changelog** in Keep a Changelog format
|
|
46
|
+
5. **Creates a git tag** (`api@v1.2.0`) and pushes
|
|
47
|
+
6. **Publishes a GitHub/GitLab release** with the changelog as release notes
|
|
48
|
+
|
|
49
|
+
In a monorepo, FerrFlow only releases packages that have changed, and understands shared dependency paths.
|
|
50
|
+
|
|
51
|
+
## Key features
|
|
52
|
+
|
|
53
|
+
- **Pre/post-release hooks** — run scripts at every lifecycle stage (bump, commit, publish, failure)
|
|
54
|
+
- **Query commands** — `ferrflow version`, `ferrflow tag`, and `ferrflow status` for CI scripting, plus `ferrflow why` to explain a package's release decision
|
|
55
|
+
- **Any version file** — Cargo.toml, package.json, pom.xml, build.gradle, Chart.yaml, plain text, and more
|
|
56
|
+
- **Browser support** — `@ferrflow/wasm` brings commit parsing, bump computation, and changelog generation to the browser
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Quick start
|
|
3
|
+
description: Go from zero to your first automated release in under 5 minutes.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<ol>
|
|
7
|
+
<li><p><strong>Scaffold the config</strong></p>
|
|
8
|
+
<p>Run <code>ferrflow init</code> at the root of your repository. It detects your version files and writes a <code>.ferrflow</code> config:</p>
|
|
9
|
+
<pre><code class="language-bash">ferrflow init
|
|
10
|
+
</code></pre>
|
|
11
|
+
<p>For a Rust project this produces:</p>
|
|
12
|
+
<pre><code class="language-json">{
|
|
13
|
+
"$schema": "https://ferrflow.com/schema/ferrflow.json",
|
|
14
|
+
"workspace": {
|
|
15
|
+
"tagTemplate": "v{version}"
|
|
16
|
+
},
|
|
17
|
+
"package": [
|
|
18
|
+
{
|
|
19
|
+
"name": "my-app",
|
|
20
|
+
"path": ".",
|
|
21
|
+
"changelog": "CHANGELOG.md",
|
|
22
|
+
"versionedFiles": [
|
|
23
|
+
{ "path": "Cargo.toml", "format": "toml" }
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
</code></pre>
|
|
29
|
+
</li>
|
|
30
|
+
<li><p><strong>Preview what would happen</strong></p>
|
|
31
|
+
<p>Before touching anything, run a dry-run to see what FerrFlow would do:</p>
|
|
32
|
+
<pre><code class="language-bash">ferrflow check
|
|
33
|
+
</code></pre>
|
|
34
|
+
<p>Output:</p>
|
|
35
|
+
<pre><code>Scanning . ...
|
|
36
|
+
→ feat: add user authentication
|
|
37
|
+
→ fix: correct pagination offset
|
|
38
|
+
|
|
39
|
+
Bump my-app 0.1.0 → 0.2.0
|
|
40
|
+
Tag v0.2.0
|
|
41
|
+
</code></pre>
|
|
42
|
+
</li>
|
|
43
|
+
<li><p><strong>Run the release</strong></p>
|
|
44
|
+
<pre><code class="language-bash">ferrflow release
|
|
45
|
+
</code></pre>
|
|
46
|
+
<p>FerrFlow will:</p>
|
|
47
|
+
<ul>
|
|
48
|
+
<li>Update <code>Cargo.toml</code> to <code>0.2.0</code></li>
|
|
49
|
+
<li>Append to <code>CHANGELOG.md</code></li>
|
|
50
|
+
<li>Commit the changes</li>
|
|
51
|
+
<li>Create and push <code>v0.2.0</code></li>
|
|
52
|
+
<li>Create a GitHub release (if <code>GITHUB_TOKEN</code> is set)</li>
|
|
53
|
+
</ul>
|
|
54
|
+
</li>
|
|
55
|
+
</ol>
|
|
56
|
+
|
|
57
|
+
<aside class="ferr-aside ferr-aside--tip"><p class="ferr-aside__title">Starting from scratch</p><div class="ferr-aside__body"><p>No prior tag? FerrFlow v3 bootstraps from the strategy's zero value automatically — the first <code>feat:</code> lands at <code>0.1.0</code>, the first <code>fix:</code> at <code>0.0.1</code>. You don't need to create a <code>v0.0.0</code> tag by hand. See <a href="/docs/reference/cli#which-version-is-bumped-from">how the baseline is chosen</a>.</p>
|
|
58
|
+
</div></aside>
|
|
59
|
+
|
|
60
|
+
## Next steps
|
|
61
|
+
|
|
62
|
+
- Set up [GitHub Actions](/docs/ci/github-actions) to run releases automatically on push to `main`
|
|
63
|
+
- Configure a [monorepo](/docs/configuration/monorepo) if you have multiple packages
|
|
64
|
+
- Add [pre/post-release hooks](/docs/configuration/config-file#hooks) for custom scripts during the release lifecycle
|
|
65
|
+
- Use `ferrflow version` and `ferrflow tag` in CI scripts — see the [CLI reference](/docs/reference/cli)
|
|
66
|
+
- Review the full [config reference](/docs/configuration/config-file)
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: FerrFlow API
|
|
3
|
+
description: Hosted HTTP endpoints for FerrFlow — validate configs, preview version bumps, resolve the latest release, and fetch the config schema.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
The FerrFlow API exposes a small set of hosted HTTP endpoints under `https://api.ferrflow.com/v1/ferrflow/*`. They are backed by the same FerrFlow core the CLI runs, so `validate` and `preview` return results identical to `ferrflow validate` and `ferrflow check` — no second implementation to drift.
|
|
7
|
+
|
|
8
|
+
Every endpoint is public (no authentication) and safe to call from CI, editors, or a browser. The machine-readable contract is served at [`/v1/ferrflow/openapi.json`](https://api.ferrflow.com/v1/ferrflow/openapi.json) (OpenAPI 3.1).
|
|
9
|
+
|
|
10
|
+
`https://api.ferrlabs.com/v1/ferrflow/*` reaches the same endpoints and keeps working indefinitely — it is where the API was first published, and released CLI versions still call it. Prefer `api.ferrflow.com` in anything new.
|
|
11
|
+
|
|
12
|
+
## `GET /v1/ferrflow/health`
|
|
13
|
+
|
|
14
|
+
Liveness and version probe. Powers status dashboards.
|
|
15
|
+
|
|
16
|
+
```json
|
|
17
|
+
{ "status": "ok", "service": "ferrflow-api", "version": "10.17.0", "time": "2026-07-21T15:00:00Z" }
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## `GET /v1/ferrflow/schema`
|
|
21
|
+
|
|
22
|
+
Returns the config JSON Schema (`Content-Type: application/schema+json`), served from the schema bundled in the FerrFlow release — the same bytes the CLI validates against. Sends a strong `ETag` and `Cache-Control`, so point your editor's `$schema` here:
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{ "$schema": "https://api.ferrflow.com/v1/ferrflow/schema" }
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`GET /v1/ferrflow/schema/v{major}` returns the schema frozen at a CLI major (e.g. `/schema/v5`). Only the current major is served today; older majors return `404` until per-major snapshots land.
|
|
29
|
+
|
|
30
|
+
## `GET /v1/ferrflow/latest`
|
|
31
|
+
|
|
32
|
+
Resolves the latest FerrFlow release from GitHub, cached server-side. Pass `platform` to get a single asset:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
curl "https://api.ferrflow.com/v1/ferrflow/latest?platform=linux-x64"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"version": "5.48.0",
|
|
41
|
+
"tag": "v5.48.0",
|
|
42
|
+
"platform": "linux-x64",
|
|
43
|
+
"download_url": "https://github.com/FerrLabs/FerrFlow/releases/download/v5.48.0/ferrflow-linux-x64.tar.gz",
|
|
44
|
+
"bundle_url": "https://github.com/FerrLabs/FerrFlow/releases/download/v5.48.0/ferrflow-linux-x64.tar.gz.bundle",
|
|
45
|
+
"published_at": "2026-07-27T19:20:00Z"
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Releases are signed with [Sigstore](/verifying-releases/) — verify the `.bundle` rather than a checksum (releases up to v5.47.4 carry a `.sig` + `.crt` pair instead). Without `platform`, the response lists `assets` for every platform. Valid platforms: `linux-x64`, `linux-arm64`, `linux-arm`, `darwin-x64`, `darwin-arm64`, `win32-x64`, `win32-arm64`.
|
|
50
|
+
|
|
51
|
+
## `POST /v1/ferrflow/validate`
|
|
52
|
+
|
|
53
|
+
Validates a config without a repo — you send the config text and, optionally, the contents of the versioned files it references so the file-existence and version-consistency checks run. The result is identical to `ferrflow validate --json`.
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
curl -X POST https://api.ferrflow.com/v1/ferrflow/validate \
|
|
57
|
+
-H 'content-type: application/json' \
|
|
58
|
+
-d '{
|
|
59
|
+
"config": "{\"package\":[{\"name\":\"app\",\"path\":\".\",\"versionedFiles\":[{\"path\":\"package.json\",\"format\":\"json\"}]}]}",
|
|
60
|
+
"files": { "package.json": "{\"version\":\"1.0.0\"}" }
|
|
61
|
+
}'
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"valid": true,
|
|
67
|
+
"config_file": null,
|
|
68
|
+
"package_count": 1,
|
|
69
|
+
"errors": [],
|
|
70
|
+
"warnings": [],
|
|
71
|
+
"suggestions": []
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
An invalid config is still a successful validation: the response is `200` with `"valid": false` and the offending entries. Only a malformed request body returns `400`. The optional `format` field (`json` | `json5` | `toml`) skips format inference.
|
|
76
|
+
|
|
77
|
+
## `POST /v1/ferrflow/preview`
|
|
78
|
+
|
|
79
|
+
Computes the version bumps and changelog for an explicit list of commits — the same logic as `ferrflow check`, as a service. No repo access; you pass the commits.
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
curl -X POST https://api.ferrflow.com/v1/ferrflow/preview \
|
|
83
|
+
-H 'content-type: application/json' \
|
|
84
|
+
-d '{
|
|
85
|
+
"config": "{\"package\":[{\"name\":\"api\",\"path\":\".\"}]}",
|
|
86
|
+
"commits": [{ "message": "feat(api): add endpoint", "hash": "a1b2" }],
|
|
87
|
+
"current_versions": { "api": "1.2.3" }
|
|
88
|
+
}'
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"packages": [
|
|
94
|
+
{
|
|
95
|
+
"name": "api",
|
|
96
|
+
"current": "1.2.3",
|
|
97
|
+
"next": "1.3.0",
|
|
98
|
+
"bump": "minor",
|
|
99
|
+
"commits": [{ "hash": "a1b2", "type": "feat", "scope": "api", "breaking": false }],
|
|
100
|
+
"changelog": "### Features\n- ..."
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
In a monorepo config, each commit is assigned to a package when its `files` fall under that package's `path`. Packages with no releasable commit are omitted.
|
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: CLI commands
|
|
3
|
+
description: Full reference for all FerrFlow CLI commands and flags.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## `ferrflow release`
|
|
7
|
+
|
|
8
|
+
Run the full release pipeline: bump versions, update changelogs, commit, tag, push, and create a release.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
ferrflow release [OPTIONS]
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
| Flag | Description |
|
|
15
|
+
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
16
|
+
| `--force` | Allow floating tags to move backward to a lower version |
|
|
17
|
+
| `--force-version <VERSION>` | Force a specific version, skipping commit analysis. Format: `VERSION` (single repo) or `NAME@VERSION` (monorepo) |
|
|
18
|
+
| `--channel <NAME>` | Pre-release channel override (e.g. `beta`, `rc`, `dev`) |
|
|
19
|
+
| `--draft` | Create releases as drafts (GitHub only). A later `ferrflow release` without `--draft` detects and publishes existing drafts automatically |
|
|
20
|
+
| `--force-unlock` | Break an existing `.git/ferrflow.lock` before acquiring it. Use only when no other `ferrflow release` is running — e.g. after a crash left the lockfile behind |
|
|
21
|
+
|
|
22
|
+
**What it does:**
|
|
23
|
+
|
|
24
|
+
1. Scans commits since the last tag for each package
|
|
25
|
+
2. Determines the version bump from Conventional Commits
|
|
26
|
+
3. Updates all `versionedFiles` with the new version
|
|
27
|
+
4. Appends the new section to `CHANGELOG.md`
|
|
28
|
+
5. Creates a git commit, opens a PR, or skips (depending on `releaseCommitMode`)
|
|
29
|
+
6. Creates and pushes the git tag
|
|
30
|
+
7. Creates a GitHub/GitLab release with the changelog as notes
|
|
31
|
+
|
|
32
|
+
### Which version is bumped from
|
|
33
|
+
|
|
34
|
+
Starting with FerrFlow **v3**, the baseline for every bump is **the highest semver-valid tag** for the package (e.g. `my-pkg@v2.4.1` or `v2.4.1`), not the value in the versioned file.
|
|
35
|
+
|
|
36
|
+
The versioned file stays the canonical write target so downstream consumers (`cargo publish`, Docker builds, etc.) always see a coherent version, but it is no longer the source of truth for the bump computation. This prevents two classes of silent failure:
|
|
37
|
+
|
|
38
|
+
- **Parallel release workflows**: two pull requests merging back-to-back used to spawn two release jobs that both read the pre-release version from the file. Both computed the same next version — the second push either collided or was silently skipped. Today the second workflow sees the first workflow's freshly-pushed tag and computes the correct next version on top of it.
|
|
39
|
+
- **File/tag drift**: a revert, a merge from an old branch, or a manual edit could leave the file behind the tags. Bumping from a stale file produced tags that collided with history and the release got silently skipped with `tag X already exists, skipping`. The tag now wins; the file only wins when it is genuinely ahead (human pre-bump).
|
|
40
|
+
|
|
41
|
+
Resolution order, per package:
|
|
42
|
+
|
|
43
|
+
| Tag | File | Baseline used |
|
|
44
|
+
| ------- | ------- | ------------------------------ |
|
|
45
|
+
| present | present | `max(tag, file)` by semver |
|
|
46
|
+
| present | absent | tag |
|
|
47
|
+
| absent | present | file |
|
|
48
|
+
| absent | absent | strategy bootstrap (see below) |
|
|
49
|
+
|
|
50
|
+
### First release on a brand-new repo
|
|
51
|
+
|
|
52
|
+
When no tag exists yet _and_ the format has no version to read (notably `go.mod`, which stores the version in tags alone), FerrFlow bootstraps from the versioning strategy's zero value:
|
|
53
|
+
|
|
54
|
+
| Strategy | Bootstrap baseline |
|
|
55
|
+
| ------------------------ | ---------------------------------------- |
|
|
56
|
+
| `semver`, `zerover` | `0.0.0` |
|
|
57
|
+
| `sequential` | `0` |
|
|
58
|
+
| `calver-seq` | `0.0` |
|
|
59
|
+
| `calver`, `calver-short` | ignored — bump derives from today's date |
|
|
60
|
+
|
|
61
|
+
From there the first `feat:` commit bumps to `0.1.0` / `1` / today's date / … and the release flow creates the tag itself — no `git tag foo@v0.0.0` ceremony required before the first run.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## `ferrflow check`
|
|
66
|
+
|
|
67
|
+
Preview what `ferrflow release` would do without making any changes.
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
ferrflow check [OPTIONS]
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
| Flag | Description |
|
|
74
|
+
| ------------------ | ------------------------------------------------------- |
|
|
75
|
+
| `--json` | Output as JSON |
|
|
76
|
+
| `--channel <NAME>` | Pre-release channel override (e.g. `beta`, `rc`, `dev`) |
|
|
77
|
+
| `--comment` | Post a preview comment on the current PR/MR |
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## `ferrflow publish`
|
|
82
|
+
|
|
83
|
+
Run the configured [publishers](/docs/configuration/config-file/#publishers) for the currently-released version of each package — without bumping, committing, or tagging. `ferrflow release` already runs your publishers at the end of a release; `ferrflow publish` is for when you'd rather run them in a **separate CI job** that has the build toolchain and registry auth the publishers need (docker buildx, helm, a built `dist/`, …) which your release job may not.
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
ferrflow publish [PACKAGES...]
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
| Argument / flag | Description |
|
|
90
|
+
| --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
91
|
+
| `[PACKAGES...]` | Publish these packages by name (space-separated). Omit to auto-detect from the triggering tag (`GITHUB_REF` / `CI_COMMIT_TAG`), falling back to every package that declares publishers. |
|
|
92
|
+
| `--all`, `-a` | Publish every package, ignoring any triggering-tag scope. |
|
|
93
|
+
|
|
94
|
+
It reads each package's current version from its `versionedFiles` (or the latest matching tag for tag-only packages), so run it **after** `ferrflow release` has cut the version. Publishers are idempotent: anything already on the registry is skipped, so a re-run is safe. Use the global `--dry-run` to preview without publishing.
|
|
95
|
+
|
|
96
|
+
**Scope resolution.** With no arguments, if the run was triggered by a package tag (e.g. `api@v2.2.1`), only that package is published — so a single tag-triggered workflow publishes each package on its own tag, with no per-package wiring. Without a matching tag (for example the release job's own branch ref), every package is published, as before. Pass package names to target a subset explicitly, or `--all` to force every package even under a tag.
|
|
97
|
+
|
|
98
|
+
The GitHub Action exposes this as `mode: publish` — it installs the binary and runs `ferrflow publish` for you, scoping to the triggering tag automatically (or pass the `package` input to override). A tag-triggered job only has to set up the toolchain its publishers need:
|
|
99
|
+
|
|
100
|
+
```yaml title=".github/workflows/publish.yml"
|
|
101
|
+
on:
|
|
102
|
+
push:
|
|
103
|
+
# `v*` for single-package repos; `*@v*` for monorepo per-package tags
|
|
104
|
+
tags: ['v*', '*@v*']
|
|
105
|
+
jobs:
|
|
106
|
+
publish:
|
|
107
|
+
runs-on: ubuntu-latest
|
|
108
|
+
permissions:
|
|
109
|
+
contents: read
|
|
110
|
+
packages: write
|
|
111
|
+
steps:
|
|
112
|
+
- uses: actions/checkout@v6
|
|
113
|
+
- uses: docker/setup-buildx-action@v4
|
|
114
|
+
- uses: docker/login-action@v4
|
|
115
|
+
with:
|
|
116
|
+
registry: ghcr.io
|
|
117
|
+
username: ${{ github.actor }}
|
|
118
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
|
119
|
+
- uses: FerrLabs/FerrFlow@v5
|
|
120
|
+
with:
|
|
121
|
+
mode: publish
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## `ferrflow changelog`
|
|
127
|
+
|
|
128
|
+
Generate or update `CHANGELOG.md` only, without bumping versions or creating tags.
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
ferrflow changelog
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Takes no command-specific flags. Use the global `--dry-run` to print the entry without writing it.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## `ferrflow init`
|
|
139
|
+
|
|
140
|
+
Scaffold a config file for the current repository. Detects existing version files (`Cargo.toml`, `package.json`, etc.) and generates the appropriate config.
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
ferrflow init [OPTIONS]
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
| Flag | Description |
|
|
147
|
+
| ------------------- | ---------------------------------------------- |
|
|
148
|
+
| `--format <FORMAT>` | Config file format: `json`, `json5`, or `toml` |
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## `ferrflow migrate`
|
|
153
|
+
|
|
154
|
+
Generate a FerrFlow config from an existing release tool's configuration. Point it at your repo and it writes the equivalent `ferrflow.json`.
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
ferrflow migrate [OPTIONS]
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
| Flag | Description |
|
|
161
|
+
| --------------- | --------------------------------------------------------------------------------------------------------- |
|
|
162
|
+
| `--from <TOOL>` | Source: `semantic-release`, `changesets`, `release-please`, `standard-version`. Auto-detected if omitted. |
|
|
163
|
+
|
|
164
|
+
### Sources
|
|
165
|
+
|
|
166
|
+
| Tool | Reads | Highlights of what maps |
|
|
167
|
+
| ------------------ | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
168
|
+
| `semantic-release` | `.releaserc`, `.releaserc.json` | `tagFormat` → `tagTemplate`; `branches` → channels; `@semantic-release/exec` → `hooks`; `changelog` / `github` / `gitlab` plugins (see the plugin table below) |
|
|
169
|
+
| `release-please` | `release-please-config.json` | the `packages` map → FerrFlow packages (per-package `release-type` → the right version file/format); `include-component-in-tag` → `tagTemplate`; PR flow → `releaseCommitMode: pr` |
|
|
170
|
+
| `standard-version` | `.versionrc`, `.versionrc.json` | `tagPrefix` → `tagTemplate`; `bumpFiles` / `packageFiles` → `versionedFiles` |
|
|
171
|
+
| `changesets` | `.changeset/config.json` | `baseBranch` → `branch`; `linked` / `fixed` → version groups (see note) |
|
|
172
|
+
|
|
173
|
+
semantic-release plugin mapping:
|
|
174
|
+
|
|
175
|
+
| semantic-release | FerrFlow |
|
|
176
|
+
| ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
177
|
+
| `tagFormat: "v${version}"` | `tagTemplate: "v{{version}}"` |
|
|
178
|
+
| `branches` | `branches` — `main`/`master` become the stable line, a `prerelease: true` (or named) branch becomes a channel |
|
|
179
|
+
| `@semantic-release/changelog` | the package's `changelog` path |
|
|
180
|
+
| `@semantic-release/exec` | `hooks` (`prepareCmd` → `preBump`, `publishCmd` → `postPublish`, `successCmd` → `onSuccess`, `failCmd` → `onError`, `verifyConditionsCmd` → `preRelease`) |
|
|
181
|
+
| `@semantic-release/github` / `gitlab` | `forge` |
|
|
182
|
+
|
|
183
|
+
Anything without a FerrFlow equivalent is **surfaced, never guessed**. Each run prints what it mapped, what it ignored, and what needs manual review — for example `@semantic-release/npm` (configure `publishers` by hand), custom `commit-analyzer` release rules (FerrFlow's bump rules are fixed), and `repositoryUrl` (FerrFlow derives the remote from git). It won't overwrite an existing FerrFlow config.
|
|
184
|
+
|
|
185
|
+
<aside class="ferr-aside ferr-aside--note"><div class="ferr-aside__body"><p><strong>changesets.</strong> changesets versions from hand-written <code>.changeset/*.md</code> files, while FerrFlow versions from conventional commits — after migrating you adopt Conventional Commits, and your existing changeset files aren't read. FerrFlow reads your workspace declaration (<code>workspaces</code> in <code>package.json</code>, or <code>pnpm-workspace.yaml</code>) and scaffolds one <code>package</code> entry per discovered package, so <code>linked</code>/<code>fixed</code> groups already reference real packages and the migrated config validates as-is. A repo with no workspace declaration gets a single root package.</p>
|
|
186
|
+
</div></aside>
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
ferrflow migrate # auto-detect
|
|
190
|
+
ferrflow migrate --from release-please
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
JSON, YAML, and JavaScript source configs all work — a JavaScript config (`.releaserc.js`, `release.config.js`, `.versionrc.js`) is evaluated with `node` (so it needs Node.js on PATH), and a YAML config (`.releaserc.yaml`, `.versionrc.yaml`) is parsed directly. After migrating, review the generated config, then run `ferrflow validate` and `ferrflow check`.
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## `ferrflow status`
|
|
198
|
+
|
|
199
|
+
Show the current version of each package and whether a release would be triggered.
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
ferrflow status [OPTIONS]
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
| Flag | Description |
|
|
206
|
+
| ------------------- | ----------------------------------------- |
|
|
207
|
+
| `--output <FORMAT>` | Output format: `text` (default) or `json` |
|
|
208
|
+
|
|
209
|
+
Example output:
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
api 1.2.3 minor bump pending (1 feat commit)
|
|
213
|
+
site 0.4.1 no release (only chore commits)
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## `ferrflow why`
|
|
219
|
+
|
|
220
|
+
Explain the release decision for a single package: whether it counts as touched, which commits were classified and how, what its dependencies are doing, and the bump that falls out of all of it. This is the command to reach for when a package did not release and it is not obvious why.
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
ferrflow why [PACKAGE] [OPTIONS]
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
| Argument / flag | Description |
|
|
227
|
+
| --------------------- | ---------------------------------------------------------------------------------------- |
|
|
228
|
+
| `[PACKAGE]` | Package name — required in a monorepo, optional (and inferred) in a single-package repo. |
|
|
229
|
+
| `--channel <CHANNEL>` | Explain the decision for a prerelease channel (`beta`, `rc`, …) instead of a stable run. |
|
|
230
|
+
| `--json` | Emit the explanation as a structured JSON object instead of the human view. |
|
|
231
|
+
|
|
232
|
+
```
|
|
233
|
+
Package: web
|
|
234
|
+
Path: web
|
|
235
|
+
Strategy: semver
|
|
236
|
+
Version: 1.0.0
|
|
237
|
+
|
|
238
|
+
Last tag: web@v1.0.0 (7dcc20b, 3 days ago, reachable from HEAD)
|
|
239
|
+
|
|
240
|
+
Touch check (changed files at HEAD):
|
|
241
|
+
✗ core/src/api.rs no match
|
|
242
|
+
→ not touched
|
|
243
|
+
|
|
244
|
+
Dependencies:
|
|
245
|
+
core bumping (major) propagate: patch → patch
|
|
246
|
+
|
|
247
|
+
Decision: patch bump from the dependency cascade — 1.0.0 → 1.0.1, tag web@v1.0.1
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
The report reads top to bottom as the decision is made:
|
|
251
|
+
|
|
252
|
+
- **Last tag** — the tag the range starts from, when it was cut, and whether its commit is still reachable from `HEAD`. A tag that is _not_ reachable (rebased away, force pushed) is why a package can look released and still replay its whole history.
|
|
253
|
+
- **Touch check** — the file set that decided whether the package is in scope, with the `path` or `sharedPaths` prefix each file matched. The set is `HEAD`'s changed files, or everything since the last tag when [`recoverMissedReleases`](/docs/configuration/config-file/) pulled the package back in.
|
|
254
|
+
- **Commits considered** — every commit back to the package's last tag with its individual bump. Bump classification is _not_ path-scoped, so a `feat!:` on a sibling package still counts here; this section is usually where an unexpected major comes from.
|
|
255
|
+
- **Dependencies** — each `dependsOn` entry, whether that upstream is moving this run, its `propagate` policy, and what the policy resolves to.
|
|
256
|
+
- **Decision** — the bump, the version range, the tag, and whether it came from the package's own commits or from the dependency cascade.
|
|
257
|
+
|
|
258
|
+
The verdict comes from the same planning code `ferrflow release` runs, so `why` and the next release cannot disagree.
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## `ferrflow diff`
|
|
263
|
+
|
|
264
|
+
Compare two versions of a package: the commits that went in, each commit's bump, the files changed, and the changelog FerrFlow would generate for the range. Handy for auditing a release, checking why a version bumped the way it did, or writing release notes for a range after the fact.
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
ferrflow diff [PACKAGE] <FROM>..<TO> [--json]
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
| Argument / flag | Description |
|
|
271
|
+
| --------------- | --------------------------------------------------------------------------------------------- |
|
|
272
|
+
| `<FROM>..<TO>` | The version range. Each side is a tag or version — `v1.4.0`, or a full tag like `api@v1.6.0`. |
|
|
273
|
+
| `[PACKAGE]` | Package name — required in a monorepo, optional (and inferred) in a single-package repo. |
|
|
274
|
+
| `--json` | Emit the comparison as a structured JSON object instead of the human view. |
|
|
275
|
+
|
|
276
|
+
Each endpoint resolves by trying the string as a tag first (a real tag, or `v1.4.0` in a single-package repo), then as the package's tag for that version (`api@v1.4.0`).
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
ferrflow diff v1.4.0..v1.6.0 # single-package repo
|
|
280
|
+
ferrflow diff api v1.4.0..v1.6.0 # monorepo — name the package
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
The output lists every commit in the range with its individual bump (`major` / `minor` / `patch` / `none`), highlights breaking changes, summarises the changed files, and renders the changelog section for the range. In a monorepo the range is scoped to the named package: only commits touching its `path` or `sharedPaths` are considered.
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## `ferrflow version`
|
|
288
|
+
|
|
289
|
+
Print the current version of one or all packages. Useful in CI scripts.
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
ferrflow version [PACKAGE] [OPTIONS]
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
| Flag | Description |
|
|
296
|
+
| -------- | -------------- |
|
|
297
|
+
| `--json` | Output as JSON |
|
|
298
|
+
|
|
299
|
+
Returns the version from the latest git tag matching the package's tag template.
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
## `ferrflow tag`
|
|
304
|
+
|
|
305
|
+
Print the latest tag for one or all packages.
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
ferrflow tag [PACKAGE] [OPTIONS]
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
| Flag | Description |
|
|
312
|
+
| -------- | -------------- |
|
|
313
|
+
| `--json` | Output as JSON |
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
## `ferrflow validate`
|
|
318
|
+
|
|
319
|
+
Validate the config and the versioned files it points at, without bumping anything. Pass `--repo` to validate a remote repository instead of the working tree.
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
ferrflow validate [OPTIONS]
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
| Flag | Description |
|
|
326
|
+
| --------------- | --------------------------------------------------------------------------------------- |
|
|
327
|
+
| `--json` | Output as JSON |
|
|
328
|
+
| `--repo <REPO>` | Remote repository to validate (e.g. `owner/repo` for GitHub, or `gitlab:group/project`) |
|
|
329
|
+
| `--ref <REF>` | Git ref for remote validation (branch, tag, or commit) |
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
333
|
+
## `ferrflow doctor`
|
|
334
|
+
|
|
335
|
+
Run read-only diagnostics on the repo, config, and forge setup and print a categorised report — the "is my setup sane?" command. Use it on a fresh checkout to see what's missing before the first release, or when a run behaves unexpectedly and you'd otherwise be staring at `--verbose` logs.
|
|
336
|
+
|
|
337
|
+
```bash
|
|
338
|
+
ferrflow doctor [OPTIONS]
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
| Flag | Description |
|
|
342
|
+
| ---------------- | --------------------------------------------------------------------- |
|
|
343
|
+
| `--format <FMT>` | `human` (default) or `json` |
|
|
344
|
+
| `--online` | Also probe the forge API (GitHub rate limit / auth); requires a token |
|
|
345
|
+
|
|
346
|
+
The report groups checks into five sections — **Repo** (git repository, commit history, clean working tree, remote, tags), **Config** (which config file wins, whether it parses, plus the full `ferrflow validate` check suite), **Versioning** (strategy and each package's on-disk version), **Forge** (detected forge and whether an auth token is present in the environment), and **CI** (workflow files, and whether a workflow pins the `FerrLabs/FerrFlow` action). Every check reports green, a warning, or an error.
|
|
347
|
+
|
|
348
|
+
The exit code is scriptable: `0` when everything is green, `1` if there are only warnings, `2` if any check errors. `--format json` has a stable shape — `{ status, exit_code, sections: [{ title, checks: [{ name, status, detail }] }] }` — so CI can assert on it.
|
|
349
|
+
|
|
350
|
+
```bash
|
|
351
|
+
ferrflow doctor # human report
|
|
352
|
+
ferrflow doctor --format json # machine-readable, stable for CI
|
|
353
|
+
ferrflow doctor --online # also check the GitHub API rate limit
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
---
|
|
357
|
+
|
|
358
|
+
## `ferrflow completions`
|
|
359
|
+
|
|
360
|
+
Generate a shell completion script and print it to stdout.
|
|
361
|
+
|
|
362
|
+
```bash
|
|
363
|
+
ferrflow completions <SHELL>
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
`<SHELL>` is one of `bash`, `elvish`, `fish`, `powershell`, or `zsh`.
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
## `ferrflow schema`
|
|
371
|
+
|
|
372
|
+
Print the JSON schema for the ferrflow config file. The schema is bundled into the binary, so this works offline — no network call to `ferrflow.com/schema/ferrflow.json`.
|
|
373
|
+
|
|
374
|
+
```bash
|
|
375
|
+
ferrflow schema [OPTIONS]
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
| Flag | Description |
|
|
379
|
+
| ----------------- | ----------------------------------------------------- |
|
|
380
|
+
| `--pretty` | Format the output instead of compact single-line JSON |
|
|
381
|
+
| `--output <FILE>` | Write to a file instead of stdout |
|
|
382
|
+
|
|
383
|
+
Use it to point an editor at a local copy, or to validate `.ferrflow.json` in a pre-commit hook with no internet access:
|
|
384
|
+
|
|
385
|
+
```bash
|
|
386
|
+
ferrflow schema --pretty --output ferrflow.schema.json
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
Then set `"$schema": "./ferrflow.schema.json"` in your config. The command parses the bundled schema before printing, so it exits non-zero if the build artefact is somehow corrupt.
|
|
390
|
+
|
|
391
|
+
---
|
|
392
|
+
|
|
393
|
+
## Global flags
|
|
394
|
+
|
|
395
|
+
These flags work with all commands:
|
|
396
|
+
|
|
397
|
+
| Flag | Description |
|
|
398
|
+
| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
399
|
+
| `--dry-run` | Show what would happen without making any changes |
|
|
400
|
+
| `--verbose`, `-v` | Verbose output, including commit hashes and file diffs |
|
|
401
|
+
| `--log-format <FORMAT>` | Diagnostic output format on stderr: `human` (default, colored) or `json` (one structured event per line). Command **data** (`--json`, `version` / `tag` values) always stays on stdout. |
|
|
402
|
+
| `--config <PATH>` | Path to a custom config file (default: auto-detected). Also accepts the `FERRFLOW_CONFIG` env variable. |
|
|
403
|
+
| `--jobs <N>` | Max threads for CPU-parallel work (per-package planning). Default: all logical cores; `1` forces single-threaded. Also accepts the `FERRFLOW_JOBS` env variable. |
|
|
404
|
+
| `--version` | Print the FerrFlow version and exit |
|
|
405
|
+
| `--help`, `-h` | Print help |
|
|
406
|
+
|
|
407
|
+
## Logging & output
|
|
408
|
+
|
|
409
|
+
FerrFlow separates **data** from **logs** across the two output streams:
|
|
410
|
+
|
|
411
|
+
- **stdout** carries data — the `--json` output of `check` / `release` / `status` / `validate`, and the value printed by `version` and `tag`. Capture it in scripts: `V=$(ferrflow version)`.
|
|
412
|
+
- **stderr** carries the human status report and every diagnostic event.
|
|
413
|
+
|
|
414
|
+
So you can capture the machine result and the run log independently:
|
|
415
|
+
|
|
416
|
+
```bash
|
|
417
|
+
ferrflow check --json > result.json 2> run.log
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
`--log-format json` renders each diagnostic as one structured JSON event per line on stderr, ready for Datadog / Loki / CloudWatch:
|
|
421
|
+
|
|
422
|
+
```json
|
|
423
|
+
{
|
|
424
|
+
"timestamp": "2026-01-01T00:00:00Z",
|
|
425
|
+
"level": "INFO",
|
|
426
|
+
"fields": { "message": "✓ Updated CHANGELOG.md" },
|
|
427
|
+
"target": "ferrflow::changelog"
|
|
428
|
+
}
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
`--verbose` (or a `RUST_LOG` filter such as `RUST_LOG=ferrflow::git=trace`) controls which levels are shown.
|