@dnbhq/release-config
v1.1.0
Published
Reusable release-it configuration for @davidsneighbour's projects.
Readme
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.
What it configures
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).
Installation
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.
Minimal setup
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": "[email protected]:dnbhq/example-package.git"
}
}Default behaviour
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.
Configure conventional changelog types and subscopes
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 instructionsConfigure patch-level groups
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;Override release-it settings
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;Built-in CITATION.cff hook
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.
Adding your own hooks
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.
Repository URL fallback
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;Custom package.json path
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;Build and test this package
npm install
npm run build
npm testnpm test runs the TypeScript build and then the test suite with Node's built-in test runner.
Test in another repository before publishing
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.
Suggested consumer configuration
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;