relion 0.44.3 → 0.46.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.
Files changed (3) hide show
  1. package/README.md +19 -26
  2. package/dist/cli.js +3 -3
  3. package/package.json +6 -5
package/README.md CHANGED
@@ -4,10 +4,9 @@
4
4
  <img alt="logo" src=".github/logo-light.png">
5
5
  </picture>
6
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=BAC4E2&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/cli.js?label=Size&logo=hackthebox&logoColor=c97026&style=flat-square&color=BAC4E2&labelColor=303145" alt="bundle size"/></a>&nbsp;
9
- <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=BAC4E2&labelColor=303145" alt="open bugs"></a>&nbsp;
10
- <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=BAC4E2&labelColor=303145" alt="license"></a>
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=BCC7EC&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/cli.js?label=Size&logo=hackthebox&logoColor=c97026&style=flat-square&color=BCC7EC&labelColor=303145" alt="bundle size"/></a>&nbsp;
9
+ <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=BCC7EC&labelColor=303145" alt="open bugs"></a>
11
10
  <br><br>
12
11
  <b>A zero‑config npm lib for automating the release workflow:<br></b> version bumping, release commit & tag creation, and AI‑assisted changelog generation
13
12
  <br><br>
@@ -16,7 +15,6 @@
16
15
  <a href="#%EF%B8%8F-release-workflow">Release Workflow</a>&nbsp; •&nbsp;
17
16
  <a href="#-changelog-generation">Changelog Generation</a>
18
17
  </b></p>
19
- <br>
20
18
  </div>
21
19
 
22
20
  ## 🕹️ Usage
@@ -36,10 +34,7 @@ Examples:
36
34
  bunx relion -d -v 1.2.3 Dry run with a custom version
37
35
  ```
38
36
 
39
- Notes:
40
37
  - `package.json` is **always included** in the bump list if exists
41
- - most files are bumped with a [generic pattern](https://regex101.com/r/t570Gh/1); `.rc` files use a dedicated one
42
- - changes are **not staged automatically** before committing
43
38
  - to create a tag without a prefix, use `-t ''`
44
39
 
45
40
  <details><summary>Example output of running <code>bunx relion</code>:</summary>
@@ -64,14 +59,17 @@ About to create a tag: 'git tag v0.43.0 -m "chore(release): v0.43.0"'
64
59
 
65
60
  ## ♻️ Release Workflow
66
61
 
67
- 1. **Context**: generates a `RELEASE.md` file with upcoming release metadata and commit log
68
- 2. **Bump**: updates version in specified files
69
- 3. **Commit**: creates a release commit
62
+ 1. **Context**: generates a `RELEASE.md` file with upcoming release metadata and commit log
63
+ The log is [automatically filtered](tests/context.test.ts) to exclude non-user-facing commits.
64
+ 2. **Bump**: updates version in specified files
65
+ Most files are bumped with a [generic pattern](https://regex101.com/r/t570Gh/1); `.rc` files use a dedicated one.
66
+ 3. **Commit**: creates a release commit
67
+ Changes are **not staged automatically** before committing, unless `-y` is passed.
70
68
  4. **Tag**: creates an annotated release tag
71
69
 
72
70
  <details><summary>Generated release context example (*):</summary>
73
71
 
74
- ```md
72
+ ```markdown
75
73
  ---
76
74
  tag: v0.33.0
77
75
  prevTag: v0.32.1
@@ -94,18 +92,19 @@ Previously, if commits contained both features and breaking changes, features wo
94
92
 
95
93
  ## 📋 Changelog Generation
96
94
 
97
- Relion doesn’t format the changelog itself — instead, it generates a release context that you can turn into a polished changelog using AI.
95
+ Relion doesn’t format the changelog itself. Instead, it generates a `RELEASE.md` file with release metadata and commit log, and provides a [`generate-changelog`](skills/generate-changelog/SKILL.md) skill to turn that context into a polished changelog entry with AI.
98
96
 
99
- Example workflow using GitHub Copilot:
97
+ Recommended workflow:
100
98
 
101
- 1. Set up the [instruction](.github/instructions/changelog-format.instructions.md) and [prompt](.github/prompts/generate-changelog.prompt.md)
99
+ 1. Install the skill: `bunx skills add kh4f/relion [-g]`
100
+ (see the [`skills` CLI docs](https://www.npmjs.com/package/skills))
102
101
  2. Run Relion to generate `RELEASE.md`
103
- 3. Review the release context
104
- 4. Run `/generate-changelog` in VS Code Copilot chat
102
+ 3. Review the generated release context
103
+ 4. Ask your AI agent to generate a changelog
105
104
 
106
- <details><summary>Generated changelog example (from the (*) release context using the instruction and prompt above; Gemini 3 Pro)</summary>
105
+ <details><summary>Generated changelog example (from the (*) release context; Gemini 3 Pro)</summary>
107
106
 
108
- ```md
107
+ ```markdown
109
108
  ## &ensp; [` 📦 v0.33.0 `](https://github.com/kh4f/relion/compare/v0.32.1...v0.33.0)
110
109
 
111
110
  ### &emsp; 🎁 Features
@@ -116,10 +115,4 @@ Example workflow using GitHub Copilot:
116
115
 
117
116
  ##### &emsp;&emsp; [Full Changelog](https://github.com/kh4f/relion/compare/v0.32.1...v0.33.0) &ensp;•&ensp; Jan 10, 2026
118
117
  ```
119
- </details>
120
-
121
- </br>
122
-
123
- <div align="center">
124
- <b>MIT License © 2025-2026 <a href="https://github.com/kh4f">kh4f</a></b>
125
- </div>
118
+ </details>
package/dist/cli.js CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import{execSync as e,spawnSync as t}from"node:child_process";import{existsSync as n,readFileSync as r,writeFileSync as i}from"node:fs";import{createInterface as a}from"node:readline";import o from"semver";const s=()=>{let t=e(`git config --get remote.origin.url`,{encoding:`utf8`}).trim(),n=/(github\.com.*?)(\.git)?$/.exec(t)?.[1]??``;return{url:n,name:n.split(`/`).at(-1)??``}},c=t=>e(`git log ${t?`${t}..`:``} --format="%h %B---" .`,{encoding:`utf8`}).trim().split(`---`).filter(Boolean).map(e=>/^(.+?) (.+)/s.exec(e.trim())).map(e=>({hash:e?.[1]??``,message:e?.[2].trim()??``})),l=(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 o.inc(t,n)??(()=>{throw Error(`Failed to increment version '${t}' with release type '${n}'`)})()},u=async(e,t=!1)=>{if(t)return!0;let n=a({input:process.stdin,output:process.stdout});return await new Promise(t=>{n.question(e,e=>{n.close(),t(e.trim()!==`s`)})})},d={bump:[`package.json`],newVersion:``,tagPrefix:`v`,dryRun:!1,yes:!1},f=[{filePattern:/\.rc$/,bump:(e,t)=>e.replace(/(\b(FileVersion|ProductVersion)\b.*?)\d[\w.+-]*/g,`$1${t}`).replace(/(\b(FILEVERSION|PRODUCTVERSION)\b.*?)\d[\w,+-]*/g,`$1${(/^\d+\.\d+\.\d+/.exec(t)?.[0]??``).replace(/\./g,`,`)+`,0`}`)},{filePattern:/.*/,bump:(e,t)=>e.replace(/(\bversion\b.*?)\d[\w.+-]*/,`$1${t}`)}],p=async(e,t,n,r,a)=>{if(!await u(`About to write context to 'RELEASE.md'`,e.yes)||e.dryRun)return;let o=``,s=`---\ntag: ${r}\nprevTag: ${n}\ndate: ${new Date().toLocaleString(`en-US`,{month:`short`,day:`numeric`,year:`numeric`})}\nrepoURL: ${a}
2
+ import{execSync as e,spawnSync as t}from"node:child_process";import{existsSync as n,readFileSync as r,writeFileSync as i}from"node:fs";import{createInterface as a}from"node:readline";import o from"semver";const s=()=>{let t=e(`git config --get remote.origin.url`,{encoding:`utf8`}).trim(),n=/(github\.com.*?)(\.git)?$/.exec(t)?.[1]??``;return{url:n,name:n.split(`/`).at(-1)??``}},c=t=>e(`git log ${t?`${t}..`:``} --format="%h %B---" .`,{encoding:`utf8`}).trim().split(`---`).filter(Boolean).map(e=>/^(.+?) (.+)/s.exec(e.trim())).map(e=>({hash:e?.[1]??``,message:e?.[2].trim()??``})),l=(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 o.inc(t,n)??(()=>{throw Error(`Failed to increment version '${t}' with release type '${n}'`)})()},u=async(e,t=!1)=>{if(t)return!0;let n=a({input:process.stdin,output:process.stdout});return await new Promise(t=>{n.question(e,e=>{n.close(),t(e.trim()!==`s`)})})},d={bump:[`package.json`],newVersion:``,tagPrefix:`v`,commitsExclude:[/^(ci|build|test)\(/,/^chore\(deps\)(?!!)/],dryRun:!1,yes:!1},f=[{filePattern:/\.rc$/,bump:(e,t)=>e.replace(/(\b(FileVersion|ProductVersion)\b.*?)\d[\w.+-]*/g,`$1${t}`).replace(/(\b(FILEVERSION|PRODUCTVERSION)\b.*?)\d[\w,+-]*/g,`$1${(/^\d+\.\d+\.\d+/.exec(t)?.[0]??``).replace(/\./g,`,`)+`,0`}`)},{filePattern:/.*/,bump:(e,t)=>e.replace(/(\bversion\b.*?)\d[\w.+-]*/,`$1${t}`)}],p=async(e,t,n,r,a)=>{if(e.yes||!await u(`About to write context to 'RELEASE.md'`,e.yes)||e.dryRun)return;let o=``,s=`---\ntag: ${r}\nprevTag: ${n}\ndate: ${new Date().toLocaleString(`en-US`,{month:`short`,day:`numeric`,year:`numeric`})}\nrepoURL: ${a}
3
3
  ---
4
4
  `;o+=s+`
5
- `;let c=t.map(e=>`[${e.hash}] ${e.message}`).join(`\n${`-`.repeat(30)}\n`);o+=`## Commit Log\n\n\`\`\`\n${c}\n\`\`\``,i(`RELEASE.md`,o,`utf8`)},m=async e=>{let t=e.bump.filter(n);await u(`About to bump version in files: ${t.join(`, `)}`,e.yes)&&t.forEach(t=>{let n=f.find(e=>e.filePattern.test(t));if(!n)return console.warn(`No matching bumper found for file '${t}', skipping...`);let a=r(t,`utf8`),o=n.bump(a,e.newVersion);e.dryRun||i(t,o,`utf8`)})},h=async(t,n)=>{let r=`git commit -m "${n}"`;await u(`About to commit changes: '${r}'`,t.yes)&&(t.dryRun||e(r,{stdio:`inherit`}))},g=async(t,n,r)=>{let i=`git tag ${n} -m "${r}"`;await u(`About to create a tag: '${i}'`,t.yes)&&(t.dryRun||e(i,{stdio:`inherit`}))},_=async e=>{let n=s();console.log(`Project: ${n.name}`),console.log(`Repo: ${n.url}`);let r={...d,...e,bump:[...d.bump,...e.bump??[]]},i=t(`git`,[`describe`,`--match`,`${r.tagPrefix}[0-9]*.[0-9]*.[0-9]*`,`--abbrev=0`],{encoding:`utf8`}).stdout.trim();console.log(`Current tag: ${i}`);let a=/\d+\.\d+\.\d+.*/.exec(i)?.[0]??`0.0.0`;console.log(`Current version: ${a}`);let o=c(i);console.log(`Parsed commits: ${o.length}`),r.newVersion||=l(o,a),console.log(`New version: ${r.newVersion}`);let u=`${r.tagPrefix}${r.newVersion}`;console.log(`New tag: ${u}`);let f=`chore(release): ${u}`;console.log(`Commit message: '${f}'`),console.log(`-`.repeat(30)),console.log(`
6
- ('' to continue / 's' to skip)`),await p(r,o,i,u,n.url),await m(r),await h(r,f),await g(r,u,f)},v=process.argv.slice(2).join(` `);v.includes(`-h`)&&(console.log(`Usage: relion [options]
5
+ `;let c=t.map(e=>`[${e.hash}] ${e.message}`).join(`\n${`-`.repeat(30)}\n`);o+=`## Commit Log\n\n\`\`\`\n${c}\n\`\`\``,i(`RELEASE.md`,o,`utf8`)},m=async e=>{let t=e.bump.filter(n);await u(`About to bump version in files: ${t.join(`, `)}`,e.yes)&&t.forEach(t=>{let n=f.find(e=>e.filePattern.test(t));if(!n)return console.warn(`No matching bumper found for file '${t}', skipping...`);let a=r(t,`utf8`),o=n.bump(a,e.newVersion);e.dryRun||i(t,o,`utf8`)})},h=async(t,n)=>{let r=`${t.yes?`git add -A && `:``}git commit -m "${n}"`;await u(`About to commit changes: '${r}'`,t.yes)&&(t.dryRun||e(r,{stdio:`inherit`}))},g=async(t,n,r)=>{let i=`git tag ${n} -m "${r}"`;await u(`About to create a tag: '${i}'`,t.yes)&&(t.dryRun||e(i,{stdio:`inherit`}))},_=async e=>{let n=s();console.log(`Project: ${n.name}`),console.log(`Repo: ${n.url}`);let r={...d,...e,bump:[...d.bump,...e.bump??[]]},i=t(`git`,[`describe`,`--match`,`${r.tagPrefix}[0-9]*.[0-9]*.[0-9]*`,`--abbrev=0`],{encoding:`utf8`}).stdout.trim();console.log(`Current tag: ${i}`);let a=/\d+\.\d+\.\d+.*/.exec(i)?.[0]??`0.0.0`;console.log(`Current version: ${a}`);let o=c(i),u=o.filter(e=>!r.commitsExclude.some(t=>t.test(e.message)));console.log(`Parsed commits: ${u.length}`),r.newVersion||=l(o,a),console.log(`New version: ${r.newVersion}`);let f=`${r.tagPrefix}${r.newVersion}`;console.log(`New tag: ${f}`);let _=`chore(release): ${f}`;console.log(`Commit message: '${_}'`),console.log(`-`.repeat(30)),console.log(`
6
+ ('' to continue / 's' to skip)`),await p(r,u,i,f,n.url),await m(r),await h(r,_),await g(r,f,_)},v=process.argv.slice(2).join(` `);v.includes(`-h`)&&(console.log(`Usage: relion [options]
7
7
 
8
8
  Options:
9
9
  -b <files> Files to bump the version in ['package.json']
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "relion",
3
- "version": "0.44.3",
3
+ "version": "0.46.0",
4
4
  "description": "🏷️ Release Workflow Helper",
5
5
  "author": "kh4f <kh4f.dev@gmail.com>",
6
6
  "license": "MIT",
@@ -16,6 +16,8 @@
16
16
  "build:watch": "tsdown --watch",
17
17
  "build:prod": "tsdown --prod",
18
18
  "lint": "eslint",
19
+ "typecheck": "tsc",
20
+ "test": "bun test",
19
21
  "release": "bun src/cli"
20
22
  },
21
23
  "dependencies": {
@@ -25,12 +27,11 @@
25
27
  "@eslint/js": "^10.0.1",
26
28
  "@stylistic/eslint-plugin": "^5.10.0",
27
29
  "@types/bun": "^1.3.11",
28
- "@types/node": "^25.5.0",
29
30
  "@types/semver": "^7.7.1",
30
31
  "eslint": "^10.1.0",
31
32
  "jiti": "^2.6.1",
32
- "tsdown": "^0.21.5",
33
- "typescript": "^5.9.3",
34
- "typescript-eslint": "^8.57.2"
33
+ "tsdown": "^0.21.7",
34
+ "typescript": "^6.0.2",
35
+ "typescript-eslint": "^8.58.0"
35
36
  }
36
37
  }