@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,120 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: GitHub Actions
|
|
3
|
+
description: Run FerrFlow releases automatically in GitHub Actions.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Using the official action
|
|
7
|
+
|
|
8
|
+
The easiest way to use FerrFlow in GitHub Actions is the `FerrLabs/ferrflow@v5` action. It installs the binary and runs `ferrflow release` automatically.
|
|
9
|
+
|
|
10
|
+
```yaml title=".github/workflows/release.yml"
|
|
11
|
+
name: Release
|
|
12
|
+
|
|
13
|
+
on:
|
|
14
|
+
push:
|
|
15
|
+
branches: [main]
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
release:
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
permissions:
|
|
21
|
+
contents: write # required to push tags and create releases
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@v6
|
|
24
|
+
with:
|
|
25
|
+
fetch-depth: 0 # full history needed for commit scanning
|
|
26
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
27
|
+
|
|
28
|
+
- uses: FerrLabs/ferrflow@v5
|
|
29
|
+
env:
|
|
30
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
<aside class="ferr-aside ferr-aside--warning"><div class="ferr-aside__body"><p><code>fetch-depth: 0</code> is required. Without it, FerrFlow cannot find previous tags and will treat every commit as new.</p>
|
|
34
|
+
</div></aside>
|
|
35
|
+
|
|
36
|
+
## Permissions
|
|
37
|
+
|
|
38
|
+
FerrFlow needs `contents: write` to:
|
|
39
|
+
|
|
40
|
+
- Push version bump commits
|
|
41
|
+
- Create and push git tags
|
|
42
|
+
- Create GitHub Releases
|
|
43
|
+
|
|
44
|
+
If your repository has branch protection rules, create a dedicated token with the necessary permissions and pass it as `FERRFLOW_TOKEN` or configure the action's `token` input.
|
|
45
|
+
|
|
46
|
+
<aside class="ferr-aside ferr-aside--tip"><div class="ferr-aside__body"><p>Prefer not to manage a token? Set <code>bot: true</code> to author releases as <code>ferrflow[bot]</code> with zero secrets — see the <a href="/docs/ci/hosted-bot">Hosted bot</a> guide.</p>
|
|
47
|
+
</div></aside>
|
|
48
|
+
|
|
49
|
+
## Accessing the release output
|
|
50
|
+
|
|
51
|
+
The action exposes the new version as an output you can use in downstream steps:
|
|
52
|
+
|
|
53
|
+
```yaml title=".github/workflows/release.yml"
|
|
54
|
+
- uses: FerrLabs/ferrflow@v5
|
|
55
|
+
id: ferrflow
|
|
56
|
+
env:
|
|
57
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
58
|
+
|
|
59
|
+
- name: Build Docker image
|
|
60
|
+
if: steps.ferrflow.outputs.version != ''
|
|
61
|
+
run: |
|
|
62
|
+
docker build -t myimage:${{ steps.ferrflow.outputs.version }} .
|
|
63
|
+
docker push myimage:${{ steps.ferrflow.outputs.version }}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Skip CI on release commits
|
|
67
|
+
|
|
68
|
+
FerrFlow commits version bumps with `[skip ci]` in the message by default to prevent infinite loops. No extra configuration needed.
|
|
69
|
+
|
|
70
|
+
## PR preview comments
|
|
71
|
+
|
|
72
|
+
FerrFlow can post a comment on every pull request showing what versions will be bumped when the PR is merged. The comment is automatically updated on each push.
|
|
73
|
+
|
|
74
|
+
```yaml title=".github/workflows/preview.yml"
|
|
75
|
+
name: FerrFlow Preview
|
|
76
|
+
|
|
77
|
+
on:
|
|
78
|
+
pull_request:
|
|
79
|
+
|
|
80
|
+
permissions:
|
|
81
|
+
contents: read
|
|
82
|
+
pull-requests: write
|
|
83
|
+
|
|
84
|
+
jobs:
|
|
85
|
+
preview:
|
|
86
|
+
runs-on: ubuntu-latest
|
|
87
|
+
steps:
|
|
88
|
+
- uses: actions/checkout@v6
|
|
89
|
+
with:
|
|
90
|
+
fetch-depth: 0
|
|
91
|
+
- uses: FerrLabs/ferrflow@v5
|
|
92
|
+
with:
|
|
93
|
+
mode: preview
|
|
94
|
+
env:
|
|
95
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The comment looks like:
|
|
99
|
+
|
|
100
|
+
> **FerrFlow Release Preview**
|
|
101
|
+
>
|
|
102
|
+
> | Package | Current | Next | Bump |
|
|
103
|
+
> | ------- | ------- | ------- | ----- |
|
|
104
|
+
> | api | `1.5.0` | `1.6.0` | minor |
|
|
105
|
+
> | site | `1.8.0` | `1.8.1` | patch |
|
|
106
|
+
>
|
|
107
|
+
> Based on 3 commit(s).
|
|
108
|
+
|
|
109
|
+
If no releasable changes are detected, the comment says so.
|
|
110
|
+
|
|
111
|
+
## Monorepo example
|
|
112
|
+
|
|
113
|
+
In a monorepo, FerrFlow releases each changed package in a single run:
|
|
114
|
+
|
|
115
|
+
```yaml title=".github/workflows/release.yml"
|
|
116
|
+
- uses: FerrLabs/ferrflow@v5
|
|
117
|
+
env:
|
|
118
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
119
|
+
# Creates api@v1.3.0 and site@v0.5.1 in one step if both changed
|
|
120
|
+
```
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: GitLab CI
|
|
3
|
+
description: Run FerrFlow releases automatically in GitLab CI.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Using the Docker image
|
|
7
|
+
|
|
8
|
+
The official FerrFlow Docker image ships the binary and can be used directly as a GitLab CI job image.
|
|
9
|
+
|
|
10
|
+
```yaml title=".gitlab-ci.yml"
|
|
11
|
+
release:
|
|
12
|
+
image: ghcr.io/ferrlabs/ferrflow:latest
|
|
13
|
+
stage: release
|
|
14
|
+
script:
|
|
15
|
+
- ferrflow release
|
|
16
|
+
variables:
|
|
17
|
+
GITLAB_TOKEN: $CI_JOB_TOKEN
|
|
18
|
+
rules:
|
|
19
|
+
- if: $CI_COMMIT_BRANCH == "main"
|
|
20
|
+
when: on_success
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
<aside class="ferr-aside ferr-aside--warning"><div class="ferr-aside__body"><p>Make sure your CI runner clones with full history. Add <code>GIT_DEPTH: 0</code> to the job variables to disable shallow cloning.</p>
|
|
24
|
+
</div></aside>
|
|
25
|
+
|
|
26
|
+
## Full history
|
|
27
|
+
|
|
28
|
+
```yaml title=".gitlab-ci.yml"
|
|
29
|
+
release:
|
|
30
|
+
image: ghcr.io/ferrlabs/ferrflow:latest
|
|
31
|
+
variables:
|
|
32
|
+
GIT_DEPTH: 0 # full history — required for tag scanning
|
|
33
|
+
GITLAB_TOKEN: $CI_JOB_TOKEN
|
|
34
|
+
script:
|
|
35
|
+
- ferrflow release
|
|
36
|
+
rules:
|
|
37
|
+
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Using a deploy token
|
|
41
|
+
|
|
42
|
+
If `CI_JOB_TOKEN` doesn't have permission to push tags, create a project deploy token with `write_repository` access and store it as a CI variable:
|
|
43
|
+
|
|
44
|
+
```yaml title=".gitlab-ci.yml"
|
|
45
|
+
release:
|
|
46
|
+
image: ghcr.io/ferrlabs/ferrflow:latest
|
|
47
|
+
variables:
|
|
48
|
+
GIT_DEPTH: 0
|
|
49
|
+
GITLAB_TOKEN: $FERRFLOW_DEPLOY_TOKEN # CI variable with write_repository access
|
|
50
|
+
script:
|
|
51
|
+
- ferrflow release
|
|
52
|
+
rules:
|
|
53
|
+
- if: $CI_COMMIT_BRANCH == "main"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## MR preview comments
|
|
57
|
+
|
|
58
|
+
FerrFlow can post a comment on every merge request showing what versions will be bumped when the MR is merged. The comment is automatically updated on each push.
|
|
59
|
+
|
|
60
|
+
```yaml title=".gitlab-ci.yml"
|
|
61
|
+
ferrflow-preview:
|
|
62
|
+
image: ghcr.io/ferrlabs/ferrflow:latest
|
|
63
|
+
stage: test
|
|
64
|
+
variables:
|
|
65
|
+
GIT_DEPTH: 0
|
|
66
|
+
GITLAB_TOKEN: $CI_JOB_TOKEN
|
|
67
|
+
script:
|
|
68
|
+
- ferrflow check --comment
|
|
69
|
+
rules:
|
|
70
|
+
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The comment looks like:
|
|
74
|
+
|
|
75
|
+
> **FerrFlow Release Preview**
|
|
76
|
+
>
|
|
77
|
+
> | Package | Current | Next | Bump |
|
|
78
|
+
> | ------- | ------- | ------- | ----- |
|
|
79
|
+
> | api | `1.5.0` | `1.6.0` | minor |
|
|
80
|
+
>
|
|
81
|
+
> Based on 2 commit(s).
|
|
82
|
+
|
|
83
|
+
If no releasable changes are detected, the comment says so.
|
|
84
|
+
|
|
85
|
+
<aside class="ferr-aside ferr-aside--note"><div class="ferr-aside__body"><p><code>CI_JOB_TOKEN</code> has permission to post MR notes by default. If your project restricts this, use a project access token with <code>api</code> scope stored as a CI variable.</p>
|
|
86
|
+
</div></aside>
|
|
87
|
+
|
|
88
|
+
## GitLab Releases
|
|
89
|
+
|
|
90
|
+
When `GITLAB_TOKEN` is set, FerrFlow creates a GitLab Release with the generated changelog as release notes, matching the behaviour of the GitHub integration.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Hosted bot (ferrflow[bot])
|
|
3
|
+
description: Author releases as ferrflow[bot] with zero secrets, using the hosted FerrFlow GitHub App and OIDC token exchange.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
By default, the releases and tags FerrFlow pushes are authored by whoever owns the token in your workflow — usually a personal access token, so releases show up under _your_ account. The hosted bot lets releases be authored by **`ferrflow[bot]`** instead, with a clean, consistent identity across every repo.
|
|
7
|
+
|
|
8
|
+
It works like Renovate or Dependabot:
|
|
9
|
+
|
|
10
|
+
- **Zero secrets** in your workflow — no PAT to create, store, or rotate.
|
|
11
|
+
- Releases authored by **`ferrflow[bot]`**.
|
|
12
|
+
- **Short-lived, scoped tokens** — each run gets a fresh token that expires in an hour and is scoped to the single repository.
|
|
13
|
+
|
|
14
|
+
## 1. Install the app
|
|
15
|
+
|
|
16
|
+
Go to **[github.com/apps/ferrflow](https://github.com/apps/ferrflow)** and click **Install**, then choose the organization and repositories you want FerrFlow to release. That's it — there are no secrets to create.
|
|
17
|
+
|
|
18
|
+
The app asks only for **Contents** (read & write, to push tags and create releases) and **Metadata** (read). You can review or uninstall it at any time from your organization's settings.
|
|
19
|
+
|
|
20
|
+
## 2. Enable it in your workflow
|
|
21
|
+
|
|
22
|
+
Add `bot: true` to the action and grant the workflow permission to mint an OIDC token:
|
|
23
|
+
|
|
24
|
+
```yaml title=".github/workflows/release.yml"
|
|
25
|
+
name: Release
|
|
26
|
+
|
|
27
|
+
on:
|
|
28
|
+
push:
|
|
29
|
+
branches: [main]
|
|
30
|
+
|
|
31
|
+
jobs:
|
|
32
|
+
release:
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
permissions:
|
|
35
|
+
id-token: write # lets the runner prove the repo's identity to FerrFlow
|
|
36
|
+
contents: read # for checkout; the release push uses the bot token
|
|
37
|
+
steps:
|
|
38
|
+
- uses: actions/checkout@v6
|
|
39
|
+
with:
|
|
40
|
+
fetch-depth: 0 # full history is needed for commit scanning
|
|
41
|
+
|
|
42
|
+
- uses: FerrLabs/FerrFlow@v5
|
|
43
|
+
with:
|
|
44
|
+
bot: true
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`permissions.id-token: write` is required — it's what lets the runner request the OIDC token that proves which repository is calling. Without it, FerrFlow stops with a clear error rather than falling back silently.
|
|
48
|
+
|
|
49
|
+
## How it works
|
|
50
|
+
|
|
51
|
+
No secret ever leaves your repository. Each run exchanges a proof of identity for a token:
|
|
52
|
+
|
|
53
|
+
1. The GitHub Actions runner issues a short-lived **OIDC token** describing your repository (audience `ferrflow.ferrlabs.com`).
|
|
54
|
+
2. FerrFlow sends that token to **`api.ferrflow.com`**, which verifies it against GitHub's public keys.
|
|
55
|
+
3. The service signs a **scoped installation token** for the FerrFlow app on your repo (using a private key that never leaves FerrLabs' KMS) and returns it. The token lives for one hour.
|
|
56
|
+
4. FerrFlow uses that token to push tags, commits, and releases — so they're authored by `ferrflow[bot]`.
|
|
57
|
+
|
|
58
|
+
## Security model
|
|
59
|
+
|
|
60
|
+
- **The app's private key never leaves FerrLabs' servers** — it lives in a KMS and is only ever used to sign installation tokens server-side.
|
|
61
|
+
- **Your identity is proven by OIDC, not a shared secret** — nothing sensitive is stored in your repo or transmitted from it.
|
|
62
|
+
- **Tokens are minimal and short-lived** — scoped to one repository, expiring after an hour.
|
|
63
|
+
- **You stay in control** — uninstall the app at any time to revoke all access immediately.
|
|
64
|
+
|
|
65
|
+
## Troubleshooting
|
|
66
|
+
|
|
67
|
+
FerrFlow never falls back silently: if bot mode can't get a token, it fails with a message naming the exact cause.
|
|
68
|
+
|
|
69
|
+
| Message | Cause and fix |
|
|
70
|
+
| ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
|
|
71
|
+
| `bot mode requires permissions: id-token: write in your workflow` | The job is missing `permissions.id-token: write`. Add it (see above). |
|
|
72
|
+
| `FerrFlow App not installed on this repository's owner` | Install the app at [github.com/apps/ferrflow](https://github.com/apps/ferrflow) for this org / repo. |
|
|
73
|
+
| `FerrFlow hosted bot rate limit hit (429)` | Token requests are rate-limited per repository. Retry shortly, or use a PAT via `token:` for that run. |
|
|
74
|
+
| `FerrFlow hosted bot service unavailable` | A transient service issue. Check [status.ferrlabs.com](https://status.ferrlabs.com) or retry. |
|
|
75
|
+
|
|
76
|
+
## Alternatives
|
|
77
|
+
|
|
78
|
+
The hosted bot is the recommended path, but it isn't the only one:
|
|
79
|
+
|
|
80
|
+
- **`token:` with a PAT** — supply your own [personal access token](/docs/ci/github-actions). Releases are authored by that token's owner. Works anywhere, including non-GitHub-Actions CI.
|
|
81
|
+
- **`token:` with your own GitHub App** — if you'd rather run your own bot identity, pass a token minted from your own app.
|
|
82
|
+
- **Default `GITHUB_TOKEN`** — the simplest option, but note that pushes made with `GITHUB_TOKEN` **do not trigger downstream workflows** (so a tag push won't kick off a separate publish job). The hosted bot and PATs don't have this limitation.
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Pipeline Triggers
|
|
3
|
+
description: Choose the right CI trigger strategy for your FerrFlow releases.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
FerrFlow works with any CI trigger strategy. This page covers the most common patterns, when to use each one, and how they interact with `releaseCommitMode`.
|
|
7
|
+
|
|
8
|
+
## Push to main
|
|
9
|
+
|
|
10
|
+
The simplest setup: run `ferrflow release` on every push to the default branch. FerrFlow decides whether a release is needed based on the commits since the last tag.
|
|
11
|
+
|
|
12
|
+
```yaml title=".github/workflows/release.yml"
|
|
13
|
+
name: Release
|
|
14
|
+
|
|
15
|
+
on:
|
|
16
|
+
push:
|
|
17
|
+
branches: [main]
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
release:
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
# Skip release commits to avoid infinite loops
|
|
23
|
+
if: "!startsWith(github.event.head_commit.message, 'chore(release):')"
|
|
24
|
+
permissions:
|
|
25
|
+
contents: write
|
|
26
|
+
steps:
|
|
27
|
+
- uses: actions/checkout@v6
|
|
28
|
+
with:
|
|
29
|
+
fetch-depth: 0
|
|
30
|
+
token: ${{ secrets.FERRFLOW_TOKEN }}
|
|
31
|
+
|
|
32
|
+
- uses: FerrLabs/ferrflow@v5
|
|
33
|
+
env:
|
|
34
|
+
GITHUB_TOKEN: ${{ secrets.FERRFLOW_TOKEN }}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**When to use:** Most projects. Simple, predictable, fully automated.
|
|
38
|
+
|
|
39
|
+
**Trade-offs:** Every push to main triggers a workflow run, even if no release is needed. FerrFlow exits early when there are no releasable commits, so the cost is minimal.
|
|
40
|
+
|
|
41
|
+
**Works with:** `releaseCommitMode: commit` (default) or `none`.
|
|
42
|
+
|
|
43
|
+
## Tag-triggered
|
|
44
|
+
|
|
45
|
+
Run your build/deploy pipeline when FerrFlow creates a new tag. This separates the release step (tagging) from the downstream steps (building, publishing, deploying).
|
|
46
|
+
|
|
47
|
+
```yaml title=".github/workflows/build.yml"
|
|
48
|
+
name: Build & Publish
|
|
49
|
+
|
|
50
|
+
on:
|
|
51
|
+
push:
|
|
52
|
+
tags:
|
|
53
|
+
- 'v*' # single-repo: v1.2.0
|
|
54
|
+
- '*@v*' # monorepo: api@v1.2.0, site@v0.5.1
|
|
55
|
+
|
|
56
|
+
jobs:
|
|
57
|
+
build:
|
|
58
|
+
runs-on: ubuntu-latest
|
|
59
|
+
steps:
|
|
60
|
+
- uses: actions/checkout@v6
|
|
61
|
+
|
|
62
|
+
- name: Extract version from tag
|
|
63
|
+
id: version
|
|
64
|
+
run: |
|
|
65
|
+
TAG="${GITHUB_REF_NAME}"
|
|
66
|
+
VERSION="${TAG##*v}"
|
|
67
|
+
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
|
|
68
|
+
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
|
69
|
+
|
|
70
|
+
- name: Build
|
|
71
|
+
run: echo "Building version ${{ steps.version.outputs.version }}"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**When to use:** When you want to decouple versioning from build/deploy. Common for Docker image builds, npm publishing, or binary releases.
|
|
75
|
+
|
|
76
|
+
**Trade-offs:** Requires two workflows: one for the release (push-to-main) and one for the downstream build (tag-triggered). Adds a few seconds of latency between the tag push and the build start.
|
|
77
|
+
|
|
78
|
+
### Monorepo: per-package builds
|
|
79
|
+
|
|
80
|
+
In a monorepo, use tag patterns to build only the package that was released:
|
|
81
|
+
|
|
82
|
+
```yaml title=".github/workflows/build.yml"
|
|
83
|
+
name: Build Package
|
|
84
|
+
|
|
85
|
+
on:
|
|
86
|
+
push:
|
|
87
|
+
tags:
|
|
88
|
+
- 'api@v*'
|
|
89
|
+
- 'site@v*'
|
|
90
|
+
|
|
91
|
+
jobs:
|
|
92
|
+
build-api:
|
|
93
|
+
if: startsWith(github.ref_name, 'api@v')
|
|
94
|
+
runs-on: ubuntu-latest
|
|
95
|
+
steps:
|
|
96
|
+
- uses: actions/checkout@v6
|
|
97
|
+
- run: echo "Building API ${{ github.ref_name }}"
|
|
98
|
+
|
|
99
|
+
build-site:
|
|
100
|
+
if: startsWith(github.ref_name, 'site@v')
|
|
101
|
+
runs-on: ubuntu-latest
|
|
102
|
+
steps:
|
|
103
|
+
- uses: actions/checkout@v6
|
|
104
|
+
- run: echo "Building site ${{ github.ref_name }}"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
<aside class="ferr-aside ferr-aside--note"><div class="ferr-aside__body"><p>If FerrFlow releases multiple packages in a single run (e.g. <code>api@v1.3.0</code> and <code>site@v0.5.1</code>), each tag triggers its own workflow run. The builds happen in parallel automatically.</p>
|
|
108
|
+
</div></aside>
|
|
109
|
+
|
|
110
|
+
## Release-triggered
|
|
111
|
+
|
|
112
|
+
Run a pipeline when a GitHub Release is published. This works well with FerrFlow's `--draft` flag: FerrFlow creates a draft release, you review it, then publishing triggers the build.
|
|
113
|
+
|
|
114
|
+
```yaml title=".github/workflows/deploy.yml"
|
|
115
|
+
name: Deploy
|
|
116
|
+
|
|
117
|
+
on:
|
|
118
|
+
release:
|
|
119
|
+
types: [published]
|
|
120
|
+
|
|
121
|
+
jobs:
|
|
122
|
+
deploy:
|
|
123
|
+
runs-on: ubuntu-latest
|
|
124
|
+
steps:
|
|
125
|
+
- uses: actions/checkout@v6
|
|
126
|
+
with:
|
|
127
|
+
ref: ${{ github.event.release.tag_name }}
|
|
128
|
+
|
|
129
|
+
- name: Deploy
|
|
130
|
+
run: echo "Deploying ${{ github.event.release.tag_name }}"
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**When to use:** When you want a manual review gate before deploying. Create draft releases with `ferrflow release --draft`, review the changelog, then publish.
|
|
134
|
+
|
|
135
|
+
**Trade-offs:** Adds a manual step. The draft release must be published before the deploy runs.
|
|
136
|
+
|
|
137
|
+
**Works with:** All `releaseCommitMode` values.
|
|
138
|
+
|
|
139
|
+
## Manual (workflow_dispatch)
|
|
140
|
+
|
|
141
|
+
Trigger a release on demand with an optional dry-run flag. Useful for controlled release cadences or when you don't want every merge to potentially release.
|
|
142
|
+
|
|
143
|
+
```yaml title=".github/workflows/release.yml"
|
|
144
|
+
name: Release
|
|
145
|
+
|
|
146
|
+
on:
|
|
147
|
+
workflow_dispatch:
|
|
148
|
+
inputs:
|
|
149
|
+
dry_run:
|
|
150
|
+
description: 'Dry run (no tags, no commits, no releases)'
|
|
151
|
+
type: boolean
|
|
152
|
+
default: false
|
|
153
|
+
|
|
154
|
+
jobs:
|
|
155
|
+
release:
|
|
156
|
+
runs-on: ubuntu-latest
|
|
157
|
+
permissions:
|
|
158
|
+
contents: write
|
|
159
|
+
steps:
|
|
160
|
+
- uses: actions/checkout@v6
|
|
161
|
+
with:
|
|
162
|
+
fetch-depth: 0
|
|
163
|
+
token: ${{ secrets.FERRFLOW_TOKEN }}
|
|
164
|
+
|
|
165
|
+
- uses: FerrLabs/ferrflow@v5
|
|
166
|
+
with:
|
|
167
|
+
args: ${{ inputs.dry_run == true && '--dry-run' || '' }}
|
|
168
|
+
env:
|
|
169
|
+
GITHUB_TOKEN: ${{ secrets.FERRFLOW_TOKEN }}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
**When to use:** Teams that prefer explicit release decisions over automatic releases. Also useful as a secondary workflow alongside push-to-main for ad-hoc releases.
|
|
173
|
+
|
|
174
|
+
**Trade-offs:** Requires someone to click "Run workflow" in the Actions tab. Commits can pile up between releases, producing larger changelogs.
|
|
175
|
+
|
|
176
|
+
## PR-based
|
|
177
|
+
|
|
178
|
+
Use `releaseCommitMode: pr` to have FerrFlow open a pull request with the version bump instead of committing directly. The release completes when the PR is merged.
|
|
179
|
+
|
|
180
|
+
```yaml title="ferrflow.json"
|
|
181
|
+
{ 'workspace': { 'releaseCommitMode': 'pr' } }
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
```yaml title=".github/workflows/release.yml"
|
|
185
|
+
name: Release
|
|
186
|
+
|
|
187
|
+
on:
|
|
188
|
+
push:
|
|
189
|
+
branches: [main]
|
|
190
|
+
|
|
191
|
+
jobs:
|
|
192
|
+
release:
|
|
193
|
+
runs-on: ubuntu-latest
|
|
194
|
+
if: "!startsWith(github.event.head_commit.message, 'chore(release):')"
|
|
195
|
+
permissions:
|
|
196
|
+
contents: write
|
|
197
|
+
pull-requests: write
|
|
198
|
+
steps:
|
|
199
|
+
- uses: actions/checkout@v6
|
|
200
|
+
with:
|
|
201
|
+
fetch-depth: 0
|
|
202
|
+
token: ${{ secrets.FERRFLOW_TOKEN }}
|
|
203
|
+
|
|
204
|
+
- uses: FerrLabs/ferrflow@v5
|
|
205
|
+
env:
|
|
206
|
+
GITHUB_TOKEN: ${{ secrets.FERRFLOW_TOKEN }}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
**When to use:** When you want to review version bumps before they land, or when branch protection prevents direct pushes to main.
|
|
210
|
+
|
|
211
|
+
**Trade-offs:** Adds an extra merge step. The PR must be merged before tags are created.
|
|
212
|
+
|
|
213
|
+
**Works with:** `releaseCommitMode: pr` only. Requires `pull-requests: write` permission.
|
|
214
|
+
|
|
215
|
+
## Combining strategies
|
|
216
|
+
|
|
217
|
+
A common production setup combines push-to-main for versioning with tag-triggered builds:
|
|
218
|
+
|
|
219
|
+
```yaml title=".github/workflows/release.yml"
|
|
220
|
+
# Workflow 1: Version and tag on every push to main
|
|
221
|
+
name: Release
|
|
222
|
+
on:
|
|
223
|
+
push:
|
|
224
|
+
branches: [main]
|
|
225
|
+
jobs:
|
|
226
|
+
release:
|
|
227
|
+
if: "!startsWith(github.event.head_commit.message, 'chore(release):')"
|
|
228
|
+
runs-on: ubuntu-latest
|
|
229
|
+
permissions:
|
|
230
|
+
contents: write
|
|
231
|
+
steps:
|
|
232
|
+
- uses: actions/checkout@v6
|
|
233
|
+
with:
|
|
234
|
+
fetch-depth: 0
|
|
235
|
+
token: ${{ secrets.FERRFLOW_TOKEN }}
|
|
236
|
+
- uses: FerrLabs/ferrflow@v5
|
|
237
|
+
env:
|
|
238
|
+
GITHUB_TOKEN: ${{ secrets.FERRFLOW_TOKEN }}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
```yaml title=".github/workflows/build.yml"
|
|
242
|
+
# Workflow 2: Build and deploy when a tag is pushed
|
|
243
|
+
name: Build
|
|
244
|
+
on:
|
|
245
|
+
push:
|
|
246
|
+
tags: ['v*', '*@v*']
|
|
247
|
+
jobs:
|
|
248
|
+
build:
|
|
249
|
+
runs-on: ubuntu-latest
|
|
250
|
+
steps:
|
|
251
|
+
- uses: actions/checkout@v6
|
|
252
|
+
- run: echo "Building ${{ github.ref_name }}"
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## Concurrency safety
|
|
256
|
+
|
|
257
|
+
Since v5.2, `ferrflow release` acquires `.git/ferrflow.lock` atomically (`O_CREAT|O_EXCL`) at the start of every mutating run. A second concurrent invocation on the same repo fails fast with a clear error rather than racing on git refs — the classic failure mode is a manually-triggered release firing at the same time as a cron-driven `auto-release`, producing half-pushed tag sets, non-fast-forward rejects, or duplicate draft releases.
|
|
258
|
+
|
|
259
|
+
You don't need to wire anything up — the lock is automatic on every `release` invocation. Read-only commands (`check`, `status`, `version`, `tag`) skip it.
|
|
260
|
+
|
|
261
|
+
If a previous run crashed without releasing the lock, the next invocation takes it over automatically after 30 minutes (the host + PID stamped inside the lockfile lets FerrFlow detect stale locks). To take it over sooner, delete `.git/ferrflow.lock` manually.
|
|
262
|
+
|
|
263
|
+
<aside class="ferr-aside ferr-aside--note"><div class="ferr-aside__body"><p>The lock is per-repo, scoped to <code>.git/</code>. It does not protect across separate clones of the same repo — if you run releases concurrently from two different runners against two different checkouts of the same remote, the lock won't see the other side. Use a single release runner, or serialize at the CI level (<code>concurrency:</code> in GitHub Actions, <code>interruptible: false</code> in GitLab).</p>
|
|
264
|
+
</div></aside>
|
|
265
|
+
|
|
266
|
+
## Crash-resume
|
|
267
|
+
|
|
268
|
+
A release does several side-effecting steps in sequence: write versioned files → commit → tag → push commit → push tags → create GitHub Releases → run `post_publish` hooks. If the process dies between any of those (network blip, runner termination, SIGKILL), the repo is in a half-released state.
|
|
269
|
+
|
|
270
|
+
Since v5.3, FerrFlow writes a `.git/ferrflow.checkpoint.json` after each phase succeeds. The next `ferrflow release` invocation on the same commit resumes from the recorded phase and skips the work that already happened — useful at CI scale where transient failures are routine. The checkpoint is deleted automatically when a release finishes cleanly.
|
|
271
|
+
|
|
272
|
+
Two safety rails:
|
|
273
|
+
|
|
274
|
+
- HEAD-pinning: the checkpoint records the commit SHA the release was operating on. If you advance HEAD between runs, FerrFlow refuses to resume and tells you to either reset HEAD back to the recorded commit or delete the checkpoint manually. This avoids replaying old tags onto a different commit graph.
|
|
275
|
+
- Idempotency: the underlying git and forge operations already no-op when their target exists (a tag that's already pushed is a no-op, a release that already exists is reused), so a mid-phase crash still recovers cleanly on the next run.
|
|
276
|
+
|
|
277
|
+
To start fresh after a crash you don't want to resume from, delete `.git/ferrflow.checkpoint.json` manually.
|
|
278
|
+
|
|
279
|
+
## Summary
|
|
280
|
+
|
|
281
|
+
| Trigger | Automatic | Review gate | Best for |
|
|
282
|
+
| ----------------- | --------- | ----------- | -------------------------- |
|
|
283
|
+
| Push to main | Yes | No | Most projects |
|
|
284
|
+
| Tag-triggered | Yes | No | Decoupled build/deploy |
|
|
285
|
+
| Release-triggered | No | Yes | Draft → review → publish |
|
|
286
|
+
| Manual | No | Yes | Controlled release cadence |
|
|
287
|
+
| PR-based | Partial | Yes | Branch protection / review |
|