FerrFlow supporte six formats de fichier de configuration, recherch\u00e9s dans cet ordre :

  1. ferrflow.json
  2. ferrflow.json5
  3. ferrflow.toml
  4. ferrflow.ts (n\u00e9cessite tsx)
  5. ferrflow.js (n\u00e9cessite node)
  6. .ferrflow (JSON)

Si aucun fichier de configuration n'est trouv\u00e9, FerrFlow d\u00e9tecte automatiquement les fichiers de version courants dans le r\u00e9pertoire actuel.

Formats de configuration

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" },
      ],
    },
  ],
}

Configurations TypeScript et JavaScript

Les fichiers de config TypeScript (.ts) et JavaScript (.js) utilisent un export ESM par d\u00e9faut. L'export peut \u00eatre un objet ou une fonction asynchrone.

L'avantage principal des configs TS/JS : les hooks sous forme de fonctions. Au lieu de commandes shell, vous pouvez \u00e9crire des hooks natifs avec acc\u00e8s complet au contexte :

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' }],
    },
  ],
};

Objet de contexte des hooks

Les hooks en fonction re\u00e7oivent un objet de contexte avec ces champs :

Champ Type Description
package string Nom du package
oldVersion string Version avant le bump (vide pour la premi\u00e8re release)
newVersion string Version apr\u00e8s le bump
bumpType string major, minor, patch, ou none
tag string Nom complet du tag git
dryRun boolean Vrai si --dry-run est actif
packagePath string Chemin absolu vers la racine du package
channel string ou null Nom du channel de pr\u00e9-release
isPrerelease boolean Vrai si c'est une pr\u00e9-release
monorepo boolean Vrai si c'est une release monorepo
changelog string Section de changelog rendue pour ce bump (markdown)
commits array { hash, message, type?, scope?, breaking } par commit du bump
bumpedFiles array { path, format } pour chaque fichier modifié par la release
allPackages array { name, version, bump } pour chaque package publié dans ce batch
releaseUrl string ou null URL de la release forge créée — hooks postPublish uniquement, null sinon

commits, bumpedFiles et allPackages arrivent comme de vrais tableaux (parsés depuis du JSON), vous pouvez donc les itérer directement :

export default {
  workspace: {
    hooks: {
      postBump(ctx) {
        for (const c of ctx.commits) {
          if (c.breaking) console.log(`breaking: ${c.message}`);
        }
      },
    },
  },
};

Les hooks sous forme de commandes shell et de fonctions peuvent \u00eatre m\u00e9lang\u00e9s dans la m\u00eame config.

workspace

Paramètres globaux qui s'appliquent à tous les packages.

Champ Type Défaut Description
remote string "origin" Remote git vers lequel pousser
branch string auto-détecté Branche vers laquelle pousser (détectée depuis le HEAD du remote)
tagTemplate string "v{version}" ou "{name}@v{version}" Modèle de nommage des tags. Utilise les placeholders {version} et {name}. Par défaut v{version} pour les repos mono-package et {name}@v{version} pour les monorepos.
versioning string "semver" Stratégie de versionnage par défaut pour tous les packages
releaseCommitMode string "commit" Gestion du commit de release : "commit", "pr" ou "none"
releaseCommitScope string "grouped" Dans un monorepo où plusieurs packages sont bumpés en même temps, créer un seul commit "grouped" ou un commit "per-package". N'a d'effet que quand plusieurs packages bumpent.
forge string "auto" Forçage du forge git : "auto" détecte depuis l'URL du remote, et pour un hôte non reconnu il sonde l'API en HTTPS pour auto-détecter une instance auto-hébergée de GitLab, GitHub Enterprise ou Gitea / Forgejo (mis en cache, ~2s, best-effort). Renseignez "github", "gitlab", "gitea" (Gitea / Forgejo / Codeberg) ou "bitbucket" (Bitbucket Cloud) pour forcer un forge — nécessaire uniquement si l'hôte n'est pas joignable en HTTPS ou pour éviter le sondage. L'auth Gitea utilise GITEA_TOKEN / FORGEJO_TOKEN ; Bitbucket utilise BITBUCKET_TOKEN. Tous couvrent la création de release — sur Bitbucket, qui n'a pas d'objet release, la release est le tag annoté que FerrFlow pousse. Le mode PR reste GitHub/GitLab.
skipCi boolean dépend du mode Ajouter [skip ci] aux commits de release. Par défaut true en mode "commit", false sinon.
commitSkipMarkers array ["[skip ci]", "[ci skip]", "[no ci]", "[skip actions]", "[actions skip]"] Marqueurs qui font ignorer un commit par FerrFlow lors du calcul de la prochaine version. Comparaison insensible à la casse, sur la ligne de sujet uniquement.
autoMergeReleases boolean true Activer l'auto-merge sur les PR de release (uniquement en mode "pr")
recoverMissedReleases boolean false Comparer les fichiers versionnés au dernier tag plutôt qu'au seul dernier commit, pour rattraper des releases manquées plus tôt dans un monorepo.
branches array [] Associe des branches à des canaux de pré-release (voir Canaux de pré-release).
linked array [] Groupes de packages qui partagent une ligne de version lorsqu'ils sont publiés ensemble. Dès qu'un membre a un commit publiable, tous passent à la même version (la plus haute) (voir Groupes de versions liées et fixes).
fixed array [] Groupes de packages verrouillés sur une version identique en permanence. Comportement de linked ; ferrflow validate avertit lorsque les versions d'un groupe fixed ont divergé.
anonymous_telemetry boolean true Dépréciée et ignorée — la télémétrie a été retirée en v5.33 (détails). La clé (et son alias telemetry) reste acceptée pour que les configurations existantes restent valides.

Modèle de tag

Le champ tagTemplate contrôle le nommage des tags git. Placeholders disponibles :

Placeholder Description
{version} Le numéro de version (ex. 1.2.3)
{name} Le nom du package

JSON

{
  "workspace": {
    "tagTemplate": "v{version}"
  }
}

TOML

[workspace]
tag_template = "v{version}"

JSON5

{
  workspace: {
    tagTemplate: "v{version}",
  },
}

Pour les monorepos, utilisez {name} pour namespacer les tags par package :

JSON

{
  "workspace": {
    "tagTemplate": "{name}@v{version}"
  }
}

TOML

[workspace]
tag_template = "{name}@v{version}"

JSON5

{
  workspace: {
    tagTemplate: "{name}@v{version}",
  },
}

Mode de commit de release

Contrôle la façon dont FerrFlow gère le commit qui met à jour les fichiers de version et les changelogs.

Mode Comportement
"commit" Commit directement sur la branche courante et pousse (par défaut)
"pr" Ouvre une pull request de release persistante et la met à jour à chaque nouveau commit
"none" Crée uniquement les tags et les releases, ne commit pas les changements de fichiers

JSON

{
  "workspace": {
    "releaseCommitMode": "pr",
    "autoMergeReleases": true
  }
}

TOML

[workspace]
release_commit_mode = "pr"
auto_merge_releases = true

JSON5

{
  workspace: {
    releaseCommitMode: "pr",
    autoMergeReleases: true,
  },
}

En mode "pr", FerrFlow maintient une seule PR de release au long cours par branche cible. Il conserve une branche de release unique — ferrflow/release- — et à chaque nouveau commit il recalcule la version et le changelog puis force-push cette même branche : la PR ouverte est mise à jour sur place au lieu d'en ouvrir une nouvelle par version.

autoMergeReleases (par défaut true) active l'auto-merge sur cette PR ; il est réappliqué à chaque mise à jour et sans effet quand il est désactivé (la PR attend simplement un humain). Le mode PR est supporté sur GitHub et GitLab.

FerrFlow n'écrase pas le travail que vous poussez sur la branche de release : si la branche porte un commit qu'il n'a pas créé — tout ce qui n'est pas un commit chore(release):, comme un correctif de revue que vous avez poussé — il avertit et laisse la branche et la PR intactes pour ce run.

Stratégies de versionnage

FerrFlow supporte plusieurs stratégies de versionnage, configurables au niveau du workspace ou du package.

Stratégie Format Progression exemple
semver MAJOR.MINOR.PATCH 1.2.31.3.02.0.0
calver YYYY.MM.PATCH 2026.03.02026.03.12026.04.0
calver-short YY.MM.PATCH 26.03.026.03.1
calver-seq YYYY.MM.SEQ 2026.03.12026.03.2
sequential N 123
zerover 0.MINOR.PATCH 0.1.00.2.0 (n'atteint jamais 1.0)

JSON

{
  "workspace": {
    "versioning": "calver"
  }
}

TOML

[workspace]
versioning = "calver"

JSON5

{
  workspace: {
    versioning: "calver",
  },
}

Canaux de pré-release

Le tableau branches associe des noms de branches (ou des motifs glob) à des canaux de pré-release. Quand FerrFlow s'exécute sur une branche correspondant à une entrée, il release sur ce canal — par exemple 1.4.0-beta.1 au lieu de 1.4.0. C'est cette même association que l'option --channel de ferrflow check et ferrflow release surcharge ponctuellement.

Chaque entrée comporte :

Champ Type Description
name string Nom de branche ou motif glob (ex. "main", "release/*")
channel string ou false Nom de canal ("beta", "rc", …), ou false pour une release stable
prereleaseIdentifier string Stratégie de l'identifiant ajouté après le nom du canal

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

Définit un package à versionner. Vous pouvez en avoir un ou plusieurs.

Champ Requis Défaut Description
name oui Identifiant du package, utilisé dans le préfixe du tag git
path oui Chemin relatif vers le répertoire du package
changelog non {path}/CHANGELOG.md Chemin vers le fichier changelog
sharedPaths non [] Chemins qui déclenchent ce package lorsqu'ils sont modifiés
versioning non hérité du workspace Surcharger la stratégie de versionnage pour ce package
tagTemplate non hérité du workspace Surcharger le modèle de tag pour ce package

versionedFiles

Fichiers dans lesquels le numéro de version doit être mis à jour.

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 Fichier Champ mis à jour
toml Cargo.toml, pyproject.toml [package].version ou [project].version
json package.json version
xml pom.xml Premier élément
gradle build.gradle, build.gradle.kts version = "..."
helm Chart.yaml version et appVersion (si présent)
gomod go.mod Pas de mise à jour de fichier — la version vient uniquement des tags git
txt VERSION, VERSION.txt Contenu entier du fichier remplacé

Packages versionnés par tag uniquement

versionedFiles est optionnel. Omettez-le (ou mettez-le à []) pour les packages dont la version est communiquée entièrement via les tags git et les GitHub Releases — modules Go, images Docker, GitHub Actions, dépôts d'infrastructure.

JSON

{
  "package": [
    {
      "name": "my-action",
      "path": ".",
      "versionedFiles": []
    }
  ]
}

TOML

[[package]]
name = "my-action"
path = "."
versioned_files = []

JSON5

{
  package: [
    {
      name: "my-action",
      path: ".",
      versionedFiles: [],
    },
  ],
}

FerrFlow lit la version courante depuis le dernier tag git correspondant, calcule le prochain bump à partir des conventional commits, puis crée le tag, la GitHub Release, le changelog et les floating tags éventuels — sans toucher au moindre fichier source. Les hooks s'exécutent normalement, vous pouvez donc lancer docker build, docker push ou gh release upload depuis postPublish en utilisant FERRFLOW_NEW_VERSION.

hooks

Exécutez des commandes shell à des points clés du cycle de release. Les hooks peuvent être définis au niveau du workspace (par défaut pour tous les packages) ou par package (surcharge les hooks du workspace pour ce package).

Cycle de vie

calcul du bump
  ↓
pre_bump        ← valider l'état, vérifier les prérequis
  ↓
écriture des fichiers de version
  ↓
post_bump       ← modifier des fichiers supplémentaires avec la nouvelle version
  ↓
génération du changelog
  ↓
pre_commit      ← vérifier les changements stagés, lancer les linters
  ↓
git commit
  ↓
post_commit     ← réagir au commit de release
  ↓
pre_tag         ← smoke-test de l'arbre bumpé avant la pose du tag
  ↓
git tag
  ↓
post_tag        ← cargo publish avant le push (récupérable en cas d'échec)
  ↓
pre_publish     ← lancer les tests sur le commit taggé, builder les artefacts
  ↓
git push + création de la release
  ↓
post_publish    ← pousser les images Docker, notifier Slack, publier les packages

pre_release      (mode PR) après l'ouverture de la PR de release, avant le merge
on_success      ← une fois, après une release entièrement réussie
on_error        ← une fois, quand la release échoue ($FERRFLOW_ERROR_CODE)

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",
    },
  },
}
Champ Type Défaut Description
preBump string Exécuté après le calcul du bump, avant l'écriture des fichiers de version
postBump string Exécuté après l'écriture des fichiers de version
preCommit string Exécuté après le changelog, avant le commit git
postCommit string Exécuté après le commit de release, avant le tag
preTag string Exécuté après le commit, juste avant git tag
postTag string Exécuté après la création des tags, avant le push
prePublish string Exécuté après le commit+tag, avant le push
postPublish string Exécuté après le push et la création de la release
preRelease string Mode PR uniquement : après l'ouverture de la PR de release, avant le merge (une fois)
onSuccess string Exécuté une fois après une release entièrement réussie
onError string Exécuté une fois quand la release échoue ; définit FERRFLOW_ERROR_CODE (une fois)
onFailure string "abort" Stratégie — "abort" annule la release en cas d'échec de hook, "continue" affiche un avertissement

Variables d'environnement

Chaque hook reçoit ces variables :

Variable Description Exemple
FERRFLOW_PACKAGE Nom du package api
FERRFLOW_OLD_VERSION Version avant le bump (vide pour la première release) 1.2.3
FERRFLOW_NEW_VERSION Version après le bump 1.3.0
FERRFLOW_BUMP_TYPE major, minor, patch ou none minor
FERRFLOW_TAG Nom complet du tag git api@v1.3.0
FERRFLOW_DRY_RUN true si --dry-run est activé false
FERRFLOW_PACKAGE_PATH Chemin absolu vers la racine du package /home/user/repo/packages/api
FERRFLOW_IS_PRERELEASE true sur un canal de pré-release false
FERRFLOW_MONOREPO true sur une release monorepo false
FERRFLOW_CHANGELOG Section de changelog rendue pour ce bump ### Features\n- ...
FERRFLOW_COMMITS_JSON Tableau JSON de { hash, message, type?, scope?, breaking } [{"hash":"a1b2","message":"feat: x","type":"feat","breaking":false}]
FERRFLOW_BUMPED_FILES_JSON Tableau JSON de { path, format } modifiés par la release [{"path":"package.json","format":"json"}]
FERRFLOW_ALL_PACKAGES_JSON Tableau JSON de { name, version, bump } publiés dans ce batch [{"name":"api","version":"1.3.0","bump":"minor"}]
FERRFLOW_RELEASE_URL URL de la release forge créée (postPublish uniquement) https://github.com/acme/api/releases/tag/v1.3.0
FERRFLOW_ERROR_CODE Code d'erreur, défini uniquement pour onError E2005

FERRFLOW_COMMITS_JSON, FERRFLOW_BUMPED_FILES_JSON et FERRFLOW_ALL_PACKAGES_JSON sont des chaînes JSON — passez-les dans jq depuis vos hooks shell.

Pour les hooks exécutés une seule fois par run (preRelease, onSuccess, onError), les variables par package sont vides et FERRFLOW_TAG contient tous les tags publiés séparés par des virgules.

onFailure est la stratégie d'échec (abort / continue), pas une commande. La commande exécutée quand une release échoue est onError, qui reçoit le FERRFLOW_ERROR_CODE fautif.

Hooks par package

Les hooks au niveau du package remplacent les hooks du workspace pour ce package (ils ne sont pas fusionnés).

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",
      },
    },
  ],
}

Dans cet exemple, le package api exécute cargo test pour preBump (surchargeant l'echo du workspace) mais hérite du hook postPublish du workspace.

Comportement

  • --dry-run : les hooks sont affichés mais non exécutés.
  • --verbose : la sortie stdout/stderr des hooks est diffusée en direct. Sinon, la sortie n'est affichée qu'en cas d'échec.
  • Les fichiers modifiés par les hooks postBump ou preCommit sont automatiquement inclus dans le commit de release.

Exemples complets

Repo unique

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" },
      ],
    },
  ],
}