@qiwi/multi-semantic-release

October 16, 2023 ยท View on GitHub

hacky semantic-release for monorepos

Travis CI Maintainability Test Coverage npm (scoped)

This fork of dhoub/multi-semantic-release replaces setImmediate loops and execa.sync hooks with event-driven flow and finally makes possible to run the most release operations in parallel.
๐ŸŽ‰ ๐ŸŽ‰ ๐ŸŽ‰

Status

We're still using this lib as a part of our release infra, but we're gradually migrating to bulk-release. This means that we do not have many resources to develop this implementation actively, but we will continue to do it on a leftover basis.

Install

yarn add @qiwi/multi-semantic-release --dev

Usage

multi-semantic-release

Configuring Multi-Semantic-Release

multi-semantic-release can be configured a number of ways:

  • A .multi-releaserc file, written in YAML or JSON, with optional extensions: .yaml/ .yml/ .json/ .js
  • A multi-release.config.js file that exports an object
  • A multi-release key in the workspace root package.json

Alternatively some options may be set via CLI flags.

Note: CLI arguments take precedence over options configured in the configuration file.

Options

OptionTypeCLI FlagDescription
dryRunboolean--dry-runDry run mode.
logLevelString--log-levelSets the internal logger verbosity level: error, warn, info, debug, trace. Defaults to info.
debugboolean--debugOutput debugging information. Shortcut for --logLevel=debug.
silentboolean--silentTurns off any log outputs.
extendsString | ArrayN/AList of modules or file paths containing a shareable configuration. If multiple shareable configurations are set, they will be imported in the order defined with each configuration option taking precedence over the options defined in the previous.
sequentialInitboolean--sequential-initAvoid hypothetical concurrent initialization collisions.
sequentialPrepareboolean--sequential-prepareAvoid hypothetical concurrent preparation collisions. True by default.
firstParentboolean--first-parentApply commit filtering to current branch only.
ignorePrivateboolean--ignore-privateExclude private packages. True by default.
ignorePackagesString | Array--ignore-packagesPackages list to be ignored on bumping process (appended to the ones that already exist at package.json workspaces). If using the CLI flag, supply a comma seperated list of strings.
tagFormatString--tag-formatFormat to use when creating tag names. Should include "name" and "version" vars. Default: "${name}@${version}" which generates "package-name@1.0.0"
depsObjectN/ADependency handling, see below for possible values.

deps Options

OptionTypeCLI FlagDescription
bumpoverride | satisfy | inherit--deps.bumpDefine deps version updating rule. Allowed: override, satisfy, inherit. override by default.
releasepatch | minor | major | inherit--deps.releaseDefine release type for dependent package if any of its deps changes. Supported values: patch, minor, major, inherit. patch by default
prefix'^' | '~' | ''--deps.prefixOptional prefix to be attached to the next version if bump is set to override. '' by default.
pullTagsForPrereleaseboolean--deps.pullTagsForPrereleaseOptional flag to use release tags for evaluating prerelease version bumping. Normally, this option will lead to dumping dependencies to a version past what was just released and tagged by semantic release. Only set this option to true if you previously had a workflow that compensated for the previous bug behavior. 'false' by default.

Examples

  • Via multi-release key in the project's package.json file:
{
	"multi-release": {
		"ignorePackages": [
			"!packages/b/**",
			"!packages/c/**"
		],
		"deps": {
			"bump": "inherit"
		}
	}
}
  • Via .multi-releaserc file:
{
	"ignorePackages": [
		"!packages/b/**",
		"!packages/c/**"
	],
	"deps": {
		"bump": "inherit"
	}
}
  • Via CLI:
$ multi-semantic-release --ignore-packages=packages/a/**,packages/b/** --deps.bump=inherit

Configuring Semantic-Release

MSR requires semrel config to be added in any supported format for each package or/and declared in repo root (globalConfig is extremely useful if all the modules have the same strategy of release).
NOTE config resolver joins globalConfig and packageConfig during execution.

// Load the package-specific options.
const { options: pkgOptions } = await getConfig(dir);

// The 'final options' are the global options merged with package-specific options.
// We merge this ourselves because package-specific options can override global options.
const finalOptions = Object.assign({}, globalOptions, pkgOptions);

Make sure to have a workspaces attribute inside your package.json project file. In there, you can set a list of packages that you might want to process in the msr process, as well as ignore others. For example, let's say your project has 4 packages (i.e. a, b, c and d) and you want to process only a and d (ignore b and c). You can set the following structure in your package.json file:

{
	"name": "msr-test-yarn",
	"author": "Dave Houlbrooke <dave@shax.com",
	"version": "0.0.0-semantically-released",
	"private": true,
	"license": "0BSD",
	"engines": {
		"node": ">=8.3"
	},
	"workspaces": [
      "packages/*",
      "!packages/b/**",
      "!packages/c/**"
	],
	"release": {
		"plugins": [
			"@semantic-release/commit-analyzer",
			"@semantic-release/release-notes-generator"
		],
		"noCi": true
	}
}

You can also ignore it with the CLI:

$ multi-semantic-release --ignore-packages=packages/b/**,packages/c/**

You can also combine the CLI ignore options with the ! operator at each package inside workspaces attribute. Even though you can use the CLI to ignore options, you can't use it to set which packages to be released โ€“ i.e. you still need to set the workspaces attribute inside the package.json.

Verified usage examples

We use this tool to release our JS platform code inhouse (GitHub Enterprise + JB TeamCity) and for our OSS (GitHub + Travis CI). Guaranteed working configurations available in projects.

License

0BSD