relion 0.34.0 → 0.34.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1 +1,141 @@
1
- # relion
1
+ <div align="center">
2
+ <img src=".github/logo.png" alt="logo"/>
3
+ <br><br>
4
+ <a href="https://www.npmjs.com/package/relion"><img src="https://img.shields.io/npm/v/relion?label=npm&logo=npm&style=flat-square&color=c8c9f1&labelColor=363a4f" alt="npm version"/></a>&nbsp;
5
+ <a href="https://bundlephobia.com/package/relion"><img src="https://img.shields.io/bundlephobia/minzip/relion?label=%F0%9F%93%A6%20Size&style=flat-square&color=c8c9f1&labelColor=363a4f" alt="bundle size"/></a>&nbsp;
6
+ <a href="https://github.com/kh4f/relion/blob/master/LICENSE"><img src="https://img.shields.io/github/license/kh4f/relion?style=flat-square&label=%F0%9F%9B%A1%EF%B8%8F%20License&color=c8c9f1&labelColor=363a4f" alt="license"></a>&nbsp;
7
+ <a href="https://github.com/kh4f/relion/issues?q=is%3Aissue+is%3Aopen+label%3Abug"><img src="https://img.shields.io/github/issues/kh4f/relion/bug?label=%F0%9F%90%9E%20Bugs&style=flat-square&color=c8c9f1&labelColor=363a4f" alt="open bugs"></a>
8
+ <br><br><br>
9
+ <b>A minimal npm library for automating release workflow:</b><br>version bumping, release commit & tag creation, and AI‑assisted changelog generation.
10
+ <br><br>
11
+ <p>
12
+ <b>
13
+ <a href="#-installation">Installation</a>&nbsp; •&nbsp;
14
+ <a href="#-cli-usage">CLI</a>&nbsp; •&nbsp;
15
+ <a href="#-api-usage">API</a>&nbsp; •&nbsp;
16
+ <a href="#%EF%B8%8F-workflow-steps">Workflow Steps</a>&nbsp; •&nbsp;
17
+ <a href="#-changelog-generation">Changelog Generation</a>
18
+ </b>
19
+ </p>
20
+ <br>
21
+ </div>
22
+
23
+ ## 📥 Installation
24
+
25
+ ```bash
26
+ pnpm add -D relion
27
+ ```
28
+
29
+ ## 🚀 CLI Usage
30
+ Running the CLI without arguments prints help
31
+
32
+ ```bash
33
+ $ pnpm relion
34
+
35
+ Usage: relion [options]
36
+
37
+ Options:
38
+ -b Bump the version
39
+ -f Prepare release context
40
+ -c Create a release commit
41
+ -t Create a release tag
42
+ -v <version> Set the new version explicitly
43
+ -d Run in dry run mode
44
+
45
+ Examples:
46
+ - `pnpm relion -bct` — bump version, create release commit and tag
47
+ - `pnpm relion -f` — generate release context
48
+ ```
49
+
50
+ ## 🧩 API Usage
51
+
52
+ ```ts
53
+ import relion from 'relion';
54
+
55
+ relion({
56
+ flow: ['bump', 'context', 'commit', 'tag'],
57
+ newVersion: '1.2.3',
58
+ bumpFiles: ['package.json'],
59
+ contextFile: 'RELEASE.md',
60
+ commitMessage: 'chore(release): {{tag}}',
61
+ tagPrefix: 'v',
62
+ dryRun: false,
63
+ });
64
+ ```
65
+
66
+ ### Options
67
+
68
+ - `flow`: release workflow steps (`'bump' | 'context' | 'commit' | 'tag'`) (default: `[]`)
69
+ - `newVersion`: set the new version explicitly
70
+ - `bumpFiles`: files or bumpers for version update (default: `['package.json']`)
71
+ - `contextFile`: path to release context output file (default: `'RELEASE.md'`)
72
+ - `commitMessage`: release commit message template (default: `'chore(release): {{tag}}'`)
73
+ - `tagPrefix`: release tag prefix (default: `'v'`)
74
+ - `commitFilters`: filters for selecting commits in release context (default: commits with types `feat`, `fix`, `perf`, `style`, `docs` or with `BREAKING CHANGE`)
75
+ - `dryRun`: run in dry mode (no modifications)
76
+
77
+ ## ♻️ Workflow Steps
78
+
79
+ - **Bump**: updates version in specified files
80
+ - **Context**: generates a file with upcoming release metadata and commit log
81
+ - **Commit**: creates a release commit (release context file is not committed)
82
+ - **Tag**: creates an annotated release tag
83
+
84
+ <details><summary>Generated release context example (*):</summary>
85
+
86
+ ```md
87
+ ---
88
+ version: 0.33.0
89
+ tag: v0.33.0
90
+ date: Jan 10, 2026
91
+ prevTag: v0.32.1
92
+ repoURL: https://github.com/kh4f/relion
93
+ ---
94
+
95
+ ## Commit Log
96
+
97
+ [8f29acf] fix(versioner): ensure breaking changes take priority over features in release type calculation
98
+
99
+ Previously, if commits contained both features and breaking changes, features would be checked last and could incorrectly override the 'major' release type with 'minor'.
100
+ ------------------------------
101
+ [e105d51] feat(config-merger): add `mergeConfigs` implementation and export
102
+
103
+ - Implement `mergeConfigs` to support merging config profiles in `config-merger.ts`
104
+ - Export `mergeConfigs` from `src/index.ts`
105
+ ------------------------------
106
+ ```
107
+ </details>
108
+
109
+ ## 📚 Changelog Generation
110
+
111
+ Relion does not format changelog itself — it generates a release context that can be used to generate a user‑friendly changelog using AI.
112
+
113
+ Recommended workflow:
114
+
115
+ 1. Set up GitHub Copilot instructions and prompt:
116
+ - [.github/instructions/changelog-format.instructions.md](.github/instructions/changelog-format.instructions.md)
117
+ - [.github/prompts/generate-changelog.prompt.md](.github/prompts/generate-changelog.prompt.md)
118
+ 2. Run the context step to generate RELEASE.md: `pnpm relion -f`
119
+ 3. Run the prompt in VSCode Copilot chat: `/generate-changelog`
120
+ 4. Copilot produces a polished changelog entry based on the release context
121
+
122
+ <details><summary>Generated changelog example (from the (*) release context using the instructions and prompt above; Gemini 3 Pro)</summary>
123
+
124
+ ```md
125
+ ## &ensp; [` 📦 v0.33.0 `](https://github.com/kh4f/relion/compare/v0.32.1...v0.33.0)
126
+
127
+ ### &emsp; 🎁 Features
128
+ - **Config merging utility**: added `mergeConfigs` implementation to support merging config profiles. [🡥](https://github.com/kh4f/relion/commit/e105d51)
129
+
130
+ ### &emsp; 🩹 Fixes
131
+ - **Correct release type calculation**: breaking changes now correctly take priority over features when determining the release type, preventing incorrect minor bumps. [🡥](https://github.com/kh4f/relion/commit/8f29acf)
132
+
133
+ ##### &emsp;&emsp; [_Full Changelog_](https://github.com/kh4f/relion/compare/v0.32.1...v0.33.0) &ensp;•&ensp; _Jan 10, 2026_
134
+ ```
135
+ </details>
136
+
137
+ </br>
138
+
139
+ <div align="center">
140
+ <b>MIT License © 2025-2026 <a href="https://github.com/kh4f">kh4f</a></b>
141
+ </div>
package/dist/cli.js CHANGED
@@ -1,10 +1,14 @@
1
1
  import e from"./index.js";const t=process.argv.slice(2).join(` `);t||(console.log(`Usage: relion [options]
2
2
 
3
3
  Options:
4
- -b Run bump step
5
- -f Run context step
6
- -c Run commit step
7
- -t Run tag step
8
- -v <version> Specify new version
9
- -d Dry run
4
+ -b Bump the version
5
+ -f Prepare release context
6
+ -c Create a release commit
7
+ -t Create a release tag
8
+ -v <version> Set the new version explicitly
9
+ -d Run in dry run mode
10
+
11
+ Examples:
12
+ - \`pnpm relion -bct\` — bump version, create release commit and tag
13
+ - \`pnpm relion -f\` — generate release context
10
14
  `),process.exit(0));const n=/-v (\S+)/.exec(t)?.[1],r=/-\w*d/.test(t);e({flow:[/-\w*b/.test(t)&&`bump`,/-\w*f/.test(t)&&`context`,/-\w*c/.test(t)&&`commit`,/-\w*t/.test(t)&&`tag`].filter(Boolean),...n&&{newVersion:n},...r&&{dryRun:r}});export{};
package/dist/index.d.ts CHANGED
@@ -1,22 +1,75 @@
1
1
  //#region src/types.d.ts
2
2
  interface Config {
3
+ /**
4
+ * Release workflow steps to execute (e.g. bump, context, commit, tag)
5
+ * @default []
6
+ */
3
7
  flow?: Step[];
8
+
9
+ /**
10
+ * Explicitly set the version for the upcoming release. If not provided, the version will be determined automatically based on conventional commit messages.
11
+ * @default ''
12
+ */
4
13
  newVersion?: string;
14
+
15
+ /**
16
+ * Files or bumpers for version update. Each item is either:
17
+ * - a bumper object specifying `file`, `pattern`, and `replacement`
18
+ * - a file name for which a default bumper exists (currently only 'package.json')
19
+ *
20
+ * @default ['package.json']
21
+ */
5
22
  bumpFiles?: (Bumper | string)[];
23
+
24
+ /**
25
+ * Path to the release context output file
26
+ * @default 'RELEASE.md'
27
+ */
6
28
  contextFile?: string;
29
+
30
+ /**
31
+ * Release commit message template
32
+ * @default 'chore(release): {{tag}}'
33
+ */
7
34
  commitMessage?: string;
35
+
36
+ /**
37
+ * Release tag prefix
38
+ * @default 'v'
39
+ */
8
40
  tagPrefix?: string;
41
+
42
+ /**
43
+ * Filters for selecting commits in the release context
44
+ * @default [
45
+ * c => /^feat|^fix|^perf|^style|^docs/.test(c.message),
46
+ * c => c.message.includes('BREAKING CHANGE')
47
+ * ]
48
+ */
9
49
  commitFilters?: ((commit: Commit) => boolean)[];
50
+
51
+ /**
52
+ * Run in dry mode without making any changes
53
+ * @default false
54
+ */
10
55
  dryRun?: boolean;
11
56
  }
12
57
  type Step = 'bump' | 'context' | 'commit' | 'tag';
13
58
  interface Bumper {
59
+ /** Path to the file to bump version in */
14
60
  file: string;
61
+
62
+ /** Regex to find the version string in the file */
15
63
  pattern: RegExp;
64
+
65
+ /** Replacement string for the version (use `{{newVersion}}` as a placeholder) */
16
66
  replacement: string;
17
67
  }
18
68
  interface Commit {
69
+ /** Commit hash */
19
70
  hash: string;
71
+
72
+ /** Full commit message */
20
73
  message: string;
21
74
  }
22
75
  //#endregion
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import{readFileSync as e,writeFileSync as t}from"node:fs";import{execSync as n}from"node:child_process";import r from"semver";const i=[{file:`package.json`,pattern:/("version": )".*"/,replacement:`$1"{{newVersion}}"`}],a={flow:[],newVersion:``,bumpFiles:i,contextFile:`RELEASE.md`,commitMessage:`chore(release): {{tag}}`,tagPrefix:`v`,commitFilters:[e=>/^feat|^fix|^perf|^style|^docs/.test(e.message),e=>e.message.includes(`BREAKING CHANGE`)],dryRun:!1},o=n=>{n.bumpFiles.forEach(r=>{let a=typeof r==`string`?i.find(e=>e.file===r)??(()=>{throw Error(`No default bumper found for file '${r}'`)})():r,o=e(a.file,`utf8`).replace(a.pattern,a.replacement.replace(`{{newVersion}}`,n.newVersion));console.log(`Updating version in '${a.file}'`),!n.dryRun&&t(a.file,o,`utf8`)})},s=(e,n,r,i,a)=>{if(console.log(`Outputting release context to '${e.contextFile}'`),e.dryRun)return;let o=``,s=`---\nversion: ${e.newVersion}\ntag: ${i}\ndate: ${new Date().toLocaleString(`en-US`,{month:`short`,day:`numeric`,year:`numeric`})}\nprevTag: ${r}\nrepoURL: ${a}
1
+ import{readFileSync as e,writeFileSync as t}from"node:fs";import{execSync as n}from"node:child_process";import r from"semver";const i=[{file:`package.json`,pattern:/("version": )".*"/,replacement:`$1"{{newVersion}}"`}],a={flow:[],newVersion:``,bumpFiles:[`package.json`],contextFile:`RELEASE.md`,commitMessage:`chore(release): {{tag}}`,tagPrefix:`v`,commitFilters:[e=>/^feat|^fix|^perf|^style|^docs/.test(e.message),e=>e.message.includes(`BREAKING CHANGE`)],dryRun:!1},o=n=>{n.bumpFiles.forEach(r=>{let a=typeof r==`string`?i.find(e=>e.file===r)??(()=>{throw Error(`No default bumper found for file '${r}'`)})():r,o=e(a.file,`utf8`).replace(a.pattern,a.replacement.replace(`{{newVersion}}`,n.newVersion));console.log(`Updating version in '${a.file}'`),!n.dryRun&&t(a.file,o,`utf8`)})},s=(e,n,r,i,a)=>{if(console.log(`Outputting release context to '${e.contextFile}'`),e.dryRun)return;let o=``,s=`---\nversion: ${e.newVersion}\ntag: ${i}\ndate: ${new Date().toLocaleString(`en-US`,{month:`short`,day:`numeric`,year:`numeric`})}\nprevTag: ${r}\nrepoURL: ${a}
2
2
  ---
3
3
  `;o+=s+`
4
- `;let c=n.map(e=>`[${e.hash}] ${e.message}`).join(`\n${`-`.repeat(30)}\n`);o+=`## Git Log\n\n\`\`\`\n${c}\n\`\`\``,t(e.contextFile,o,`utf8`)},c=e=>{let t=`git add -A && git reset ${e.contextFile} && git commit -m "${e.commitMessage}"`;console.log(`Committing changes: '${t}'`),!e.dryRun&&n(t,{stdio:`inherit`})},l=(e,t)=>{let r=`git tag ${t} -m "${e.commitMessage}"`;console.log(`Creating a tag: '${r}'`),!e.dryRun&&n(r,{stdio:`inherit`})},u=e=>n(`git log ${e}.. --format="%h %B---"`,{encoding:`utf8`}).trim().split(`---`).filter(Boolean).map(e=>/^(.+?) (.+)/s.exec(e.trim())).map(e=>({hash:e?.[1]??``,message:e?.[2].trim()??``})),d=(e,t)=>{let n=e.some(e=>e.message.includes(`BREAKING CHANGE`))?t.startsWith(`0.`)?`minor`:`major`:e.some(e=>/feat(\(.*?\))?:/.test(e.message))?`minor`:`patch`;return r.inc(t,n)??(()=>{throw Error(`Failed to increment version '${t}' with release type '${n}'`)})()};function f(t){let r=JSON.parse(e(`package.json`,`utf8`)),i={...a,...r.relion,...t};console.log(`-`.repeat(30));let f=r.version;console.log(`Current version: ${f}`);let p=n(`git describe --match "${i.tagPrefix}*" --abbrev=0`,{encoding:`utf8`}).trim();console.log(`Current tag: ${p}`);let m=u(p).filter(e=>i.commitFilters.some(t=>t(e)));console.log(`Filtered commits: ${m.length}`),i.newVersion||=d(m,f),console.log(`New version: ${i.newVersion}`);let h=`${i.tagPrefix}${i.newVersion}`;console.log(`New tag: ${h}`),i.commitMessage=i.commitMessage.replace(`{{tag}}`,h),console.log(`Commit message: '${i.commitMessage}'`);let g=r.repository;console.log(`Repo URL: ${g}`),console.log(`-`.repeat(30));for(let e of i.flow)({bump:()=>o(i),context:()=>s(i,m,p,h,g),commit:()=>c(i),tag:()=>l(i,h)})[e]()}const p=e=>e;export{f as default,p as defineConfig};
4
+ `;let c=n.map(e=>`[${e.hash}] ${e.message}`).join(`\n${`-`.repeat(30)}\n`);o+=`## Commit Log\n\n\`\`\`\n${c}\n\`\`\``,t(e.contextFile,o,`utf8`)},c=e=>{let t=`git add -A && git reset ${e.contextFile} && git commit -m "${e.commitMessage}"`;console.log(`Committing changes: '${t}'`),!e.dryRun&&n(t,{stdio:`inherit`})},l=(e,t)=>{let r=`git tag ${t} -m "${e.commitMessage}"`;console.log(`Creating a tag: '${r}'`),!e.dryRun&&n(r,{stdio:`inherit`})},u=e=>n(`git log ${e}.. --format="%h %B---"`,{encoding:`utf8`}).trim().split(`---`).filter(Boolean).map(e=>/^(.+?) (.+)/s.exec(e.trim())).map(e=>({hash:e?.[1]??``,message:e?.[2].trim()??``})),d=(e,t)=>{let n=e.some(e=>e.message.includes(`BREAKING CHANGE`))?t.startsWith(`0.`)?`minor`:`major`:e.some(e=>/feat(\(.*?\))?:/.test(e.message))?`minor`:`patch`;return r.inc(t,n)??(()=>{throw Error(`Failed to increment version '${t}' with release type '${n}'`)})()};function f(t){let r=JSON.parse(e(`package.json`,`utf8`)),i={...a,...r.relion,...t};console.log(`-`.repeat(30));let f=r.version;console.log(`Current version: ${f}`);let p=n(`git describe --match "${i.tagPrefix}*" --abbrev=0`,{encoding:`utf8`}).trim();console.log(`Current tag: ${p}`);let m=u(p).filter(e=>i.commitFilters.some(t=>t(e)));console.log(`Filtered commits: ${m.length}`),i.newVersion||=d(m,f),console.log(`New version: ${i.newVersion}`);let h=`${i.tagPrefix}${i.newVersion}`;console.log(`New tag: ${h}`),i.commitMessage=i.commitMessage.replace(`{{tag}}`,h),console.log(`Commit message: '${i.commitMessage}'`);let g=r.repository;console.log(`Repo URL: ${g}`),console.log(`-`.repeat(30));for(let e of i.flow)({bump:()=>o(i),context:()=>s(i,m,p,h,g),commit:()=>c(i),tag:()=>l(i,h)})[e]()}const p=e=>e;export{f as default,p as defineConfig};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "relion",
3
- "version": "0.34.0",
3
+ "version": "0.34.1",
4
4
  "description": "Release Workflow Helper",
5
5
  "author": "kh4f <kh4f.dev@gmail.com>",
6
6
  "license": "MIT",