relion 0.39.1 → 0.40.0

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,22 +1,23 @@
1
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://www.npmjs.com/package/relion"><img src="https://img.badgesize.io/https:/unpkg.com/relion/dist/index.js?label=Size&logo=hackthebox&logoColor=c97026&style=flat-square&color=c8c9f1&labelColor=363a4f" alt="runtime 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>
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset=".github/logo-light.png">
4
+ <img alt="logo" src=".github/logo-dark.png">
5
+ </picture>
6
+ <br>
7
+ <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=303145" alt="npm version"/></a>&nbsp;
8
+ <a href="https://www.npmjs.com/package/relion"><img src="https://img.badgesize.io/https:/unpkg.com/relion/dist/index.js?label=Size&logo=hackthebox&logoColor=c97026&style=flat-square&color=c8c9f1&labelColor=303145" alt="runtime size"/></a>&nbsp;
9
+ <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=303145" alt="license"></a>&nbsp;
10
+ <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%9B%20Bugs&style=flat-square&color=c8c9f1&labelColor=303145" alt="open bugs"></a>
8
11
  <br><br>
9
- <b>A minimal npm library for automating release workflow:</b> version bumping,<br>release commit & tag creation, and AI‑assisted changelog generation.
12
+ <b>A minimal npm library for automating release workflow:<br></b> version bumping, release commit & tag creation, and AI‑assisted changelog generation
10
13
  <br><br>
11
- <p>
12
- <b>
13
- <a href="#-installation">Installation</a>&nbsp; •&nbsp;
14
- <a href="#%EF%B8%8F-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>
14
+ <p><b>
15
+ <a href="#-installation">Installation</a>&nbsp; •&nbsp;
16
+ <a href="#%EF%B8%8F-cli-usage">CLI</a>&nbsp; •&nbsp;
17
+ <a href="#-api-usage">API</a>&nbsp; •&nbsp;
18
+ <a href="#%EF%B8%8F-workflow-steps">Workflow Steps</a>&nbsp; •&nbsp;
19
+ <a href="#-changelog-generation">Changelog Generation</a>
20
+ </b></p>
20
21
  <br>
21
22
  </div>
22
23
 
@@ -54,7 +55,7 @@ Examples:
54
55
  ------------------------------
55
56
  Current version: 0.36.1
56
57
  Current tag: v0.36.1
57
- Filtered commits: 16
58
+ Parsed commits: 16
58
59
  New version: 0.37.0
59
60
  New tag: v0.37.0
60
61
  Commit message: 'chore(release): v0.37.0'
@@ -83,7 +84,7 @@ import relion from 'relion';
83
84
  relion({
84
85
  flow: ['context', 'bump', 'commit', 'tag'],
85
86
  newVersion: '1.2.3',
86
- bumpFiles: [
87
+ bump: [
87
88
  'package.json', // uses default bumper
88
89
  // custom bumper (equivalent to the default bumper implementation)
89
90
  {
@@ -95,7 +96,6 @@ relion({
95
96
  contextFile: 'RELEASE.md',
96
97
  commitMessage: 'chore(release): {{tag}}',
97
98
  tagPrefix: 'v',
98
- commitFilters: [/^feat|^fix/, 'BREAKING CHANGE'],
99
99
  dryRun: false,
100
100
  });
101
101
  ```
@@ -104,11 +104,10 @@ relion({
104
104
 
105
105
  - `flow`: release workflow steps (`'context' | 'bump' | 'commit' | 'tag'`) (default: `[]`)
106
106
  - `newVersion`: set the new version explicitly
107
- - `bumpFiles`: files or custom bumpers for version update (default: [`'package.json'`])
107
+ - `bump`: files or custom bumpers for version update (default: [`'package.json'`])
108
108
  - `contextFile`: path to release context output file (default: `'RELEASE.md'`)
109
109
  - `commitMessage`: release commit message template (default: `'chore(release): {{tag}}'`)
110
110
  - `tagPrefix`: release tag prefix (default: `'v'`)
111
- - `commitFilters`: commit log filters (substring or RegExp; default: [`/^feat|^fix|^perf|^style|^docs/`, `'BREAKING CHANGE'`])
112
111
  - `dryRun`: run in dry mode (no modifications)
113
112
 
114
113
  ### Configuration via `package.json`
@@ -121,7 +120,7 @@ Relion can also be configured via `relion` field in `package.json`:
121
120
  "relion": {
122
121
  "commitMessage": "release(relion): {{tag}}",
123
122
  "tagPrefix": "",
124
- "bumpFiles": ["package.json",
123
+ "bump": ["package.json",
125
124
  {
126
125
  "file": "manifest.json",
127
126
  "pattern": "/(\"version\": )\".*\"/",
@@ -178,8 +177,9 @@ Recommended workflow:
178
177
  - [.github/instructions/changelog-format.instructions.md](.github/instructions/changelog-format.instructions.md)
179
178
  - [.github/prompts/generate-changelog.prompt.md](.github/prompts/generate-changelog.prompt.md)
180
179
  2. Run the context step to generate RELEASE.md: `pnpm relion -f`
181
- 3. Run the prompt in VSCode Copilot chat: `/generate-changelog`
182
- 4. Copilot produces a polished changelog entry based on the release context
180
+ 3. Review the release context, adjust as needed
181
+ 4. Run the prompt in VSCode Copilot chat: `/generate-changelog`
182
+ 5. Copilot produces a polished changelog entry based on the release context
183
183
 
184
184
  <details><summary>Generated changelog example (from the (*) release context using the instruction and prompt above; Gemini 3 Pro)</summary>
185
185
 
@@ -192,7 +192,7 @@ Recommended workflow:
192
192
  ### &emsp; 🩹 Fixes
193
193
  - **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)
194
194
 
195
- ##### &emsp;&emsp; [_Full Changelog_](https://github.com/kh4f/relion/compare/v0.32.1...v0.33.0) &ensp;•&ensp; _Jan 10, 2026_
195
+ ##### &emsp;&emsp; [Full Changelog](https://github.com/kh4f/relion/compare/v0.32.1...v0.33.0) &ensp;•&ensp; Jan 10, 2026
196
196
  ```
197
197
  </details>
198
198
 
package/dist/index.d.ts CHANGED
@@ -17,7 +17,7 @@ interface Config {
17
17
  *
18
18
  * @default ['package.json']
19
19
  */
20
- bumpFiles?: (Bumper | string)[];
20
+ bump?: (Bumper | string)[];
21
21
  /**
22
22
  * Path to the release context output file
23
23
  * @default 'RELEASE.md'
@@ -33,11 +33,6 @@ interface Config {
33
33
  * @default 'v'
34
34
  */
35
35
  tagPrefix?: string;
36
- /**
37
- * Commit log filters (substrings or regexes)
38
- * @default [/^feat|^fix|^perf|^style|^docs/, 'BREAKING CHANGE']
39
- */
40
- commitFilters?: (string | RegExp)[];
41
36
  /**
42
37
  * Run in dry mode without making any changes
43
38
  * @default false
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import{readFileSync as e,writeFileSync as t}from"node:fs";import{execSync as n,spawnSync as r}from"node:child_process";import{createInterface as i}from"node:readline";import a from"semver";const o=e=>n(`git log ${e?`${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()??``})),s=(e,t=[])=>e.filter(e=>t.some(t=>t instanceof RegExp?t.test(e.message):u(t).test(e.message))),c=(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 a.inc(t,n)??(()=>{throw Error(`Failed to increment version '${t}' with release type '${n}'`)})()},l=async()=>{let e=i({input:process.stdin,output:process.stdout});return await new Promise(t=>{e.question(`Press Enter to continue ('s' to skip): `,n=>{e.close(),t(n.trim()!==`s`)})})},u=e=>{let t=/^\/(.+)\/(\w*)$/.exec(e);return t?new RegExp(t[1],t[2]):new RegExp(e)},d=[`context`,`bump`,`commit`,`tag`],f={file:`package.json`,pattern:/(version.*?)\d[\w.+-]*/,replacement:`$1{{newVersion}}`},p={flow:[],newVersion:``,bumpFiles:[`package.json`],contextFile:`RELEASE.md`,commitMessage:`chore(release): {{tag}}`,tagPrefix:`v`,commitFilters:[/^feat|^fix|^perf|^style|^docs/,`BREAKING CHANGE`],dryRun:!1},m=async(e,n,r,i,a)=>{if(console.log(`\nAbout to write context to '${e.contextFile}'`),!await l()||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,spawnSync as r}from"node:child_process";import{createInterface as i}from"node:readline";import a from"semver";const o=e=>n(`git log ${e?`${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()??``})),s=(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 a.inc(t,n)??(()=>{throw Error(`Failed to increment version '${t}' with release type '${n}'`)})()},c=async()=>{let e=i({input:process.stdin,output:process.stdout});return await new Promise(t=>{e.question(`Press Enter to continue ('s' to skip): `,n=>{e.close(),t(n.trim()!==`s`)})})},l=e=>{let t=/^\/(.+)\/(\w*)$/.exec(e);return t?new RegExp(t[1],t[2]):new RegExp(e)},u=[`context`,`bump`,`commit`,`tag`],d={file:`package.json`,pattern:/(\bversion\b.*?)\d[\w.+-]*/,replacement:`$1{{newVersion}}`},f={flow:[],newVersion:``,bump:[`package.json`],contextFile:`RELEASE.md`,commitMessage:`chore(release): {{tag}}`,tagPrefix:`v`,dryRun:!1},p=async(e,n,r,i,a)=>{if(console.log(`\nAbout to write context to '${e.contextFile}'`),!await c()||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+=`## Commit Log\n\n\`\`\`\n${c}\n\`\`\``,t(e.contextFile,o,`utf8`)},h=async n=>{let r=n.bumpFiles.map(e=>typeof e==`string`?{...f,file:e}:e);console.log(`\nAbout to bump versions in files: ${r.map(e=>[e.file].flat()).flat().join(`, `)}`),await l()&&r.forEach(r=>{typeof r.pattern==`string`&&(r.pattern=u(r.pattern)),[r.file].flat().forEach(i=>{let a=e(i,`utf8`).replace(r.pattern,r.replacement.replace(`{{newVersion}}`,n.newVersion));n.dryRun||t(i,a,`utf8`)})})},g=async e=>{let t=`git commit -m "${e.commitMessage}"`;console.log(`\nAbout to commit changes: '${t}'`),await l()&&(e.dryRun||n(t,{stdio:`inherit`}))},_=async(e,t,r)=>{let i=`git tag ${r} -m "${e.commitMessage}"`,a=RegExp(`^${e.commitMessage.replace(r,t).replace(/[()]/g,`\\$&`)}$`),o=n(`git log -1 --format=%s`,{encoding:`utf8`}).trim(),s=``;a.test(o)&&(s+=`
5
- Latest commit is a release commit. Reusing the latest tag.`,i=`git tag ${t} -m "${o}" -f`),s+=`\nAbout to create a tag: '${i}'`,console.log(s),await l()&&(e.dryRun||n(i,{stdio:`inherit`}))};var v=async t=>{let n=JSON.parse(e(`package.json`,`utf8`));t={...n.relion,...t};let i={...p,...t};console.log(`-`.repeat(30)),!t.tagPrefix&&n.name.startsWith(`@`)&&(i.tagPrefix=`${n.name}@`);let a=n.version;console.log(`Current version: ${a}`);let l=r(`git`,[`describe`,`--match`,`${i.tagPrefix}[0-9]*.[0-9]*.[0-9]*`,`--abbrev=0`],{encoding:`utf8`}).stdout.trim();console.log(`Current tag: ${l}`);let u=s(o(l),i.commitFilters);console.log(`Filtered commits: ${u.length}`),i.newVersion||=c(u,a),console.log(`New version: ${i.newVersion}`);let f=`${i.tagPrefix}${i.newVersion}`;console.log(`New tag: ${f}`),i.commitMessage=i.commitMessage.replace(`{{tag}}`,f),console.log(`Commit message: '${i.commitMessage}'`);let v=n.repository;console.log(`Repo URL: ${v}`),console.log(`-`.repeat(30));for(let e of d.filter(e=>i.flow.includes(e)))await{context:()=>m(i,u,l,f,v),bump:()=>h(i),commit:()=>g(i),tag:()=>_(i,l,f)}[e]()};const y=e=>e;export{v as default,y as defineConfig};
4
+ `;let l=n.map(e=>`[${e.hash}] ${e.message}`).join(`\n${`-`.repeat(30)}\n`);o+=`## Commit Log\n\n\`\`\`\n${l}\n\`\`\``,t(e.contextFile,o,`utf8`)},m=async n=>{let r=n.bump.map(e=>typeof e==`string`?{...d,file:e}:e);console.log(`\nAbout to bump versions in files: ${r.map(e=>[e.file].flat()).flat().join(`, `)}`),await c()&&r.forEach(r=>{typeof r.pattern==`string`&&(r.pattern=l(r.pattern)),[r.file].flat().forEach(i=>{let a=e(i,`utf8`).replace(r.pattern,r.replacement.replace(`{{newVersion}}`,n.newVersion));n.dryRun||t(i,a,`utf8`)})})},h=async e=>{let t=`git commit -m "${e.commitMessage}"`;console.log(`\nAbout to commit changes: '${t}'`),await c()&&(e.dryRun||n(t,{stdio:`inherit`}))},g=async(e,t,r)=>{let i=`git tag ${r} -m "${e.commitMessage}"`,a=RegExp(`^${e.commitMessage.replace(r,t).replace(/[()]/g,`\\$&`)}$`),o=n(`git log -1 --format=%s`,{encoding:`utf8`}).trim(),s=``;a.test(o)&&(s+=`
5
+ Latest commit is a release commit. Reusing the latest tag.`,i=`git tag ${t} -m "${o}" -f`),s+=`\nAbout to create a tag: '${i}'`,console.log(s),await c()&&(e.dryRun||n(i,{stdio:`inherit`}))};var _=async t=>{let n=JSON.parse(e(`package.json`,`utf8`));t={...n.relion,...t};let i={...f,...t};console.log(`-`.repeat(30)),!t.tagPrefix&&n.name.startsWith(`@`)&&(i.tagPrefix=`${n.name}@`);let a=n.version;console.log(`Current version: ${a}`);let c=r(`git`,[`describe`,`--match`,`${i.tagPrefix}[0-9]*.[0-9]*.[0-9]*`,`--abbrev=0`],{encoding:`utf8`}).stdout.trim();console.log(`Current tag: ${c}`);let l=o(c);console.log(`Parsed commits: ${l.length}`),i.newVersion||=s(l,a),console.log(`New version: ${i.newVersion}`);let d=`${i.tagPrefix}${i.newVersion}`;console.log(`New tag: ${d}`),i.commitMessage=i.commitMessage.replace(`{{tag}}`,d),console.log(`Commit message: '${i.commitMessage}'`);let _=n.repository;console.log(`Repo URL: ${_}`),console.log(`-`.repeat(30));for(let e of u.filter(e=>i.flow.includes(e)))await{context:()=>p(i,l,c,d,_),bump:()=>m(i),commit:()=>h(i),tag:()=>g(i,c,d)}[e]()};const v=e=>e;export{_ as default,v as defineConfig};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "relion",
3
- "version": "0.39.1",
3
+ "version": "0.40.0",
4
4
  "description": "🔖 Modern Release Workflow Helper",
5
5
  "author": "kh4f <kh4f.dev@gmail.com>",
6
6
  "license": "MIT",
@@ -26,16 +26,16 @@
26
26
  "semver": "^7.7.4"
27
27
  },
28
28
  "devDependencies": {
29
- "@eslint/js": "^9.39.2",
30
- "@stylistic/eslint-plugin": "^5.7.1",
31
- "@types/node": "^25.2.1",
29
+ "@eslint/js": "^10.0.1",
30
+ "@stylistic/eslint-plugin": "^5.9.0",
31
+ "@types/node": "^25.3.0",
32
32
  "@types/semver": "^7.7.1",
33
- "eslint": "^9.39.2",
33
+ "eslint": "^10.0.2",
34
34
  "jiti": "^2.6.1",
35
35
  "tsdown": "^0.20.3",
36
36
  "tsx": "^4.21.0",
37
37
  "typescript": "^5.9.3",
38
- "typescript-eslint": "^8.54.0"
38
+ "typescript-eslint": "^8.56.1"
39
39
  },
40
40
  "scripts": {
41
41
  "build": "tsdown",