FerrFlow considère un repository comme un monorepo lorsque la configuration définit plus d'un package. Chaque package est versionné indépendamment en fonction de son propre historique git.

Isolation des packages

FerrFlow utilise les préfixes de chemin pour déterminer quels commits appartiennent à quel package. Seuls les commits qui touchent des fichiers sous path (ou sharedPaths) déclenchent une release pour ce package.

JSON

{
  "package": [
    {
      "name": "api",
      "path": "packages/api"
    },
    {
      "name": "site",
      "path": "packages/site"
    }
  ]
}

TOML

[[package]]
name = "api"
path = "packages/api"

[[package]] name = "site" path = "packages/site"

JSON5

{
  package: [
    {
      name: "api",
      path: "packages/api",
    },
    {
      name: "site",
      path: "packages/site",
    },
  ],
}

YAML

package:
  - name: api
    path: packages/api
  - name: site
    path: packages/site

Dépendances partagées

Si vous avez du code partagé entre packages (ex. une bibliothèque packages/shared/), déclarez-le comme entrée sharedPaths. Un changement dans un chemin partagé déclenche une release pour chaque package qui le référence :

JSON

{
  "package": [
    {
      "name": "api",
      "path": "packages/api",
      "sharedPaths": ["packages/shared/"]
    },
    {
      "name": "site",
      "path": "packages/site",
      "sharedPaths": ["packages/shared/"]
    }
  ]
}

TOML

[[package]]
name = "api"
path = "packages/api"
shared_paths = ["packages/shared/"]

[[package]] name = "site" path = "packages/site" shared_paths = ["packages/shared/"]

JSON5

{
  package: [
    {
      name: "api",
      path: "packages/api",
      sharedPaths: ["packages/shared/"],
    },
    {
      name: "site",
      path: "packages/site",
      sharedPaths: ["packages/shared/"],
    },
  ],
}

YAML

package:
  - name: api
    path: packages/api
    sharedPaths:
      - packages/shared/
  - name: site
    path: packages/site
    sharedPaths:
      - packages/shared/

Dependances entre packages

Utilisez dependsOn pour declarer qu'un package depend d'un autre. Quand une dependance est publiee, le package dependant recoit automatiquement un bump patch — meme si aucun de ses propres fichiers n'a change. La cascade est transitive : si app depend de cli et cli depend de core, publier core bumpe aussi cli et app.

JSON

{
  "package": [
    {
      "name": "core",
      "path": "packages/core"
    },
    {
      "name": "cli",
      "path": "packages/cli",
      "dependsOn": ["core"]
    },
    {
      "name": "app",
      "path": "packages/app",
      "dependsOn": ["cli"]
    }
  ]
}

TOML

[[package]]
name = "core"
path = "packages/core"

[[package]] name = "cli" path = "packages/cli" depends_on = ["core"]

[[package]] name = "app" path = "packages/app" depends_on = ["cli"]

JSON5

{
  package: [
    {
      name: "core",
      path: "packages/core",
    },
    {
      name: "cli",
      path: "packages/cli",
      dependsOn: ["core"],
    },
    {
      name: "app",
      path: "packages/app",
      dependsOn: ["cli"],
    },
  ],
}

YAML

package:
  - name: core
    path: packages/core
  - name: cli
    path: packages/cli
    dependsOn:
      - core
  - name: app
    path: packages/app
    dependsOn:
      - cli

Cycles de dépendances

dependsOn doit décrire un graphe orienté acyclique. Si deux packages dépendent l'un de l'autre — directement ou transitivement — il n'existe aucun ordre de release possible : FerrFlow s'arrête alors avec l'erreur E8003 en nommant la boucle :

cycle detected: api → web → api

La vérification s'exécute avant toute écriture de version : une configuration cyclique ne produit jamais de release partielle. Cassez la boucle en supprimant l'une des arêtes dependsOn. Sinon, le graphe est publié dépendances d'abord : un package est toujours publié après les packages dont il dépend.

Groupes de versions liées et fixes

Parfois, plusieurs packages doivent partager le même numéro de version, pas seulement propager un bump. linked et fixed listent des groupes de packages qui évoluent ensemble :

[workspace]
linked = [["react", "react-dom"]]
fixed  = [["@scope/a", "@scope/b", "@scope/c"]]

Dès qu'un membre d'un groupe a un commit publiable, tous les membres sont bumpés à la même version — la plus haute que le groupe atteindrait. Un feat sur un membre et un fix sur un autre publient tout le groupe sur le minor. Les noms de packages restent distincts ; seule la version est partagée, et les membres sans commit propre sont intégrés à la release à la version partagée.

  • linked — les packages partagent une ligne de version lorsqu'ils sont publiés ensemble (par exemple react et react-dom passent tous deux de 1.2.3 à 1.2.4).
  • fixed — les packages sont verrouillés sur une version identique en permanence. Le comportement est celui de linked, et ferrflow validate avertit en plus lorsque les versions d'un groupe fixed ont déjà divergé, pour repérer une édition manuelle avant que la prochaine release ne les réaligne.

Chaque groupe doit lister au moins deux packages, et un package ne peut appartenir qu'à un seul groupe linked ou fixed. Nommer un package absent de package[], ou en lister un dans deux groupes, arrête la release avec une erreur claire avant toute écriture — la même garantie amont que les cycles de dépendances.

linked/fixed et dependsOn se combinent : un package qui dépend d'un package groupé reçoit toujours son bump en cascade après l'alignement du groupe.

Format des tags git

Par défaut, les tags en monorepo utilisent le format {name}@v{version} :

api@v1.2.0
site@v0.4.1

Configurez cela avec le champ tagTemplate :

JSON

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

TOML

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

JSON5

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

YAML

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

Pour un repo mono-package, le défaut est v{version} (sans préfixe de nom).

FerrFlow recherche le tag le plus récent correspondant au modèle pour déterminer quels commits sont nouveaux.

Cadences indépendantes

Les packages sont publiés indépendamment. Dans une seule exécution de ferrflow release :

  • api peut passer de 1.2.01.3.0 (nouveau commit feat:)
  • site peut passer de 0.4.00.4.1 (uniquement des commits fix:)
  • shared peut ne pas être publié (uniquement des commits chore:)

Surcharges par package

Chaque package peut surcharger la stratégie de versioning et le tagTemplate du workspace :

JSON

{
  "workspace": {
    "versioning": "semver",
    "tagTemplate": "{name}@v{version}"
  },
  "package": [
    {
      "name": "api",
      "path": "packages/api",
      "versioning": "calver"
    },
    {
      "name": "site",
      "path": "packages/site",
      "tagTemplate": "site-v{version}"
    }
  ]
}

TOML

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

[[package]] name = "api" path = "packages/api" versioning = "calver"

[[package]] name = "site" path = "packages/site" tag_template = "site-v{version}"

JSON5

{
  workspace: {
    versioning: "semver",
    tagTemplate: "{name}@v{version}",
  },
  package: [
    {
      name: "api",
      path: "packages/api",
      versioning: "calver",
    },
    {
      name: "site",
      path: "packages/site",
      tagTemplate: "site-v{version}",
    },
  ],
}

YAML

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

package:

  • name: api path: packages/api versioning: calver
  • name: site path: packages/site tagTemplate: "site-v{version}"