Reusable release-it configuration for @davidsneighbour's projects.
The package provides a TypeScript config factory that keeps the usual release setup in one place while still allowing project-level overrides.
release-itwith npm publishing disabled by default.- Git release commits and tags in the format
chore(release): v${version}andv${version}. - GitHub releases using
GITHUB_TOKEN_CONTENT_PRIVATEby default. - Conventional changelog generation through
@release-it/conventional-changelog. - Changelog URLs generated from the consuming project's
package.jsonrepository.url. - Configurable conventional changelog types, scopes, and subscopes.
- A built-in
before:git:releasehook that updatesCITATION.cffwhen that file exists (see Built-in CITATION.cff hook).
Install the package together with its peer dependencies:
npm install --save-dev @dnbhq/release-config release-it @release-it/conventional-changelogThe package expects the consuming project to use ESM and a TypeScript release-it config.
Create .release-it.ts in the consuming repository:
import { createReleaseConfig } from "@dnbhq/release-config";
import type { Config } from "release-it";
const config: Config = createReleaseConfig();
export default config;Add scripts to package.json:
{
"scripts": {
"release": "release-it",
"release:dry": "release-it --dry-run"
}
}Make sure package.json contains repository information:
{
"repository": {
"type": "git",
"url": "git+https://github.com/dnbhq/example-package.git"
}
}The repository URL is normalised before it is passed to conventional changelog. These forms are supported:
{
"repository": "https://github.com/dnbhq/example-package.git"
}{
"repository": {
"type": "git",
"url": "git+https://github.com/dnbhq/example-package.git"
}
}{
"repository": {
"type": "git",
"url": "git@github.com:dnbhq/example-package.git"
}
}The default config is equivalent to this release-it setup:
import { createReleaseConfig } from "@dnbhq/release-config";
import type { Config } from "release-it";
const config: Config = createReleaseConfig({
changelogFile: "CHANGELOG.md",
githubTokenRef: "GITHUB_TOKEN_CONTENT_PRIVATE"
});
export default config;Default release rules:
feat,prompt,instructions, andskillare configured as minor-level groups.fix,perf,refactor,docs,style,test,build,ci, andchoreare configured as patch-level groups.- The subscopes
feat(fix),prompt(fix),instructions(fix), andskill(fix)are explicitly listed as changelog entries but excluded from the minor-type set.
Use scopes.minorTypes to define the commit types that should be treated as minor-level changelog groups:
import { createReleaseConfig } from "@dnbhq/release-config";
import type { Config } from "release-it";
const config: Config = createReleaseConfig({
scopes: {
minorTypes: ["feat", "prompt", "instructions", "skill"],
minorExclusionSubscopes: {
feat: ["fix"],
prompt: ["fix"],
instructions: ["fix"],
skill: ["fix"]
}
}
});
export default config;This keeps commits such as these visible in the changelog without letting the fix subscope act like a minor change:
feat(fix): repair generated changelog link
prompt(fix): correct release note generation prompt
instructions(fix): repair repository setup instructions
skill(fix): fix package export instructions
Use scopes.patchTypes when a project needs a narrower or broader changelog grouping:
import { createReleaseConfig } from "@dnbhq/release-config";
import type { Config } from "release-it";
const config: Config = createReleaseConfig({
scopes: {
patchTypes: ["fix", "docs", "ci", "chore"]
}
});
export default config;Use overrides for project-specific release-it settings. The merge is shallow for the main git, github, npm, and plugins objects. Hooks are merged by concatenation — see Built-in CITATION.cff hook for details.
import { createReleaseConfig } from "@dnbhq/release-config";
import type { Config } from "release-it";
const config: Config = createReleaseConfig({
overrides: {
git: {
requireCleanWorkingDir: true,
commitMessage: "chore(release): v${version}",
tagName: "v${version}"
},
github: {
release: true,
skipChecks: true
}
}
});
export default config;Every config produced by createReleaseConfig includes a before:git:release hook that updates CITATION.cff if that file exists in the project root. When the file is absent the hook exits silently, so repositories without a CITATION.cff are unaffected.
The hook sets three fields (only if the line already exists in the file):
| Field | Updated to |
|---|---|
version |
v<new-version> |
date-released |
today's date in yyyy-mm-dd format |
commit |
the HEAD commit hash at the point the hook runs (the last real code commit, before the release-it bump commit) |
After updating the file the hook stages it with git add CITATION.cff so it is included in the release commit.
Pass additional hooks through overrides.hooks. The built-in CITATION.cff hook is always placed first in the array so it runs before any project-level hooks. All other entries from overrides.hooks are appended in the order you supply them:
import { createReleaseConfig } from "@dnbhq/release-config";
import type { Config } from "release-it";
const config: Config = createReleaseConfig({
overrides: {
hooks: {
"before:git:release": ["node scripts/update-version-file.mjs"],
"after:git:release": ["echo release tagged"]
}
}
});
export default config;The resulting before:git:release array will be:
[
"<built-in CITATION.cff hook>",
"node scripts/update-version-file.mjs"
]
Hook arrays for different lifecycle events (e.g. after:git:release) are carried through as-is without any built-in entries from this package.
In unusual repositories where package.json does not contain a repository field, pass a fallback URL explicitly:
import { createReleaseConfig } from "@dnbhq/release-config";
import type { Config } from "release-it";
const config: Config = createReleaseConfig({
repository: {
fallbackUrl: "https://github.com/dnbhq/example-package"
}
});
export default config;By default, the config reads package.json from process.cwd(). For unusual repository layouts, pass an explicit path:
import { createReleaseConfig } from "@dnbhq/release-config";
import type { Config } from "release-it";
const config: Config = createReleaseConfig({
repository: {
packageJsonPath: "./packages/example/package.json",
fallbackUrl: "https://github.com/dnbhq/example-package"
}
});
export default config;npm install
npm run build
npm testnpm test runs the TypeScript build and then the test suite with Node's built-in test runner.
From this package directory:
npm packThen install the generated tarball in another repository:
npm install --save-dev ../release-config/dnbhq-release-config-0.1.0.tgzCreate or update .release-it.ts in that repository:
import { createReleaseConfig } from "@dnbhq/release-config";
import type { Config } from "release-it";
const config: Config = createReleaseConfig();
export default config;Run a dry release:
npx release-it --dry-runCheck that:
- the changelog links point to the repository defined in that project's
package.json; feat,prompt,instructions, andskillare grouped as expected;feat(fix),prompt(fix),instructions(fix), andskill(fix)do not behave like normal minor scopes;- GitHub release settings use the intended token reference.
For most projects, keep .release-it.ts small and project-specific only where necessary:
import { createReleaseConfig } from "@dnbhq/release-config";
import type { Config } from "release-it";
const config: Config = createReleaseConfig({
scopes: {
minorTypes: ["feat", "prompt", "instructions", "skill"],
minorExclusionSubscopes: {
feat: ["fix"],
prompt: ["fix"],
instructions: ["fix"],
skill: ["fix"]
}
}
});
export default config;