@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,206 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Supported formats
|
|
3
|
+
description: Version file formats that FerrFlow can read and update.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<div class="ferr-tabs">
|
|
7
|
+
<div class="ferr-tab" data-label="JSON"><p class="ferr-tab__label">JSON</p><div class="ferr-tab__body"><p>Used by Node.js (<code>package.json</code>).</p>
|
|
8
|
+
<p>FerrFlow updates the top-level <code>version</code> field.</p>
|
|
9
|
+
<pre><code class="language-json">{
|
|
10
|
+
"name": "my-package",
|
|
11
|
+
"version": "1.2.3"
|
|
12
|
+
}
|
|
13
|
+
</code></pre>
|
|
14
|
+
</div></div>
|
|
15
|
+
<div class="ferr-tab" data-label="TOML"><p class="ferr-tab__label">TOML</p><div class="ferr-tab__body"><p>Used by Rust (<code>Cargo.toml</code>) and Python (<code>pyproject.toml</code>).</p>
|
|
16
|
+
<p>FerrFlow updates the <code>version</code> field under <code>[package]</code>, <code>[project]</code>, or <code>[tool.poetry]</code>.</p>
|
|
17
|
+
<pre><code class="language-toml">[package]
|
|
18
|
+
name = "my-crate"
|
|
19
|
+
version = "1.2.3" # ← updated
|
|
20
|
+
</code></pre>
|
|
21
|
+
</div></div>
|
|
22
|
+
<div class="ferr-tab" data-label="XML"><p class="ferr-tab__label">XML</p><div class="ferr-tab__body"><p>Used by Java/Maven (<code>pom.xml</code>).</p>
|
|
23
|
+
<p>FerrFlow updates the first <code><version></code> element it encounters.</p>
|
|
24
|
+
<pre><code class="language-xml"><project>
|
|
25
|
+
<groupId>com.example</groupId>
|
|
26
|
+
<artifactId>my-app</artifactId>
|
|
27
|
+
<version>1.2.3</version> <!-- updated -->
|
|
28
|
+
</project>
|
|
29
|
+
</code></pre>
|
|
30
|
+
</div></div>
|
|
31
|
+
<div class="ferr-tab" data-label="Gradle"><p class="ferr-tab__label">Gradle</p><div class="ferr-tab__body"><p>Used by Java/Kotlin Gradle projects (<code>build.gradle</code>, <code>build.gradle.kts</code>).</p>
|
|
32
|
+
<p>FerrFlow updates the <code>version = "..."</code> assignment.</p>
|
|
33
|
+
<pre><code class="language-groovy">version = "1.2.3" // updated
|
|
34
|
+
</code></pre>
|
|
35
|
+
</div></div>
|
|
36
|
+
<div class="ferr-tab" data-label="Plain text"><p class="ferr-tab__label">Plain text</p><div class="ferr-tab__body"><p>Used for simple version files (<code>VERSION</code>, <code>VERSION.txt</code>).</p>
|
|
37
|
+
<p>FerrFlow replaces the entire file content with the version number.</p>
|
|
38
|
+
<pre><code>1.2.3
|
|
39
|
+
</code></pre>
|
|
40
|
+
</div></div>
|
|
41
|
+
<div class="ferr-tab" data-label="Go"><p class="ferr-tab__label">Go</p><div class="ferr-tab__body"><p>Used by Go projects (<code>go.mod</code>).</p>
|
|
42
|
+
<p>Go modules use git tags directly — FerrFlow does <strong>not</strong> modify <code>go.mod</code>. The version is derived entirely from the git tag (<code>v1.2.3</code> or <code>{name}@v1.2.3</code>).</p>
|
|
43
|
+
<p>On a brand-new repo with no matching tag yet, FerrFlow v3+ bootstraps from the strategy's zero value (<code>0.0.0</code> for <code>semver</code>, <code>0</code> for <code>sequential</code>, …) and creates the first real tag itself — you do not need to run <code>git tag … v0.0.0</code> before the first release. See <a href="/docs/reference/cli#which-version-is-bumped-from">how <code>release</code> picks the baseline</a>.</p>
|
|
44
|
+
</div></div>
|
|
45
|
+
<div class="ferr-tab" data-label="Helm"><p class="ferr-tab__label">Helm</p><div class="ferr-tab__body"><p>Used by Kubernetes Helm charts (<code>Chart.yaml</code>).</p>
|
|
46
|
+
<p>FerrFlow updates the <code>version</code> field and, when present, keeps <code>appVersion</code> in sync.</p>
|
|
47
|
+
<p>The newer <code>chartyaml</code> alias is functionally equivalent — use whichever reads more naturally in your config.</p>
|
|
48
|
+
<pre><code class="language-yaml">apiVersion: v2
|
|
49
|
+
name: my-app
|
|
50
|
+
version: 1.2.3 # ← updated
|
|
51
|
+
appVersion: "1.2.3" # ← updated when present
|
|
52
|
+
</code></pre>
|
|
53
|
+
</div></div>
|
|
54
|
+
<div class="ferr-tab" data-label="Dart"><p class="ferr-tab__label">Dart</p><div class="ferr-tab__body"><p>Used by Dart and Flutter packages (<code>pubspec.yaml</code>).</p>
|
|
55
|
+
<p>FerrFlow updates the top-level <code>version:</code> key, leaving dependency versions, anchors, and comments intact. SemVer build suffixes (<code>1.2.3+42</code>) are supported.</p>
|
|
56
|
+
<pre><code class="language-yaml">name: my_app
|
|
57
|
+
version: 1.2.3+42 # ← updated
|
|
58
|
+
dependencies:
|
|
59
|
+
some_pkg:
|
|
60
|
+
version: 2.0.0 # untouched — this is a dep constraint
|
|
61
|
+
</code></pre>
|
|
62
|
+
<p>Config snippet:</p>
|
|
63
|
+
<pre><code class="language-toml">[[package.versioned_files]]
|
|
64
|
+
path = "pubspec.yaml"
|
|
65
|
+
format = "pubspecyaml"
|
|
66
|
+
</code></pre>
|
|
67
|
+
</div></div>
|
|
68
|
+
<div class="ferr-tab" data-label="Elixir"><p class="ferr-tab__label">Elixir</p><div class="ferr-tab__body"><p>Used by Elixir / Mix projects (<code>mix.exs</code>).</p>
|
|
69
|
+
<p>FerrFlow updates the first <code>version: "…"</code> literal it finds — the canonical spot is inside <code>def project do [ ..., version: "x.y.z", ... ] end</code>.</p>
|
|
70
|
+
<pre><code class="language-elixir">def project do
|
|
71
|
+
[
|
|
72
|
+
app: :my_app,
|
|
73
|
+
version: "1.2.3", # ← updated
|
|
74
|
+
elixir: "~> 1.15",
|
|
75
|
+
deps: deps()
|
|
76
|
+
]
|
|
77
|
+
end
|
|
78
|
+
</code></pre>
|
|
79
|
+
<p>Config snippet:</p>
|
|
80
|
+
<pre><code class="language-toml">[[package.versioned_files]]
|
|
81
|
+
path = "mix.exs"
|
|
82
|
+
format = "mixexs"
|
|
83
|
+
</code></pre>
|
|
84
|
+
</div></div>
|
|
85
|
+
<div class="ferr-tab" data-label="Ruby"><p class="ferr-tab__label">Ruby</p><div class="ferr-tab__body"><p>Used by Ruby gems (<code>*.gemspec</code>).</p>
|
|
86
|
+
<p>FerrFlow updates the <code>.version = "…"</code> assignment. Any receiver name works (<code>s</code>, <code>spec</code>, <code>gem</code>, …). Setting <code>version</code> from a constant (<code>s.version = MyGem::VERSION</code>) isn't covered — version the loaded <code>version.rb</code> file directly in that case.</p>
|
|
87
|
+
<pre><code class="language-ruby">Gem::Specification.new do |s|
|
|
88
|
+
s.name = "my_gem"
|
|
89
|
+
s.version = "1.2.3" # ← updated
|
|
90
|
+
end
|
|
91
|
+
</code></pre>
|
|
92
|
+
<p>Config snippet:</p>
|
|
93
|
+
<pre><code class="language-toml">[[package.versioned_files]]
|
|
94
|
+
path = "my_gem.gemspec"
|
|
95
|
+
format = "gemspec"
|
|
96
|
+
</code></pre>
|
|
97
|
+
</div></div>
|
|
98
|
+
<div class="ferr-tab" data-label="Swift"><p class="ferr-tab__label">Swift</p><div class="ferr-tab__body"><p>Used by Swift packages (<code>Package.swift</code>).</p>
|
|
99
|
+
<p>Swift PM derives a package's version from git tags, so there's no canonical location inside <code>Package.swift</code> — FerrFlow updates the first <code>let <name>Version = "…"</code> declaration. Constant names must end with <code>Version</code> (e.g. <code>packageVersion</code>, <code>AppVersion</code>) or be literally <code>version</code>. Dependency <code>.package(url:..., from: "…")</code> arguments are <strong>not</strong> touched.</p>
|
|
100
|
+
<pre><code class="language-swift">import PackageDescription
|
|
101
|
+
|
|
102
|
+
let packageVersion = "1.2.3" // ← updated
|
|
103
|
+
|
|
104
|
+
let package = Package(
|
|
105
|
+
name: "MyPackage",
|
|
106
|
+
dependencies: [
|
|
107
|
+
.package(url: "…", from: "1.5.0"), // untouched
|
|
108
|
+
]
|
|
109
|
+
)
|
|
110
|
+
</code></pre>
|
|
111
|
+
<p>Config snippet:</p>
|
|
112
|
+
<pre><code class="language-toml">[[package.versioned_files]]
|
|
113
|
+
path = "Package.swift"
|
|
114
|
+
format = "packageswift"
|
|
115
|
+
</code></pre>
|
|
116
|
+
</div></div>
|
|
117
|
+
<div class="ferr-tab" data-label="Haskell"><p class="ferr-tab__label">Haskell</p><div class="ferr-tab__body"><p>Used by Haskell packages (<code>*.cabal</code>).</p>
|
|
118
|
+
<p>FerrFlow updates the top-level <code>version:</code> field. Field names are case-insensitive and top-level fields sit at column 0, so <code>cabal-version:</code> — which declares the file format, not the package version — is <strong>never</strong> touched, and neither is an indented <code>version:</code> inside a stanza.</p>
|
|
119
|
+
<pre><code class="language-cabal">cabal-version: 2.4 <-- untouched
|
|
120
|
+
name: my-package
|
|
121
|
+
version: 1.2.3 <-- updated
|
|
122
|
+
</code></pre>
|
|
123
|
+
<p>Config snippet:</p>
|
|
124
|
+
<pre><code class="language-toml">[[package.versioned_files]]
|
|
125
|
+
path = "my-package.cabal"
|
|
126
|
+
format = "cabal"
|
|
127
|
+
</code></pre>
|
|
128
|
+
</div></div>
|
|
129
|
+
<div class="ferr-tab" data-label="CMake"><p class="ferr-tab__label">CMake</p><div class="ferr-tab__body"><p>Used by C / C++ projects (<code>CMakeLists.txt</code>).</p>
|
|
130
|
+
<p>FerrFlow updates the <code>VERSION</code> argument of the <code>project()</code> call, including the multi-line form. <code>cmake_minimum_required(VERSION …)</code> — the CMake tool floor — and any <code>set(<name>_VERSION …)</code> variable are <strong>not</strong> touched.</p>
|
|
131
|
+
<pre><code class="language-cmake">cmake_minimum_required(VERSION 3.20) // untouched
|
|
132
|
+
|
|
133
|
+
project(MyProject
|
|
134
|
+
VERSION 1.2.3 // updated
|
|
135
|
+
LANGUAGES CXX)
|
|
136
|
+
</code></pre>
|
|
137
|
+
<p>Config snippet:</p>
|
|
138
|
+
<pre><code class="language-toml">[[package.versioned_files]]
|
|
139
|
+
path = "CMakeLists.txt"
|
|
140
|
+
format = "cmake"
|
|
141
|
+
</code></pre>
|
|
142
|
+
</div></div>
|
|
143
|
+
</div>
|
|
144
|
+
|
|
145
|
+
## File → format quick reference
|
|
146
|
+
|
|
147
|
+
| File | `format` | Selector / behaviour |
|
|
148
|
+
| ---------------------------------- | --------------------- | ------------------------------------------ |
|
|
149
|
+
| `Cargo.toml` | `toml` | `package.version` |
|
|
150
|
+
| `pyproject.toml` | `toml` | `project.version` or `tool.poetry.version` |
|
|
151
|
+
| `package.json` | `json` | `version` |
|
|
152
|
+
| `composer.json` | `json` | `version` |
|
|
153
|
+
| `pom.xml` | `xml` | first `<version>` tag |
|
|
154
|
+
| `*.csproj` | `csproj` | `<Version>` in `<PropertyGroup>` |
|
|
155
|
+
| `build.gradle`, `build.gradle.kts` | `gradle` | `version = "…"` |
|
|
156
|
+
| `Chart.yaml` | `helm` or `chartyaml` | top-level `version:` |
|
|
157
|
+
| `pubspec.yaml` | `pubspecyaml` | top-level `version:` |
|
|
158
|
+
| `mix.exs` | `mixexs` | `version: "…"` in project keyword list |
|
|
159
|
+
| `*.gemspec` | `gemspec` | `<ident>.version = "…"` |
|
|
160
|
+
| `Package.swift` | `packageswift` | top-level `let <name>Version = "…"` |
|
|
161
|
+
| `*.cabal` | `cabal` | top-level `version:` field |
|
|
162
|
+
| `CMakeLists.txt` | `cmake` | `VERSION` argument of `project()` |
|
|
163
|
+
| `go.mod` | `gomod` | git tag only — no file write |
|
|
164
|
+
| `VERSION`, `VERSION.txt` | `txt` | entire file content |
|
|
165
|
+
|
|
166
|
+
## Multiple files per package
|
|
167
|
+
|
|
168
|
+
A package can have as many versioned file entries as needed:
|
|
169
|
+
|
|
170
|
+
<div class="ferr-tabs">
|
|
171
|
+
<div class="ferr-tab" data-label="JSON"><p class="ferr-tab__label">JSON</p><div class="ferr-tab__body"><pre><code class="language-json">{
|
|
172
|
+
"package": [
|
|
173
|
+
{
|
|
174
|
+
"versionedFiles": [
|
|
175
|
+
{ "path": "Cargo.toml", "format": "toml" },
|
|
176
|
+
{ "path": "npm/package.json", "format": "json" }
|
|
177
|
+
]
|
|
178
|
+
}
|
|
179
|
+
]
|
|
180
|
+
}
|
|
181
|
+
</code></pre>
|
|
182
|
+
</div></div>
|
|
183
|
+
<div class="ferr-tab" data-label="TOML"><p class="ferr-tab__label">TOML</p><div class="ferr-tab__body"><pre><code class="language-toml">[[package.versioned_files]]
|
|
184
|
+
path = "Cargo.toml"
|
|
185
|
+
format = "toml"
|
|
186
|
+
|
|
187
|
+
[[package.versioned_files]]
|
|
188
|
+
path = "npm/package.json"
|
|
189
|
+
format = "json"
|
|
190
|
+
</code></pre>
|
|
191
|
+
</div></div>
|
|
192
|
+
<div class="ferr-tab" data-label="JSON5"><p class="ferr-tab__label">JSON5</p><div class="ferr-tab__body"><pre><code class="language-json5">{
|
|
193
|
+
package: [
|
|
194
|
+
{
|
|
195
|
+
versionedFiles: [
|
|
196
|
+
{ path: "Cargo.toml", format: "toml" },
|
|
197
|
+
{ path: "npm/package.json", format: "json" },
|
|
198
|
+
],
|
|
199
|
+
},
|
|
200
|
+
],
|
|
201
|
+
}
|
|
202
|
+
</code></pre>
|
|
203
|
+
</div></div>
|
|
204
|
+
</div>
|
|
205
|
+
|
|
206
|
+
Both files will be updated to the same version before the git commit.
|
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Monorepo
|
|
3
|
+
description: Version multiple packages independently in a single repository.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
FerrFlow treats a repository as a monorepo when the config defines more than one package. Each package is versioned independently based on its own git history.
|
|
7
|
+
|
|
8
|
+
## Package isolation
|
|
9
|
+
|
|
10
|
+
FerrFlow uses path prefixes to determine which commits belong to which package. Only commits that touch files under `path` (or `sharedPaths`) trigger a release for that package.
|
|
11
|
+
|
|
12
|
+
<div class="ferr-tabs">
|
|
13
|
+
<div class="ferr-tab" data-label="JSON"><p class="ferr-tab__label">JSON</p><div class="ferr-tab__body"><pre><code class="language-json">{
|
|
14
|
+
"package": [
|
|
15
|
+
{
|
|
16
|
+
"name": "api",
|
|
17
|
+
"path": "packages/api"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"name": "site",
|
|
21
|
+
"path": "packages/site"
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
</code></pre>
|
|
26
|
+
</div></div>
|
|
27
|
+
<div class="ferr-tab" data-label="TOML"><p class="ferr-tab__label">TOML</p><div class="ferr-tab__body"><pre><code class="language-toml">[[package]]
|
|
28
|
+
name = "api"
|
|
29
|
+
path = "packages/api"
|
|
30
|
+
|
|
31
|
+
[[package]]
|
|
32
|
+
name = "site"
|
|
33
|
+
path = "packages/site"
|
|
34
|
+
</code></pre>
|
|
35
|
+
|
|
36
|
+
</div></div>
|
|
37
|
+
<div class="ferr-tab" data-label="JSON5"><p class="ferr-tab__label">JSON5</p><div class="ferr-tab__body"><pre><code class="language-json5">{
|
|
38
|
+
package: [
|
|
39
|
+
{
|
|
40
|
+
name: "api",
|
|
41
|
+
path: "packages/api",
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: "site",
|
|
45
|
+
path: "packages/site",
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
}
|
|
49
|
+
</code></pre>
|
|
50
|
+
</div></div>
|
|
51
|
+
<div class="ferr-tab" data-label="YAML"><p class="ferr-tab__label">YAML</p><div class="ferr-tab__body"><pre><code class="language-yaml">package:
|
|
52
|
+
- name: api
|
|
53
|
+
path: packages/api
|
|
54
|
+
- name: site
|
|
55
|
+
path: packages/site
|
|
56
|
+
</code></pre>
|
|
57
|
+
</div></div>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
## Shared dependencies
|
|
61
|
+
|
|
62
|
+
If you have code shared between packages (e.g., a `packages/shared/` library), declare it as a `sharedPaths` entry. A change to any shared path triggers a release for every package that lists it:
|
|
63
|
+
|
|
64
|
+
<div class="ferr-tabs">
|
|
65
|
+
<div class="ferr-tab" data-label="JSON"><p class="ferr-tab__label">JSON</p><div class="ferr-tab__body"><pre><code class="language-json">{
|
|
66
|
+
"package": [
|
|
67
|
+
{
|
|
68
|
+
"name": "api",
|
|
69
|
+
"path": "packages/api",
|
|
70
|
+
"sharedPaths": ["packages/shared/"]
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"name": "site",
|
|
74
|
+
"path": "packages/site",
|
|
75
|
+
"sharedPaths": ["packages/shared/"]
|
|
76
|
+
}
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
</code></pre>
|
|
80
|
+
</div></div>
|
|
81
|
+
<div class="ferr-tab" data-label="TOML"><p class="ferr-tab__label">TOML</p><div class="ferr-tab__body"><pre><code class="language-toml">[[package]]
|
|
82
|
+
name = "api"
|
|
83
|
+
path = "packages/api"
|
|
84
|
+
shared_paths = ["packages/shared/"]
|
|
85
|
+
|
|
86
|
+
[[package]]
|
|
87
|
+
name = "site"
|
|
88
|
+
path = "packages/site"
|
|
89
|
+
shared_paths = ["packages/shared/"]
|
|
90
|
+
</code></pre>
|
|
91
|
+
|
|
92
|
+
</div></div>
|
|
93
|
+
<div class="ferr-tab" data-label="JSON5"><p class="ferr-tab__label">JSON5</p><div class="ferr-tab__body"><pre><code class="language-json5">{
|
|
94
|
+
package: [
|
|
95
|
+
{
|
|
96
|
+
name: "api",
|
|
97
|
+
path: "packages/api",
|
|
98
|
+
sharedPaths: ["packages/shared/"],
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
name: "site",
|
|
102
|
+
path: "packages/site",
|
|
103
|
+
sharedPaths: ["packages/shared/"],
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
}
|
|
107
|
+
</code></pre>
|
|
108
|
+
</div></div>
|
|
109
|
+
<div class="ferr-tab" data-label="YAML"><p class="ferr-tab__label">YAML</p><div class="ferr-tab__body"><pre><code class="language-yaml">package:
|
|
110
|
+
- name: api
|
|
111
|
+
path: packages/api
|
|
112
|
+
sharedPaths:
|
|
113
|
+
- packages/shared/
|
|
114
|
+
- name: site
|
|
115
|
+
path: packages/site
|
|
116
|
+
sharedPaths:
|
|
117
|
+
- packages/shared/
|
|
118
|
+
</code></pre>
|
|
119
|
+
</div></div>
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
## Package dependencies
|
|
123
|
+
|
|
124
|
+
Use `dependsOn` to declare that a package depends on another. When a dependency is released, the dependent package is bumped too — even if none of its own files changed — with the same bump type by default. This cascades transitively: if `app` depends on `cli` and `cli` depends on `core`, bumping `core` bumps both `cli` and `app`.
|
|
125
|
+
|
|
126
|
+
<div class="ferr-tabs">
|
|
127
|
+
<div class="ferr-tab" data-label="JSON"><p class="ferr-tab__label">JSON</p><div class="ferr-tab__body"><pre><code class="language-json">{
|
|
128
|
+
"package": [
|
|
129
|
+
{
|
|
130
|
+
"name": "core",
|
|
131
|
+
"path": "packages/core"
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"name": "cli",
|
|
135
|
+
"path": "packages/cli",
|
|
136
|
+
"dependsOn": ["core"]
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"name": "app",
|
|
140
|
+
"path": "packages/app",
|
|
141
|
+
"dependsOn": ["cli"]
|
|
142
|
+
}
|
|
143
|
+
]
|
|
144
|
+
}
|
|
145
|
+
</code></pre>
|
|
146
|
+
</div></div>
|
|
147
|
+
<div class="ferr-tab" data-label="TOML"><p class="ferr-tab__label">TOML</p><div class="ferr-tab__body"><pre><code class="language-toml">[[package]]
|
|
148
|
+
name = "core"
|
|
149
|
+
path = "packages/core"
|
|
150
|
+
|
|
151
|
+
[[package]]
|
|
152
|
+
name = "cli"
|
|
153
|
+
path = "packages/cli"
|
|
154
|
+
depends_on = ["core"]
|
|
155
|
+
|
|
156
|
+
[[package]]
|
|
157
|
+
name = "app"
|
|
158
|
+
path = "packages/app"
|
|
159
|
+
depends_on = ["cli"]
|
|
160
|
+
</code></pre>
|
|
161
|
+
|
|
162
|
+
</div></div>
|
|
163
|
+
<div class="ferr-tab" data-label="JSON5"><p class="ferr-tab__label">JSON5</p><div class="ferr-tab__body"><pre><code class="language-json5">{
|
|
164
|
+
package: [
|
|
165
|
+
{
|
|
166
|
+
name: "core",
|
|
167
|
+
path: "packages/core",
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
name: "cli",
|
|
171
|
+
path: "packages/cli",
|
|
172
|
+
dependsOn: ["core"],
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
name: "app",
|
|
176
|
+
path: "packages/app",
|
|
177
|
+
dependsOn: ["cli"],
|
|
178
|
+
},
|
|
179
|
+
],
|
|
180
|
+
}
|
|
181
|
+
</code></pre>
|
|
182
|
+
</div></div>
|
|
183
|
+
<div class="ferr-tab" data-label="YAML"><p class="ferr-tab__label">YAML</p><div class="ferr-tab__body"><pre><code class="language-yaml">package:
|
|
184
|
+
- name: core
|
|
185
|
+
path: packages/core
|
|
186
|
+
- name: cli
|
|
187
|
+
path: packages/cli
|
|
188
|
+
dependsOn:
|
|
189
|
+
- core
|
|
190
|
+
- name: app
|
|
191
|
+
path: packages/app
|
|
192
|
+
dependsOn:
|
|
193
|
+
- cli
|
|
194
|
+
</code></pre>
|
|
195
|
+
</div></div>
|
|
196
|
+
</div>
|
|
197
|
+
|
|
198
|
+
### Propagation policy
|
|
199
|
+
|
|
200
|
+
Write an entry as an object to choose how the upstream bump translates:
|
|
201
|
+
|
|
202
|
+
```json
|
|
203
|
+
{
|
|
204
|
+
"name": "cli",
|
|
205
|
+
"path": "packages/cli",
|
|
206
|
+
"dependsOn": [{ "name": "core", "propagate": "patch" }]
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
| Policy | A major in the dependency becomes | A minor becomes | A patch becomes |
|
|
211
|
+
| ---------------- | ------------------------------------- | --------------- | --------------- |
|
|
212
|
+
| `same` (default) | major | minor | patch |
|
|
213
|
+
| `major-on-major` | major | patch | patch |
|
|
214
|
+
| `patch` | patch | patch | patch |
|
|
215
|
+
| `none` | nothing — the dependent is not bumped | nothing | nothing |
|
|
216
|
+
|
|
217
|
+
A bare string is shorthand for `same`, so `"dependsOn": ["core"]` and `{ "name": "core", "propagate": "same" }` are identical. When several dependencies move at once under different policies, the strongest resulting bump wins.
|
|
218
|
+
|
|
219
|
+
### Updating dependents' manifests
|
|
220
|
+
|
|
221
|
+
Set `workspace.updateDependents` to `true` to rewrite the version constraint each dependent declares for the bumped package, staged in the same release commit:
|
|
222
|
+
|
|
223
|
+
```
|
|
224
|
+
● core 1.0.0 → 1.1.0 (minor)
|
|
225
|
+
● cli 2.3.0 → 2.4.0 (minor, dependency: core)
|
|
226
|
+
↳ core → 1.1.0 in cli/package.json
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
`cli/package.json` goes from `"core": "^1.0.0"` to `"core": "^1.1.0"`. Only `json` and `toml` manifests are rewritten, and only plain operator + version constraints — the operator is preserved. A `workspace:*`, `file:`/`git:` spec, `1.x` or a multi-part range carries intent a version pin would destroy, so it is left for you to handle.
|
|
230
|
+
|
|
231
|
+
<aside class="ferr-aside ferr-aside--note"><div class="ferr-aside__body"><p><code>dependsOn</code> differs from <code>sharedPaths</code>. Shared paths trigger a bump when files in the shared directory change. <code>dependsOn</code> triggers a bump when another <strong>package</strong> is released, regardless of which files changed.</p>
|
|
232
|
+
</div></aside>
|
|
233
|
+
|
|
234
|
+
### Dependency cycles
|
|
235
|
+
|
|
236
|
+
`dependsOn` must describe a directed acyclic graph. If two packages depend on each other — directly or transitively — there is no order in which to release them, so FerrFlow stops with error `E8003` and names the loop:
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
cycle detected: api → web → api
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
The check runs before any version is written, so a cyclic configuration never produces a partial release. Break the loop by removing one of the `dependsOn` edges. Otherwise the graph is released dependencies-first: a package is always released after the packages it depends on.
|
|
243
|
+
|
|
244
|
+
## Linked and fixed version groups
|
|
245
|
+
|
|
246
|
+
Sometimes packages must share a version number, not just cascade a bump. `linked` and `fixed` list groups of packages that move in lockstep:
|
|
247
|
+
|
|
248
|
+
```toml
|
|
249
|
+
[workspace]
|
|
250
|
+
linked = [["react", "react-dom"]]
|
|
251
|
+
fixed = [["@scope/a", "@scope/b", "@scope/c"]]
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
When **any** member of a group has a releasable commit, every member is bumped to the same version — the highest version the group would reach. A `feat` on one member and a `fix` on another release the whole group on the minor. Package names stay distinct; only the version is shared, and members with no commits of their own are pulled into the release at the shared version.
|
|
255
|
+
|
|
256
|
+
- **`linked`** — packages share a version line when they are released together (e.g. `react` and `react-dom` both go `1.2.3 → 1.2.4`).
|
|
257
|
+
- **`fixed`** — packages are locked to an identical version forever. It behaves like `linked`, and `ferrflow validate` additionally warns when a fixed group's versions have already drifted apart, so you catch a manual edit before the next release realigns them.
|
|
258
|
+
|
|
259
|
+
Each group must list at least two packages, and a package may appear in only one `linked` or `fixed` group. Naming a package that isn't defined in `package[]`, or listing one in two groups, stops the release with a clear error before anything is written — the same pre-flight guarantee as [dependency cycles](#dependency-cycles).
|
|
260
|
+
|
|
261
|
+
`linked`/`fixed` and `dependsOn` compose: a package that depends on a grouped package still receives its cascade bump after the group is aligned.
|
|
262
|
+
|
|
263
|
+
## Git tag format
|
|
264
|
+
|
|
265
|
+
By default, monorepo tags use the `{name}@v{version}` format:
|
|
266
|
+
|
|
267
|
+
```
|
|
268
|
+
api@v1.2.0
|
|
269
|
+
site@v0.4.1
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Configure this with the `tagTemplate` field:
|
|
273
|
+
|
|
274
|
+
<div class="ferr-tabs">
|
|
275
|
+
<div class="ferr-tab" data-label="JSON"><p class="ferr-tab__label">JSON</p><div class="ferr-tab__body"><pre><code class="language-json">{
|
|
276
|
+
"workspace": {
|
|
277
|
+
"tagTemplate": "{name}@v{version}"
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
</code></pre>
|
|
281
|
+
</div></div>
|
|
282
|
+
<div class="ferr-tab" data-label="TOML"><p class="ferr-tab__label">TOML</p><div class="ferr-tab__body"><pre><code class="language-toml">[workspace]
|
|
283
|
+
tag_template = "{name}@v{version}"
|
|
284
|
+
</code></pre>
|
|
285
|
+
</div></div>
|
|
286
|
+
<div class="ferr-tab" data-label="JSON5"><p class="ferr-tab__label">JSON5</p><div class="ferr-tab__body"><pre><code class="language-json5">{
|
|
287
|
+
workspace: {
|
|
288
|
+
tagTemplate: "{name}@v{version}",
|
|
289
|
+
},
|
|
290
|
+
}
|
|
291
|
+
</code></pre>
|
|
292
|
+
</div></div>
|
|
293
|
+
<div class="ferr-tab" data-label="YAML"><p class="ferr-tab__label">YAML</p><div class="ferr-tab__body"><pre><code class="language-yaml">workspace:
|
|
294
|
+
tagTemplate: "{name}@v{version}"
|
|
295
|
+
</code></pre>
|
|
296
|
+
</div></div>
|
|
297
|
+
</div>
|
|
298
|
+
|
|
299
|
+
For a single-package repo, the default is `v{version}` (no name prefix).
|
|
300
|
+
|
|
301
|
+
FerrFlow looks for the most recent tag matching the template to determine what commits are new.
|
|
302
|
+
|
|
303
|
+
## Independent cadences
|
|
304
|
+
|
|
305
|
+
Packages release independently. In a single `ferrflow release` run:
|
|
306
|
+
|
|
307
|
+
- `api` may bump from `1.2.0` → `1.3.0` (new `feat:` commit)
|
|
308
|
+
- `site` may bump from `0.4.0` → `0.4.1` (only `fix:` commits)
|
|
309
|
+
- `shared` may not release at all (only `chore:` commits)
|
|
310
|
+
|
|
311
|
+
## Per-package overrides
|
|
312
|
+
|
|
313
|
+
Each package can override the workspace-level `versioning` strategy and `tagTemplate`:
|
|
314
|
+
|
|
315
|
+
<div class="ferr-tabs">
|
|
316
|
+
<div class="ferr-tab" data-label="JSON"><p class="ferr-tab__label">JSON</p><div class="ferr-tab__body"><pre><code class="language-json">{
|
|
317
|
+
"workspace": {
|
|
318
|
+
"versioning": "semver",
|
|
319
|
+
"tagTemplate": "{name}@v{version}"
|
|
320
|
+
},
|
|
321
|
+
"package": [
|
|
322
|
+
{
|
|
323
|
+
"name": "api",
|
|
324
|
+
"path": "packages/api",
|
|
325
|
+
"versioning": "calver"
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
"name": "site",
|
|
329
|
+
"path": "packages/site",
|
|
330
|
+
"tagTemplate": "site-v{version}"
|
|
331
|
+
}
|
|
332
|
+
]
|
|
333
|
+
}
|
|
334
|
+
</code></pre>
|
|
335
|
+
</div></div>
|
|
336
|
+
<div class="ferr-tab" data-label="TOML"><p class="ferr-tab__label">TOML</p><div class="ferr-tab__body"><pre><code class="language-toml">[workspace]
|
|
337
|
+
versioning = "semver"
|
|
338
|
+
tag_template = "{name}@v{version}"
|
|
339
|
+
|
|
340
|
+
[[package]]
|
|
341
|
+
name = "api"
|
|
342
|
+
path = "packages/api"
|
|
343
|
+
versioning = "calver"
|
|
344
|
+
|
|
345
|
+
[[package]]
|
|
346
|
+
name = "site"
|
|
347
|
+
path = "packages/site"
|
|
348
|
+
tag_template = "site-v{version}"
|
|
349
|
+
</code></pre>
|
|
350
|
+
|
|
351
|
+
</div></div>
|
|
352
|
+
<div class="ferr-tab" data-label="JSON5"><p class="ferr-tab__label">JSON5</p><div class="ferr-tab__body"><pre><code class="language-json5">{
|
|
353
|
+
workspace: {
|
|
354
|
+
versioning: "semver",
|
|
355
|
+
tagTemplate: "{name}@v{version}",
|
|
356
|
+
},
|
|
357
|
+
package: [
|
|
358
|
+
{
|
|
359
|
+
name: "api",
|
|
360
|
+
path: "packages/api",
|
|
361
|
+
versioning: "calver",
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
name: "site",
|
|
365
|
+
path: "packages/site",
|
|
366
|
+
tagTemplate: "site-v{version}",
|
|
367
|
+
},
|
|
368
|
+
],
|
|
369
|
+
}
|
|
370
|
+
</code></pre>
|
|
371
|
+
</div></div>
|
|
372
|
+
<div class="ferr-tab" data-label="YAML"><p class="ferr-tab__label">YAML</p><div class="ferr-tab__body"><pre><code class="language-yaml">workspace:
|
|
373
|
+
versioning: semver
|
|
374
|
+
tagTemplate: "{name}@v{version}"
|
|
375
|
+
|
|
376
|
+
package:
|
|
377
|
+
|
|
378
|
+
- name: api
|
|
379
|
+
path: packages/api
|
|
380
|
+
versioning: calver
|
|
381
|
+
- name: site
|
|
382
|
+
path: packages/site
|
|
383
|
+
tagTemplate: "site-v{version}"
|
|
384
|
+
</code></pre>
|
|
385
|
+
|
|
386
|
+
</div></div>
|
|
387
|
+
</div>
|
|
388
|
+
|
|
389
|
+
<aside class="ferr-aside ferr-aside--tip"><div class="ferr-aside__body"><p>Use <code>ferrflow check</code> to preview exactly which packages would be released and at what version before committing to a release.</p>
|
|
390
|
+
</div></aside>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Installation
|
|
3
|
+
description: How to install FerrFlow locally or in CI.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Local installation
|
|
7
|
+
|
|
8
|
+
<div class="ferr-tabs">
|
|
9
|
+
<div class="ferr-tab" data-label="Cargo"><p class="ferr-tab__label">Cargo</p><div class="ferr-tab__body"><pre><code class="language-bash">cargo install ferrflow
|
|
10
|
+
</code></pre>
|
|
11
|
+
</div></div>
|
|
12
|
+
<div class="ferr-tab" data-label="npm"><p class="ferr-tab__label">npm</p><div class="ferr-tab__body"><pre><code class="language-bash">npm install -g @ferrlabs/ferrflow
|
|
13
|
+
# or as a dev dependency
|
|
14
|
+
npm install -D @ferrlabs/ferrflow
|
|
15
|
+
</code></pre>
|
|
16
|
+
</div></div>
|
|
17
|
+
<div class="ferr-tab" data-label="WASM (browser)"><p class="ferr-tab__label">WASM (browser)</p><div class="ferr-tab__body"><pre><code class="language-bash">npm install @ferrflow/wasm
|
|
18
|
+
</code></pre>
|
|
19
|
+
<p>Use FerrFlow directly in the browser — parse commits, compute version bumps, and generate changelogs client-side without a backend.</p>
|
|
20
|
+
</div></div>
|
|
21
|
+
<div class="ferr-tab" data-label="Binary"><p class="ferr-tab__label">Binary</p><div class="ferr-tab__body"><p>Download a pre-built binary from <a href="https://github.com/FerrLabs/FerrFlow/releases/latest">Releases</a>:</p>
|
|
22
|
+
<pre><code class="language-bash"># Linux x86_64
|
|
23
|
+
curl -L https://github.com/FerrLabs/FerrFlow/releases/latest/download/ferrflow-linux-x64.tar.gz | tar xz
|
|
24
|
+
sudo mv ferrflow /usr/local/bin/
|
|
25
|
+
</code></pre>
|
|
26
|
+
</div></div>
|
|
27
|
+
<div class="ferr-tab" data-label="Docker"><p class="ferr-tab__label">Docker</p><div class="ferr-tab__body"><pre><code class="language-bash">docker run --rm -v $(pwd):/repo ghcr.io/ferrlabs/ferrflow:latest check
|
|
28
|
+
</code></pre>
|
|
29
|
+
</div></div>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
## CI installation
|
|
33
|
+
|
|
34
|
+
The recommended way to use FerrFlow in CI is the GitHub Action — no installation step needed:
|
|
35
|
+
|
|
36
|
+
```yaml title=".github/workflows/release.yml"
|
|
37
|
+
- uses: FerrLabs/ferrflow@v5
|
|
38
|
+
env:
|
|
39
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
See [GitHub Actions](/docs/ci/github-actions) and [GitLab CI](/docs/ci/gitlab-ci) for complete examples.
|
|
43
|
+
|
|
44
|
+
## Verify
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
ferrflow --version
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Upgrading from v4
|
|
51
|
+
|
|
52
|
+
If you're following the documented GitHub Actions / GitLab CI setup (`GITHUB_TOKEN`/`CI_JOB_TOKEN` as an environment variable), no changes are required — just bump the action pin to `FerrLabs/ferrflow@v5` and the binary to v5.x.
|
|
53
|
+
|
|
54
|
+
The only breaking change in v5.0 is internal: FerrFlow no longer injects tokens into the remote URL when pushing. It now uses the standard git credential-helper protocol (`GIT_ASKPASS`). This is invisible to anyone using the recommended setup, but if you had a custom workflow that relied on URL-injected tokens — for example, a self-hosted runner with a pre-seeded `https://x-access-token:$TOKEN@github.com/...` remote — switch to setting `GITHUB_TOKEN` (or `FERRFLOW_TOKEN`) as an environment variable instead and FerrFlow handles the rest.
|
|
55
|
+
|
|
56
|
+
Releases since v5.2 are signed via Sigstore and ship a CycloneDX SBOM — see [Verifying releases](/docs/verifying-releases).
|