FerrFlow supports six config file formats, searched in this order:
ferrflow.jsonferrflow.json5ferrflow.tomlferrflow.ts(requirestsx)ferrflow.js(requiresnode).ferrflow(JSON)
If no config file is found, FerrFlow auto-detects common version files in the current directory.
Config formats
TypeScript
export default {
workspace: {
tagTemplate: "v{version}",
},
package: [
{
name: "my-app",
path: ".",
changelog: "CHANGELOG.md",
versionedFiles: [
{ path: "Cargo.toml", format: "toml" },
],
},
],
};
JSON
{
"$schema": "https://ferrflow.com/schema/ferrflow.json",
"workspace": {
"tagTemplate": "v{version}"
},
"package": [
{
"name": "my-app",
"path": ".",
"changelog": "CHANGELOG.md",
"versionedFiles": [
{ "path": "Cargo.toml", "format": "toml" }
]
}
]
}
TOML
[workspace] tag_template = "v{version}"[[package]] name = "my-app" path = "." changelog = "CHANGELOG.md"
[[package.versioned_files]] path = "Cargo.toml" format = "toml"
JSON5
{
$schema: "https://ferrflow.com/schema/ferrflow.json",
workspace: {
tagTemplate: "v{version}",
},
package: [
{
name: "my-app",
path: ".",
changelog: "CHANGELOG.md",
versionedFiles: [
{ path: "Cargo.toml", format: "toml" },
],
},
],
}
TypeScript and JavaScript configs
TypeScript (.ts) and JavaScript (.js) config files use a default ESM export. The export can be a plain object or an async function.
The main advantage of TS/JS configs is function hooks. Instead of shell command strings, you can write hooks as native functions with full access to the hook context:
export default {
workspace: {
tagTemplate: "v{version}",
hooks: {
postPublish: async (ctx) => {
await fetch("https://hooks.slack.com/services/...", {
method: "POST",
body: JSON.stringify({
text: `Released ${ctx.package}@${ctx.newVersion}`,
}),
});
},
},
},
package: [
{
name: "my-app",
path: ".",
versionedFiles: [{ path: "package.json", format: "json" }],
},
],
};
Hook context object
Function hooks receive a context object with these fields:
| Field | Type | Description |
|---|---|---|
package |
string | Package name |
oldVersion |
string | Version before bump (empty on first release) |
newVersion |
string | Version after bump |
bumpType |
string | major, minor, patch, or none |
tag |
string | Full git tag name |
dryRun |
boolean | Whether --dry-run is set |
packagePath |
string | Absolute path to package root |
channel |
string or null | Pre-release channel name |
isPrerelease |
boolean | Whether this is a pre-release |
Shell string hooks and function hooks can be mixed in the same config. Shell strings still work in TS/JS configs.
workspace
Global settings that apply to all packages.
| Field | Type | Default | Description |
|---|---|---|---|
remote |
string | "origin" |
Git remote to push to |
branch |
string | auto-detected | Branch to push to (detected from remote HEAD) |
tagTemplate |
string | "v{version}" or "{name}@v{version}" |
Tag naming pattern. Uses {version} and {name} placeholders. Defaults to v{version} for single-package repos and {name}@v{version} for monorepos. |
versioning |
string | "semver" |
Default versioning strategy for all packages |
releaseCommitMode |
string | "commit" |
How to handle the release commit: "commit", "pr", or "none" |
releaseCommitScope |
string | "grouped" |
In a monorepo where several packages are bumped at once, whether to create a single "grouped" commit or one commit "per-package". Only matters when multiple packages bump. |
forge |
string | "auto" |
Git forge override: "auto" detects from the remote URL, "github" or "gitlab" force a forge (useful for self-hosted instances on custom domains). |
skipCi |
boolean | depends on mode | Add [skip ci] to release commits. Defaults to true when mode is "commit", false otherwise. |
commitSkipMarkers |
array | ["[skip ci]", "[ci skip]", "[no ci]", "[skip actions]", "[actions skip]"] |
Markers that cause FerrFlow to skip a commit when computing the next version. Matched case-insensitively, subject line only. |
autoMergeReleases |
boolean | true |
Enable auto-merge on release PRs (only applies when mode is "pr") |
recoverMissedReleases |
boolean | false |
Compare versioned files against the last tag instead of just the last commit, recovering releases missed earlier in a monorepo. |
floatingTags |
array | [] |
Floating tag levels to create on each release: "major", "minor". For example, ["major"] creates a v1 tag that always points to the latest v1.x.y release. |
orphanedTagStrategy |
string | "warn" |
How to handle tags pointing to orphaned commits after rebase + force-push: "warn", "treeHash", or "message" |
branches |
array | [] |
Map branches to pre-release channels (see Pre-release channels). |
anonymous_telemetry |
boolean | true |
Send anonymous usage statistics (details). No identifying data is collected. The old telemetry key is a deprecated alias — prefer anonymous_telemetry in new configs. |
Tag template
The tagTemplate field controls how git tags are named. Available placeholders:
| Placeholder | Description |
|---|---|
{version} |
The version number (e.g. 1.2.3) |
{name} |
The package name |
JSON
{
"workspace": {
"tagTemplate": "v{version}"
}
}
TOML
[workspace]
tag_template = "v{version}"
JSON5
{
workspace: {
tagTemplate: "v{version}",
},
}
For monorepos, use {name} to namespace tags per package:
JSON
{
"workspace": {
"tagTemplate": "{name}@v{version}"
}
}
TOML
[workspace]
tag_template = "{name}@v{version}"
JSON5
{
workspace: {
tagTemplate: "{name}@v{version}",
},
}
Floating tags
Floating tags are version aliases that always point to the latest release matching a given level. This is useful for GitHub Actions or Docker images where users reference v1 instead of v1.2.3.
JSON
{
"workspace": {
"floatingTags": ["major"]
}
}
TOML
[workspace]
floating_tags = ["major"]
JSON5
{
workspace: {
floatingTags: ["major"],
},
}
When releasing v1.2.3, FerrFlow creates or moves a v1 tag pointing to the same commit. With ["major", "minor"], both v1 and v1.2 tags are maintained.
If a floating tag would move backward (e.g. releasing a v1.1.0 hotfix when v1.2.0 already exists), FerrFlow blocks the release. Use --force to override this check.
Orphaned tag strategy
When a branch is rebased and force-pushed, existing tags may point to commits that are no longer part of the branch history. By default, FerrFlow warns about these orphaned tags and skips them. You can configure automatic recovery instead.
| Strategy | Behavior |
|---|---|
"warn" |
Log a warning identifying the orphaned tag and skip it (default) |
"treeHash" |
Attempt to find a commit on the current branch with the same file tree as the orphaned tag's commit |
"message" |
Attempt to find a commit on the current branch with the same commit message |
JSON
{
"workspace": {
"orphanedTagStrategy": "treeHash"
}
}
TOML
[workspace]
orphaned_tag_strategy = "treeHash"
JSON5
{
workspace: {
orphanedTagStrategy: "treeHash",
},
}
"treeHash" is the safest recovery option — it matches commits that have identical file contents, which is typical after a rebase that doesn't modify files. Use "message" when rebases also change the tree (e.g. squashing commits) but preserve the original message.
If recovery fails (no matching commit found within the last 1000 commits), FerrFlow falls back to warning and skipping the tag. In that case, re-tag manually:
git tag -f api@v1.2.0 <correct-commit>
Release commit mode
Controls how FerrFlow handles the commit that updates version files and changelogs.
| Mode | Behavior |
|---|---|
"commit" |
Commits directly to the current branch and pushes (default) |
"pr" |
Creates a release/ branch and opens a pull request |
"none" |
Only creates tags and releases, does not commit file changes |
JSON
{
"workspace": {
"releaseCommitMode": "pr",
"autoMergeReleases": true
}
}
TOML
[workspace]
release_commit_mode = "pr"
auto_merge_releases = true
JSON5
{
workspace: {
releaseCommitMode: "pr",
autoMergeReleases: true,
},
}
Versioning strategies
FerrFlow supports multiple versioning strategies, configurable at workspace or package level.
| Strategy | Format | Example progression |
|---|---|---|
semver |
MAJOR.MINOR.PATCH |
1.2.3 → 1.3.0 → 2.0.0 |
calver |
YYYY.MM.PATCH |
2026.03.0 → 2026.03.1 → 2026.04.0 |
calver-short |
YY.MM.PATCH |
26.03.0 → 26.03.1 |
calver-seq |
YYYY.MM.SEQ |
2026.03.1 → 2026.03.2 |
sequential |
N |
1 → 2 → 3 |
zerover |
0.MINOR.PATCH |
0.1.0 → 0.2.0 (never reaches 1.0) |
JSON
{
"workspace": {
"versioning": "calver"
}
}
TOML
[workspace]
versioning = "calver"
JSON5
{
workspace: {
versioning: "calver",
},
}
Pre-release channels
The branches array maps branch names (or glob patterns) to pre-release channels. When FerrFlow runs on a branch matching an entry, it releases on that channel — e.g. 1.4.0-beta.1 instead of 1.4.0. The same mapping is what --channel on ferrflow check and ferrflow release overrides ad-hoc.
Each entry has:
| Field | Type | Description |
|---|---|---|
name |
string | Branch name or glob pattern (e.g. "main", "release/*") |
channel |
string or false |
Channel name ("beta", "rc", …), or false for a stable release |
prereleaseIdentifier |
string | Strategy for the identifier appended after the channel name |
JSON
{
"workspace": {
"branches": [
{ "name": "main", "channel": false },
{ "name": "next", "channel": "beta" }
]
}
}
TOML
[[workspace.branches]] name = "main" channel = false
[[workspace.branches]] name = "next" channel = "beta"
JSON5
{
workspace: {
branches: [
{ name: "main", channel: false },
{ name: "next", channel: "beta" },
],
},
}
package
Defines a package to version. You can have one or many.
| Field | Required | Default | Description |
|---|---|---|---|
name |
yes | — | Package identifier, used in git tag prefix |
path |
yes | — | Relative path to the package directory |
changelog |
no | {path}/CHANGELOG.md |
Path to the changelog file |
sharedPaths |
no | [] |
Paths that trigger this package when changed |
dependsOn |
no | [] |
Package names this package depends on. When a dependency is bumped, this package gets a patch bump automatically. |
versioning |
no | inherited from workspace | Override versioning strategy for this package |
tagTemplate |
no | inherited from workspace | Override tag template for this package |
floatingTags |
no | inherited from workspace | Override floating tags for this package |
versionedFiles
Files where the version number should be updated.
JSON
{
"package": [
{
"name": "my-app",
"path": ".",
"versionedFiles": [
{ "path": "Cargo.toml", "format": "toml" },
{ "path": "npm/package.json", "format": "json" }
]
}
]
}
TOML
[[package]] name = "my-app" path = "."[[package.versioned_files]] path = "Cargo.toml" format = "toml"
[[package.versioned_files]] path = "npm/package.json" format = "json"
JSON5
{
package: [
{
name: "my-app",
path: ".",
versionedFiles: [
{ path: "Cargo.toml", format: "toml" },
{ path: "npm/package.json", format: "json" },
],
},
],
}
format |
File | Field updated |
|---|---|---|
toml |
Cargo.toml, pyproject.toml |
[package].version or [project].version |
json |
package.json |
version |
xml |
pom.xml |
First element |
gradle |
build.gradle, build.gradle.kts |
version = "..." |
helm |
Chart.yaml |
version and appVersion (when present) |
gomod |
go.mod |
No file update — version comes from git tags only |
txt |
VERSION, VERSION.txt |
Entire file content replaced |
Tag-only packages
versionedFiles is optional. Omit it (or set it to []) for packages whose version is communicated entirely through git tags and GitHub Releases — Go modules, Docker images, GitHub Actions, infrastructure repos.
JSON
{
"package": [
{
"name": "my-action",
"path": ".",
"versionedFiles": []
}
]
}
TOML
[[package]]
name = "my-action"
path = "."
versioned_files = []
JSON5
{
package: [
{
name: "my-action",
path: ".",
versionedFiles: [],
},
],
}
FerrFlow reads the current version from the latest matching git tag, computes the next bump from conventional commits, then creates the tag, the GitHub Release, the changelog and any floating tags — without touching any source file. Hooks still run normally, so you can docker build, docker push, or gh release upload from postPublish against FERRFLOW_NEW_VERSION.
hooks
Run shell commands at key points in the release lifecycle. Hooks can be defined at workspace level (defaults for all packages) or per package (overrides workspace hooks for that package).
Lifecycle
calculate bump
↓
pre_bump ← validate state, check prerequisites
↓
write version files
↓
post_bump ← modify additional files based on new version
↓
generate changelog
↓
pre_commit ← review staged changes, run linters
↓
git commit + tag
↓
pre_publish ← run tests against tagged commit, build artifacts
↓
git push + create release
↓
post_publish ← push Docker images, notify Slack, publish packages
Configuration
JSON
{
"workspace": {
"hooks": {
"preBump": "cargo test",
"postBump": "node scripts/sync-deps.js",
"preCommit": "cargo fmt --check",
"prePublish": "cargo build --release",
"postPublish": "make docker-push && ./scripts/notify.sh",
"onFailure": "abort"
}
}
}
TOML
[hooks]
pre_bump = "cargo test"
post_bump = "node scripts/sync-deps.js"
pre_commit = "cargo fmt --check"
pre_publish = "cargo build --release"
post_publish = "make docker-push && ./scripts/notify.sh"
on_failure = "abort"
JSON5
{
workspace: {
hooks: {
preBump: "cargo test",
postBump: "node scripts/sync-deps.js",
preCommit: "cargo fmt --check",
prePublish: "cargo build --release",
postPublish: "make docker-push && ./scripts/notify.sh",
onFailure: "abort",
},
},
}
| Field | Type | Default | Description |
|---|---|---|---|
preBump |
string | — | Run after bump calculation, before writing version files |
postBump |
string | — | Run after version files are written |
preCommit |
string | — | Run after changelog, before git commit |
prePublish |
string | — | Run after commit+tag, before push |
postPublish |
string | — | Run after push and release creation |
onFailure |
string | "abort" |
"abort" cancels the release on failure, "continue" prints a warning |
Environment variables
Every hook receives these variables:
| Variable | Description | Example |
|---|---|---|
FERRFLOW_PACKAGE |
Package name | api |
FERRFLOW_OLD_VERSION |
Version before bump (empty on first release) | 1.2.3 |
FERRFLOW_NEW_VERSION |
Version after bump | 1.3.0 |
FERRFLOW_BUMP_TYPE |
major, minor, patch, or none |
minor |
FERRFLOW_TAG |
Full git tag name | api@v1.3.0 |
FERRFLOW_DRY_RUN |
true if --dry-run is set |
false |
FERRFLOW_PACKAGE_PATH |
Absolute path to package root | /home/user/repo/packages/api |
Per-package hooks
Package-level hooks replace workspace-level hooks for that package (they are not merged).
JSON
{
"workspace": {
"hooks": {
"preBump": "echo releasing $FERRFLOW_PACKAGE",
"postPublish": "make notify"
}
},
"package": [
{
"name": "api",
"path": "packages/api",
"hooks": {
"preBump": "cargo test"
}
}
]
}
TOML
[hooks] pre_bump = "echo releasing $FERRFLOW_PACKAGE" post_publish = "make notify"[[package]] name = "api" path = "packages/api"
[package.hooks] pre_bump = "cargo test"
JSON5
{
workspace: {
hooks: {
preBump: "echo releasing $FERRFLOW_PACKAGE",
postPublish: "make notify",
},
},
package: [
{
name: "api",
path: "packages/api",
hooks: {
preBump: "cargo test",
},
},
],
}
In this example, the api package runs cargo test for preBump (overriding the workspace echo) but inherits the workspace postPublish hook.
Behavior
--dry-run: hooks are printed but not executed.--verbose: hook stdout/stderr is streamed live. Otherwise output is only shown on failure.- Files modified by
postBumporpreCommithooks are automatically included in the release commit.
publishers
Declarative replacement for the shell-script-in-postPublish-hook pattern. Each entry says "after the GitHub Release is created, push this package to that target." Available since v5.4.
Six built-in kinds cover the common publishing targets:
kind |
What it does | Idempotent on |
|---|---|---|
cargo |
cargo publish to crates.io or a custom registry |
"already uploaded" registry response |
npm |
npm publish to npmjs.org, GitHub Packages, or a custom registry |
"cannot publish over the previously published versions" |
docker |
docker buildx build --push with multi-arch + optional Sigstore |
docker manifest inspect on each requested tag |
helm |
helm package + helm push to an OCI registry |
helm show chart on the new version |
github-release-asset |
gh release upload --clobber of a sidecar file |
always re-uploads (clobber semantics) |
webhook |
Generic POST notifier with {name} / {version} / {tag} / {env:NAME} interpolation |
none — webhooks are fire-and-forget |
All kinds honor --dry-run (print the plan, do nothing) and the crash-resume checkpoint (a re-run after a partial failure picks up where it left off).
Registries
Token credentials are declared once at the workspace level. Each publisher references a registry by name; FerrFlow validates the token env var is exported before invoking the underlying tool.
JSON
{
"workspace": {
"registries": {
"kellnr": {
"url": "https://kellnr.example.com",
"tokenEnv": "CARGO_REGISTRIES_KELLNR_TOKEN"
},
"gh-packages": {
"url": "https://npm.pkg.github.com",
"tokenEnv": "NODE_AUTH_TOKEN"
}
}
}
}
TOML
[workspace.registries.kellnr] url = "https://kellnr.example.com" token_env = "CARGO_REGISTRIES_KELLNR_TOKEN"
[workspace.registries.gh-packages] url = "https://npm.pkg.github.com" token_env = "NODE_AUTH_TOKEN"
The token value itself never lives in the config file — only the env-var name does. This keeps ferrflow.json checked-in safely.
Cargo publisher
{
"package": [{
"name": "ferrlabs-auth",
"path": "crates/auth",
"versionedFiles": [{ "path": "Cargo.toml", "format": "toml" }],
"publishers": [
{ "kind": "cargo", "registry": "kellnr" }
]
}]
}
Omit registry to publish to crates.io. allowDirty: true adds --allow-dirty (mirrors cargo publish's own flag). noVerify: true adds --no-verify — set it for multi-crate batch releases so inter-dependent crates don't fail on registry-index propagation timing.
npm publisher
{
"package": [{
"name": "@ferrlabs/ui-react",
"path": "packages/react",
"publishers": [
{ "kind": "npm", "registry": "gh-packages", "tag": "next", "access": "public" }
]
}]
}
Omit registry to publish to npmjs.org. tag defaults to "latest". A scoped .npmrc is written into the package dir for the duration of the publish and removed on exit — your project's .npmrc is never modified.
Docker publisher
{
"package": [{
"name": "ferrlabs-auth-api",
"path": "crates/auth-api",
"publishers": [{
"kind": "docker",
"image": "ghcr.io/ferrlabs/auth-api",
"tags": ["{version}", "{major}", "{minor}", "latest"],
"platforms": ["linux/amd64", "linux/arm64"],
"sign": "sigstore"
}]
}]
}
{version}, {major}, {minor} expand from the release version. sign: "sigstore" runs cosign sign --yes against the produced manifest after push. Auth assumes you've already run @
docker login (FerrFlow doesn't manage docker credentials so it doesn't conflict with the rest of the CI).
Helm publisher
{
"package": [{
"name": "ferrvault-operator",
"path": "operator",
"publishers": [{
"kind": "helm",
"chart": "chart",
"registry": "oci://ghcr.io/ferrlabs/charts"
}]
}]
}
chart is the directory containing Chart.yaml, relative to the package path. Auth assumes helm registry login was done in CI.
GitHub release asset
{
"publishers": [
{ "kind": "github-release-asset", "path": "sbom.cdx.json" },
{ "kind": "github-release-asset", "path": "ferrflow-linux-x64.tar.gz.sig", "displayName": "linux-x64.sig" }
]
}
Re-uploads use --clobber so a retry replaces the previous file rather than failing. Picks up GITHUB_TOKEN from the environment, same as gh release upload.
Webhook
{
"publishers": [{
"kind": "webhook",
"url": "https://hooks.slack.com/services/...",
"body": { "text": "Released {name}@{version} :rocket:" },
"headers": { "Authorization": "Bearer {env:SLACK_TOKEN}" }
}]
}
{name}, {version}, {tag} and {env:NAME} are interpolated in the URL, body, and header values. Missing {env:NAME} is an error (a webhook with an unset bearer token must NOT send anonymously).
Extra flags (args)
Every command-based publisher — cargo, npm, docker, helm, github-release-asset — accepts an args array. The strings are appended verbatim to the underlying tool invocation, so you can pass options FerrFlow doesn't model natively without waiting for a new field.
{
"publishers": [
{ "kind": "cargo", "registry": "kellnr", "args": ["--locked"] },
{ "kind": "npm", "args": ["--provenance"] },
{ "kind": "docker", "image": "ghcr.io/ferrlabs/api", "args": ["--build-arg", "PROFILE=release"] }
]
}
For the docker publisher, args are inserted before the build-context positional (buildx rejects flags that follow the context argument). The webhook publisher has no args — it isn't a shelled-out command.
Deferring publishing to a separate job (deferPublish)
By default publishers run inline at the end of ferrflow release. That's fine when the release job already has what the publishers need — but docker, helm, and npm publishers need a build toolchain (buildx, helm, a built dist/) that a minimal release job often doesn't carry.
Set workspace.deferPublish: true and ferrflow release will skip the publishers; a separate ferrflow publish run executes them. You keep one config file:
{
"workspace": { "deferPublish": true },
"package": [{
"name": "my-operator",
"path": ".",
"versionedFiles": [{ "path": "go.mod", "format": "gomod" }],
"publishers": [
{ "kind": "docker", "image": "ghcr.io/acme/my-operator", "tags": ["{version}", "latest"] },
{ "kind": "helm", "chart": "charts/my-operator", "registry": "oci://ghcr.io/acme/charts" }
]
}]
}
release versions + tags as usual; a tag-triggered job that sets up the toolchain runs ferrflow publish (which always runs the publishers, ignoring deferPublish). See the ferrflow publish reference for the matching workflow.
Migrating from postPublish hooks
The publishers block is additive — your existing postPublish hooks keep working. Recommended order:
- Add a
publishersblock alongside your hook with--dry-runenabled in CI to preview what would be published. - Once the dry-run output matches what your hook does, switch CI to a real
ferrflow releaseand verify the live publish. - Delete the
postPublishhook.
The crash-resume checkpoint (see pipeline triggers) means a partially-failed publish is safely re-runnable — the publishers that already succeeded skip themselves on the second pass.
Complete examples
Single repo
JSON
{
"$schema": "https://ferrflow.com/schema/ferrflow.json",
"workspace": {
"tagTemplate": "v{version}"
},
"package": [
{
"name": "ferrflow",
"path": ".",
"changelog": "CHANGELOG.md",
"versionedFiles": [
{ "path": "Cargo.toml", "format": "toml" },
{ "path": "npm/package.json", "format": "json" }
]
}
]
}
TOML
[workspace] tag_template = "v{version}"[[package]] name = "ferrflow" path = "." changelog = "CHANGELOG.md"
[[package.versioned_files]] path = "Cargo.toml" format = "toml"
[[package.versioned_files]] path = "npm/package.json" format = "json"
JSON5
{
$schema: "https://ferrflow.com/schema/ferrflow.json",
workspace: {
tagTemplate: "v{version}",
},
package: [
{
name: "ferrflow",
path: ".",
changelog: "CHANGELOG.md",
versionedFiles: [
{ path: "Cargo.toml", format: "toml" },
{ path: "npm/package.json", format: "json" },
],
},
],
}
Monorepo
JSON
{
"$schema": "https://ferrflow.com/schema/ferrflow.json",
"workspace": {
"tagTemplate": "{name}@v{version}"
},
"package": [
{
"name": "api",
"path": "packages/api",
"changelog": "packages/api/CHANGELOG.md",
"sharedPaths": ["packages/shared/"],
"versionedFiles": [
{ "path": "packages/api/Cargo.toml", "format": "toml" }
]
},
{
"name": "site",
"path": "packages/site",
"changelog": "packages/site/CHANGELOG.md",
"sharedPaths": ["packages/shared/"],
"versionedFiles": [
{ "path": "packages/site/package.json", "format": "json" }
]
}
]
}
TOML
[workspace] tag_template = "{name}@v{version}"[[package]] name = "api" path = "packages/api" changelog = "packages/api/CHANGELOG.md" shared_paths = ["packages/shared/"]
[[package.versioned_files]] path = "packages/api/Cargo.toml" format = "toml"
[[package]] name = "site" path = "packages/site" changelog = "packages/site/CHANGELOG.md" shared_paths = ["packages/shared/"]
[[package.versioned_files]] path = "packages/site/package.json" format = "json"
JSON5
{
$schema: "https://ferrflow.com/schema/ferrflow.json",
workspace: {
tagTemplate: "{name}@v{version}",
},
package: [
{
name: "api",
path: "packages/api",
changelog: "packages/api/CHANGELOG.md",
sharedPaths: ["packages/shared/"],
versionedFiles: [
{ path: "packages/api/Cargo.toml", format: "toml" },
],
},
{
name: "site",
path: "packages/site",
changelog: "packages/site/CHANGELOG.md",
sharedPaths: ["packages/shared/"],
versionedFiles: [
{ path: "packages/site/package.json", format: "json" },
],
},
],
}