relion 0.13.0 → 0.14.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/LICENSE CHANGED
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
18
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
19
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
20
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
21
+ SOFTWARE.
package/dist/cli.js CHANGED
@@ -1 +1 @@
1
- import{resolve as e}from"node:path";import{pathToFileURL as t}from"node:url";import n from"./index.js";import{cli as r}from"cleye";import.meta.main&&await i();async function i(i,a){if(!i)try{let n=t(e(process.cwd(),`relion.config.ts`)).href;i=(await import(n)).default}catch(e){throw Error(`Error loading config: ${e.message}`)}let o=r({name:`relion`,flags:{bump:{alias:`b`,type:Boolean,description:`Bump the version`,default:!1},changelog:{alias:`l`,type:Boolean,description:`Generate a changelog`,default:!1},commit:{alias:`c`,type:Boolean,description:`Create a commit`,default:!1},tag:{alias:`t`,type:Boolean,description:`Create a tag`,default:!1},profile:{alias:`p`,type:String,description:`Use config profile`},dryRun:{alias:`d`,type:Boolean,description:`Run without making any changes`,default:!1},latest:{alias:`L`,type:Boolean,description:`Use the latest-release commit range in changelog`,default:!1}}},void 0,a);o&&(o.flags.bump||(i.bump=!1),o.flags.changelog||(i.changelog=!1),o.flags.commit||(i.commit=!1),o.flags.tag||(i.tag=!1),o.flags.profile&&(i.profile=o.flags.profile),o.flags.dryRun&&(i.dryRun=o.flags.dryRun),o.flags.latest&&i.changelog&&(i.changelog===!0&&(i.changelog={}),i.changelog.commitRange=`latest-release`),await n(i))}export{i as runCli};
1
+ import{resolve as e}from"node:path";import{pathToFileURL as t}from"node:url";import n from"./index.js";import{cli as r}from"cleye";import.meta.main&&await i();async function i(e,t){typeof e==`string`&&(e=e.split(` `)),e=e&&[e].flat();let i=r({name:`relion`,flags:{config:{alias:`c`,type:String,description:`Path to the config file`,default:`relion.config.ts`},bump:{alias:`b`,type:Boolean,description:`Bump the version`,default:!1},changelog:{alias:`l`,type:Boolean,description:`Generate a changelog`,default:!1},commit:{alias:`m`,type:Boolean,description:`Create a commit`,default:!1},tag:{alias:`t`,type:Boolean,description:`Create a tag`,default:!1},profile:{alias:`p`,type:String,description:`Use config profile`},dry:{alias:`d`,type:Boolean,description:`Run without making any changes`,default:!1},latest:{alias:`L`,type:Boolean,description:`Use the latest-release commit range in changelog`,default:!1}}},void 0,e?[...e]:process.argv.slice(2));if(i)return t??=await a(i.flags.config),t.bump||=i.flags.bump,t.changelog||=i.flags.changelog,t.commit||=i.flags.commit,t.tag||=i.flags.tag,t.profile??=i.flags.profile,t.dryRun??=i.flags.dry,i.flags.latest&&t.changelog&&(t.changelog===!0&&(t.changelog={}),t.changelog.commitRange=`latest-release`),n(t)}const a=async n=>{try{return(await import(t(e(process.cwd(),n)).href)).default}catch(e){throw Error(`Error loading config: ${e.message}`)}};export{i as runCli};
package/dist/index.d.ts CHANGED
@@ -303,16 +303,18 @@ interface BumpResult extends VersionedFile {
303
303
  }
304
304
  //#endregion
305
305
  //#region src/relion.d.ts
306
- declare function relion(userConfig: UserConfig): Promise<{
306
+ declare function relion(userConfig: UserConfig): {
307
307
  resolvedConfig: ResolvedConfig;
308
308
  generatedChangelog: string | null;
309
309
  commitCommand: string | null;
310
310
  tagCommand: string | null;
311
311
  bumpResults: BumpResult[] | null;
312
- }>;
313
- declare const defineConfig: (config: UserConfig) => UserConfig;
312
+ };
314
313
  //#endregion
315
314
  //#region src/utils/sections-selector.d.ts
316
315
  declare const changelogSectionsSelector: ChangelogSectionsSelector;
317
316
  //#endregion
317
+ //#region src/index.d.ts
318
+ declare const defineConfig: (config: UserConfig) => UserConfig;
319
+ //#endregion
318
320
  export { BumpFiles, BumpResult, ChangelogOptions, ChangelogSectionsSelector, CommitMessage, CommitOptions, CommitRange, CommitsParser, CompleteChangelogOptions, CompleteCommitOptions, CompleteCommitsParser, CompleteTagOptions, Context, Contributor, DefaultChangelogSections, DefaultVersionedFile, FalseOrComplete, FilledTypeGroup, FilledTypeGroupMap, GithubUserInfo, GpgSig, GpgSigCode, MergedConfig, ParsedCommit, RawCommit, RawReference, RefLabel, Reference, ReleaseContext, ReleaseType, ReleaseWithFlatCommits, ReleaseWithTypeGroups, RelionResult, RepoInfo, ResolvedChangelogOptions, ResolvedCommit, ResolvedConfig, ResolvedContext, TagOptions, TransformedConfig, TypeGroupDefinition, TypeGroupsMap, UserConfig, VersionedFile, changelogSectionsSelector, relion as default, defineConfig };
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import{existsSync as e,readFileSync as t,writeFileSync as n}from"node:fs";import r from"semver";import{createHash as i}from"node:crypto";import{execSync as a}from"node:child_process";import o from"handlebars";const s={bump:!1,changelog:!1,commit:!1,tag:!1,versionSourceFile:`./package.json`,newTagFormat:`v{{version}}`,prevReleaseTagPattern:/^v?(?<version>\d+\.\d+\.\d+)/,zeroMajorBreakingIsMinor:!0,dryRun:!1,silent:!1,context:{commitHyperlink:!0,refHyperlink:!0},commitsParser:{headerPattern:/^(?<type>\w+)(?:\((?<scope>.+)\))?(?<bang>!)?: (?<subject>.+)/s,breakingChangesPattern:/BREAKING CHANGES?:\s*(?<content>.+)/s,breakingChangeListPattern:/- (.+)/g,tagPattern:/tag: (?<tag>.*?)[,)]/g,coAuthorPattern:/Co-authored-by: (?<name>.+?) <(?<email>.+)>/g,signerPattern:/Signed-off-by: (?<name>.+?) <(?<email>.+)>/g,ghEmailPattern:/^(?:\d+\+)?(?<username>.+)@users\.noreply\.github\.com$/,remoteUrlPattern:/^(https:\/\/|git@)(?<host>[^/:]+)[/:](?<owner>.+?)\/(?<name>.+?)(?:\..*)?$/,refPattern:/^(?<action>.+?) (?<labels>.+)$/gm,refLabelPattern:/(?:(?<owner>\S+?)\/(?<repo>\S+?))?#(?<number>\d+)/g,refActionPattern:/Fixes|Closes|Refs/i,dateSource:`authorDate`,dateFormat:`US`,revertCommitBodyPattern:/^This reverts commit (?<hash>.{7})/m}},c={breaking:{title:`⚠️ BREAKING CHANGES`,commitType:`breaking`},feat:{title:`✨ Features`,commitType:`feat`},fix:{title:`🩹 Fixes`,commitType:`fix`},perf:{title:`⚡ Performance`,commitType:`perf`},refactor:{title:`🚜 Refactoring`,commitType:`refactor`},docs:{title:`📚 Documentation`,commitType:`docs`},style:{title:`🎨 Style`,commitType:`style`},build:{title:`📦 Build`,commitType:`build`},ci:{title:`🚀 CI`,commitType:`ci`},revert:{title:`♻️ Reverts`,commitType:`revert`},types:{title:`🏷️ Types`,commitType:`types`},deps:{title:`🧩 Dependencies`,commitType:`chore`,filter:e=>!!e.scope?.includes(`deps`)},chore:{title:`🛠️ Chores`,commitType:`chore`},test:{title:`🧪 Tests`,commitType:`test`},misc:{title:`⚙️ Miscellaneous`,commitType:`*`,filter:e=>e.type!==`release`}},l={output:`CHANGELOG.md`,commitRange:`unreleased`,sections:c,header:`# Changelog
2
2
 
3
3
 
4
- `,prevReleaseHeaderPattern:/^##.*?\d+\.\d+\.\d+/m,helpers:{eq:(e,t)=>e===t,repeat:(e,t)=>e.repeat(t),isArray:e=>Array.isArray(e),isBreakingCommitInOtherTypeGroup:(e,t)=>Object.entries(t.data.root.commitTypeGroups).filter(([,{commitType:e}])=>e!==`breaking`).some(([,t])=>t.commits.includes(e))},partials:{}},u={message:`release({{repo.name}}): {{newTag}}`,signOff:!1,gpgSign:!1,stageAll:!0,extraArgs:null},d={name:`{{newTag}}`,message:`release({{repo.name}}): {{newTag}}`,gpgSign:!1,force:!1,extraArgs:null},f=[{filePathRegex:/package\.json$/,versionPattern:/(^.*?"version".*?")(.*?)(")/s},{filePathRegex:/package-lock\.json$/,versionPattern:/(^.*?"version".*?"|"packages".*?"".*"version".*?")(.*?)(")/gs}],p=async e=>{let t=m(e),n=h(t),r=g(n),i=await _(r),a=x(i);return a},m=e=>{let t=e.profile;if(!t)return e;let n=e[`_${t}`];if(!n)throw Error(`Profile "${t}" not found in configuration.`);let r=(t,...r)=>{let i=e=>Object.prototype.toString.call(e)===`[object Object]`,a=(e,t)=>{let n=i(e),r=i(t);if(n&&r)return{...e,...t};if(!n&&r)return t;if(n&&!r)return e},o=e[t],s=n[t],c=a(o,s);if(c!==void 0)return r.forEach(e=>{c[e]=a(o?.[e],s?.[e])}),c};return{...e,...n,commitsParser:r(`commitsParser`),changelog:r(`changelog`,`partials`,`helpers`),commit:r(`commit`),tag:r(`tag`),context:r(`context`)}},h=e=>{let t=(e,t,n,...r)=>{if(t==null||t===!1)return!1;if(t===!0)return n;if(typeof t!=`object`)throw Error(`Invalid value for ${e}. It should be a boolean or an object.`);let i={...n,...t};return r.forEach(e=>i[e]={...n[e],...t[e]}),i};return{...s,...e,commitsParser:{...s.commitsParser,...e.commitsParser},changelog:t(`changelog`,e.changelog,l,`partials`,`helpers`),commit:t(`commit`,e.commit,u),tag:t(`tag`,e.tag,d)}},g=e=>{let t=e=>{let t=f.find(t=>t.filePathRegex.test(e));if(t)return{filePath:e,versionPattern:t.versionPattern};throw Error(`File ${e} doesn't match any default versioned files. Please provide a custom version pattern for this file.`)},n=e=>{if(e===!1)return!1;if(e===!0)return[r];if(Array.isArray(e))return[r,...e.map(e=>typeof e==`string`?t(e):e)];throw Error(`Invalid value for bump. It should be a boolean or an array.`)},r=typeof e.versionSourceFile==`string`?t(e.versionSourceFile):e.versionSourceFile;return{...e,versionSourceFile:r,bump:n(e.bump),changelog:e.changelog===!1?!1:{...e.changelog,compiledPartials:J(e.changelog.partials)}}},_=async e=>{let t=e.context??{},n=z(e.commitsParser.remoteUrlPattern),r=t.currentVersion??S(e.versionSourceFile),i=t.currentTag??H(e.prevReleaseTagPattern)[0],a=t.newVersion??await w(e,r),o=t.newTag??e.newTagFormat.replace(`{{version}}`,a),s=e.changelog?e.changelog.commitRange:`unreleased`,c=t.commits?(await Promise.all(t.commits.map(async t=>typeof t==`object`&&`message`in t||typeof t==`string`?await j(t,e.commitsParser,e.prevReleaseTagPattern):t))).filter(e=>e!=null):await A(s,e.commitsParser,e.prevReleaseTagPattern),l=v(c,o,e.commitsParser.revertCommitBodyPattern),u=e.changelog?y(l,e.changelog.sections,e.prevReleaseTagPattern):null,{commits:d,...f}=t;return{...e,context:{currentVersion:r,currentTag:i,newVersion:a,newTag:o,commits:l,releases:u,...f,repo:{...n,...e.context?.repo}}}},v=(e,t,n)=>{let r=0;return e.map(i=>{let a=null,o=e.find(e=>e.type===`revert`&&n.exec(e.body??``)?.groups?.hash===i.hash);return o&&(a=o.associatedReleaseTag===i.associatedReleaseTag?`inTheSameRelease`:`inOtherRelease`),{...i,associatedReleaseTag:i.associatedReleaseTag??t,isReverted:i.isReverted??a,breakingChangeIndex:i.breakingChanges?++r:void 0}})},y=(e,t,n)=>{let r={};return e.forEach(e=>{let t=e.associatedReleaseTag;t in r?r[t].commits.push(e):r[t]={tag:t,version:C(t,n),date:e.date,commits:[e]}}),Object.values(r).map(({commits:e,...n})=>({...n,commitTypeGroups:b(e,t)})).filter(e=>Object.keys(e.commitTypeGroups).length)},b=(e,t)=>{let n=Object.fromEntries(Object.entries(t).map(([e,{filter:t,...n}])=>[e,{...n,commits:[]}]));return e.forEach(e=>{let r=!!e.breakingChanges,i=!1,a=!1;for(let o in t){if(t[o].filter&&!t[o].filter(e))continue;let s=[t[o].commitType].flat();if(r&&!a&&s.includes(`breaking`)){n[o].commits.push(e),a=!0;continue}if(!i&&(s.includes(e.type)||s.includes(`*`))&&(n[o].commits.push(e),i=!0),i&&(!r||a))return}}),Object.fromEntries(Object.entries(n).filter(([e,t])=>t.commits.length))},x=e=>({...e,commit:e.commit?{...e.commit,message:q(e.commit.message,e.context)}:e.commit,tag:e.tag?{...e.tag,name:q(e.tag.name,e.context),message:q(e.tag.message,e.context)}:e.tag}),S=e=>{let n=t(e.filePath,`utf8`),i=e.versionPattern.exec(n)?.[2];if(!i)throw Error(`Version not found in '${e.filePath}' with pattern '${e.versionPattern}'`);if(!r.valid(i))throw Error(`Invalid version format in '${e.filePath}': '${i}'`);return G(`Current version from '${e.filePath}': '${i}'`),i},C=(e,t)=>t.exec(e)?.groups?.version,w=async(e,t)=>{if(e.context?.newVersion){if(!r.valid(e.context.newVersion))throw Error(`Invalid release version format: '${e.context.newVersion}'`);return e.context.newVersion}let n;if(e.releaseType)n=e.releaseType;else{let i=await A(`unreleased`,e.commitsParser,e.prevReleaseTagPattern);n=T(i),e.zeroMajorBreakingIsMinor&&r.major(t)===0&&n===`major`&&(n=`minor`)}let i=E(t,n);return G(`Determined new version: '${i}' (release type: '${n}')`),i},T=e=>{let t=e.some(e=>e.breakingChanges);if(t)return`major`;let n=e.some(e=>e.type===`feat`);return n?`minor`:`patch`},E=(e,t)=>r.inc(e,t)??(()=>{throw Error(`Failed to calculate new version from '${e}' with release type '${t}'`)})();let D=function(e){return e.G=`valid`,e.B=`bad`,e.U=`valid, unknown validity`,e.X=`valid, expired`,e.Y=`valid, made by expired key`,e.R=`valid, made by revoked key`,e.E=`cannot check (missing key)`,e.N=`no signature`,e}({});const O={};let k;const A=async(e,t,n)=>{let r=Array.isArray(e)?e:B(e,n),i=t,a=(await Promise.all(r.map(async e=>j(e,i,n)))).filter(e=>e!==null);return k=void 0,a},j=async(e,t,n)=>{typeof e==`string`&&(e={message:e});let{tagRefs:r,hash:i=M(e.message)}=e;if(i in O)return O[i];let a=e.message.trim();if(!a)throw Error(`Message is missing for commit: ${JSON.stringify(e)}`);let o;try{o=N(a,t)}catch(e){return console.warn(`Error parsing commit '${i}':`,e.message),null}let{type:s,scope:c,subject:l,body:u,breakingChanges:d,footer:f}=o,p=r?[...r.matchAll(t.tagPattern)].map(e=>e.groups?.tag??``):[],m=f?[...f.matchAll(t.signerPattern)].map(e=>e.groups):[],h=[],g=e=>{h.some(t=>t.email===e.email)||h.push(e)},_=e.authorName&&e.authorEmail?F({name:e.authorName,email:e.authorEmail},m):void 0;_&&g(_);let v=e.committerName&&e.committerEmail?F({name:e.committerName,email:e.committerEmail},m):void 0;v&&g(v);let y=f?[...f.matchAll(t.coAuthorPattern)].map(e=>e.groups).map(e=>F(e,m)):[];y.forEach(e=>g(e));let b=await I(f??``,t),x=e.gpgSigCode?{code:e.gpgSigCode,label:D[e.gpgSigCode],keyId:e.gpgSigKeyId}:void 0,S=e[t.dateSource===`committerDate`?`committerTs`:`authorTs`];typeof S==`string`&&(S=L(new Date(S*1e3),t.dateFormat));let C=p.find(e=>n.exec(e)),w=C??k;w&&(k=w);let T={hash:i,type:s,scope:c,subject:l,body:u,breakingChanges:d,footer:f,committer:v,gpgSig:x,date:S,releaseTag:C,associatedReleaseTag:w,tags:p.length?p:void 0,authors:h.length?h:void 0,refs:b.length?b:void 0};return i&&!(i in O)&&(O[i]=T),T},M=e=>`fake_`+i(`sha256`).update(e,`utf8`).digest(`hex`).slice(0,7),N=(e,t)=>{let[n,...r]=e.split(`
4
+ `,prevReleaseHeaderPattern:/^##.*?\d+\.\d+\.\d+/m,helpers:{eq:(e,t)=>e===t,repeat:(e,t)=>e.repeat(t),isArray:e=>Array.isArray(e),isBreakingCommitInOtherTypeGroup:(e,t)=>Object.entries(t.data.root.commitTypeGroups).filter(([,{commitType:e}])=>e!==`breaking`).some(([,t])=>t.commits.includes(e))},partials:{}},u={message:`release({{repo.name}}): {{newTag}}`,signOff:!1,gpgSign:!1,stageAll:!0,extraArgs:null},d={name:`{{newTag}}`,message:`release({{repo.name}}): {{newTag}}`,gpgSign:!1,force:!1,extraArgs:null},f=[{filePathRegex:/package\.json$/,versionPattern:/(^.*?"version".*?")(.*?)(")/s},{filePathRegex:/package-lock\.json$/,versionPattern:/(^.*?"version".*?"|"packages".*?"".*"version".*?")(.*?)(")/gs}],p=e=>{let t=m(e),n=h(t),r=g(n),i=_(r);return x(i)},m=e=>{let t=e.profile;if(!t)return e;let n=e[`_${t}`];if(!n)throw Error(`Profile "${t}" not found in configuration.`);let r=(t,...r)=>{let i=e=>Object.prototype.toString.call(e)===`[object Object]`,a=(e,t)=>{let n=i(e),r=i(t);return n&&r?{...e,...t}:t??e},o=e[t],s=n[t],c=a(o,s);if(c!==void 0)return r.forEach(e=>{c[e]=a(o?.[e],s?.[e])}),c};return{...e,...n,commitsParser:r(`commitsParser`),changelog:r(`changelog`,`partials`,`helpers`),commit:r(`commit`),tag:r(`tag`),context:r(`context`)}},h=e=>{let t=(e,t,n,...r)=>{if(t==null||t===!1)return!1;if(t===!0)return n;if(typeof t!=`object`)throw Error(`Invalid value for ${e}. It should be a boolean or an object.`);let i={...n,...t};return r.forEach(e=>i[e]={...n[e],...t[e]}),i};return{...s,...e,commitsParser:{...s.commitsParser,...e.commitsParser},changelog:t(`changelog`,e.changelog,l,`partials`,`helpers`),commit:t(`commit`,e.commit,u),tag:t(`tag`,e.tag,d)}},g=e=>{let t=e=>{let t=f.find(t=>t.filePathRegex.test(e));if(t)return{filePath:e,versionPattern:t.versionPattern};throw Error(`File ${e} doesn't match any default versioned files. Please provide a custom version pattern for this file.`)},n=e=>{if(e===!1)return!1;if(e===!0)return[r];if(Array.isArray(e))return[r,...e.map(e=>typeof e==`string`?t(e):e)];throw Error(`Invalid value for bump. It should be a boolean or an array.`)},r=typeof e.versionSourceFile==`string`?t(e.versionSourceFile):e.versionSourceFile;return{...e,versionSourceFile:r,bump:n(e.bump),changelog:e.changelog===!1?!1:{...e.changelog,compiledPartials:J(e.changelog.partials)}}},_=e=>{let t=e.context??{},n=z(e.commitsParser.remoteUrlPattern),r=t.currentVersion??S(e.versionSourceFile),i=t.currentTag??H(e.prevReleaseTagPattern)[0],a=t.newVersion??w(e,r),o=t.newTag??e.newTagFormat.replace(`{{version}}`,a),s=e.changelog?e.changelog.commitRange:`unreleased`,c=t.commits?t.commits.map(t=>typeof t==`object`&&`message`in t||typeof t==`string`?j(t,e.commitsParser,e.prevReleaseTagPattern):t).filter(e=>e!=null):A(s,e.commitsParser,e.prevReleaseTagPattern),l=v(c,o,e.commitsParser.revertCommitBodyPattern),u=e.changelog?y(l,e.changelog.sections,e.prevReleaseTagPattern):null,{commits:d,...f}=t;return{...e,context:{currentVersion:r,currentTag:i,newVersion:a,newTag:o,commits:l,releases:u,...f,repo:{...n,...e.context?.repo}}}},v=(e,t,n)=>{let r=0;return e.map(i=>{let a=null,o=e.find(e=>e.type===`revert`&&n.exec(e.body??``)?.groups?.hash===i.hash);return o&&(a=o.associatedReleaseTag===i.associatedReleaseTag?`inTheSameRelease`:`inOtherRelease`),{...i,associatedReleaseTag:i.associatedReleaseTag??t,isReverted:i.isReverted??a,breakingChangeIndex:i.breakingChanges?++r:void 0}})},y=(e,t,n)=>{let r={};return e.forEach(e=>{let t=e.associatedReleaseTag;t in r?r[t].commits.push(e):r[t]={tag:t,version:C(t,n),date:e.date,commits:[e]}}),Object.values(r).map(({commits:e,...n})=>({...n,commitTypeGroups:b(e,t)})).filter(e=>Object.keys(e.commitTypeGroups).length)},b=(e,t)=>{let n=Object.fromEntries(Object.entries(t).map(([e,{filter:t,...n}])=>[e,{...n,commits:[]}]));return e.forEach(e=>{let r=!!e.breakingChanges,i=!1,a=!1;for(let o in t){if(t[o].filter&&!t[o].filter(e))continue;let s=[t[o].commitType].flat();if(r&&!a&&s.includes(`breaking`)){n[o].commits.push(e),a=!0;continue}if(!i&&(s.includes(e.type)||s.includes(`*`))&&(n[o].commits.push(e),i=!0),i&&(!r||a))return}}),Object.fromEntries(Object.entries(n).filter(([e,t])=>t.commits.length))},x=e=>({...e,commit:e.commit?{...e.commit,message:q(e.commit.message,e.context)}:e.commit,tag:e.tag?{...e.tag,name:q(e.tag.name,e.context),message:q(e.tag.message,e.context)}:e.tag}),S=e=>{let n=t(e.filePath,`utf8`),i=e.versionPattern.exec(n)?.[2];if(!i)throw Error(`Version not found in '${e.filePath}' with pattern '${e.versionPattern}'`);if(!r.valid(i))throw Error(`Invalid version format in '${e.filePath}': '${i}'`);return G(`Current version from '${e.filePath}': '${i}'`),i},C=(e,t)=>t.exec(e)?.groups?.version,w=(e,t)=>{if(e.context?.newVersion){if(!r.valid(e.context.newVersion))throw Error(`Invalid release version format: '${e.context.newVersion}'`);return e.context.newVersion}let n;if(e.releaseType)n=e.releaseType;else{let i=A(`unreleased`,e.commitsParser,e.prevReleaseTagPattern);n=T(i),e.zeroMajorBreakingIsMinor&&r.major(t)===0&&n===`major`&&(n=`minor`)}let i=E(t,n);return G(`Determined new version: '${i}' (release type: '${n}')`),i},T=e=>e.some(e=>e.breakingChanges)?`major`:e.some(e=>e.type===`feat`)?`minor`:`patch`,E=(e,t)=>r.inc(e,t)??(()=>{throw Error(`Failed to calculate new version from '${e}' with release type '${t}'`)})();let D=function(e){return e.G=`valid`,e.B=`bad`,e.U=`valid, unknown validity`,e.X=`valid, expired`,e.Y=`valid, made by expired key`,e.R=`valid, made by revoked key`,e.E=`cannot check (missing key)`,e.N=`no signature`,e}({});const O={};let k;const A=(e,t,n)=>{let r=Array.isArray(e)?e:B(e,n),i=t,a=r.map(e=>j(e,i,n)).filter(e=>e!==null);return k=void 0,a},j=(e,t,n)=>{typeof e==`string`&&(e={message:e});let{tagRefs:r,hash:i=M(e.message)}=e;if(i in O)return O[i];let a=e.message.trim();if(!a)throw Error(`Message is missing for commit: ${JSON.stringify(e)}`);let o;try{o=N(a,t)}catch(e){return console.warn(`Error parsing commit '${i}':`,e.message),null}let{type:s,scope:c,subject:l,body:u,breakingChanges:d,footer:f}=o,p=r?[...r.matchAll(t.tagPattern)].map(e=>e.groups?.tag??``):[],m=f?[...f.matchAll(t.signerPattern)].map(e=>e.groups):[],h=[],g=e=>{h.some(t=>t.email===e.email)||h.push(e)},_=e.authorName&&e.authorEmail?F({name:e.authorName,email:e.authorEmail},m):void 0;_&&g(_);let v=e.committerName&&e.committerEmail?F({name:e.committerName,email:e.committerEmail},m):void 0;v&&g(v),(f?[...f.matchAll(t.coAuthorPattern)].map(e=>e.groups).map(e=>F(e,m)):[]).forEach(e=>g(e));let y=I(f??``,t),b=e.gpgSigCode?{code:e.gpgSigCode,label:D[e.gpgSigCode],keyId:e.gpgSigKeyId}:void 0,x=e[t.dateSource===`committerDate`?`committerTs`:`authorTs`];typeof x==`string`&&(x=L(new Date(x*1e3),t.dateFormat));let S=p.find(e=>n.exec(e)),C=S??k;C&&(k=C);let w={hash:i,type:s,scope:c,subject:l,body:u,breakingChanges:d,footer:f,committer:v,gpgSig:b,date:x,releaseTag:S,associatedReleaseTag:C,tags:p.length?p:void 0,authors:h.length?h:void 0,refs:y.length?y:void 0};return i&&!(i in O)&&(O[i]=w),w},M=e=>`fake_`+i(`sha256`).update(e,`utf8`).digest(`hex`).slice(0,7),N=(e,t)=>{let[n,...r]=e.split(`
5
5
 
6
6
  `),i=t.headerPattern.exec(n);if(!i?.groups)throw Error(`Commit header '${n}' doesn't match expected format`);let{type:a,scope:o,bang:s,subject:c}=i.groups,l,u=r.find(e=>t.breakingChangesPattern.test(e));u?(l=P(u,t),r.splice(r.indexOf(u),1)):s&&(l=c);let d=r.findIndex(e=>e.match(t.refActionPattern)??e.match(t.coAuthorPattern)??e.match(t.signerPattern)),[f,p]=d===-1?[r.join(`
7
7
 
@@ -9,9 +9,19 @@ import{existsSync as e,readFileSync as t,writeFileSync as n}from"node:fs";import
9
9
 
10
10
  `),r.slice(d).join(`
11
11
 
12
- `)];return{type:a,scope:o||void 0,subject:c,body:f||void 0,breakingChanges:l,footer:p||void 0}},P=(e,t)=>{let n=t.breakingChangesPattern.exec(e)?.groups?.content;if(!n)throw Error(`Failed to extract breaking changes content from '${e}' using pattern "${t.breakingChangesPattern}"`);let r=[...n.matchAll(t.breakingChangeListPattern)];return r.length?r.map(e=>e[1]):n},F=(e,t)=>{let n=t.some(t=>t.email===e.email&&t.name===e.name);return{...e,hasSignedOff:n,ghLogin:e.name,ghUrl:`https://github.com/${e.name}`}},I=async(e,t)=>await Promise.all([...e.matchAll(t.refPattern)].map(e=>e.groups).filter(e=>t.refActionPattern.test(e.action)).flatMap(e=>[...e.labels.matchAll(t.refLabelPattern)].map(e=>e.groups).filter(e=>!!e.number).map(t=>({action:e.action,owner:t.owner,repo:t.repo,number:t.number})))),L=(e,t)=>{let n=e=>e.toString().padStart(2,`0`);if(t===`US`)return e.toLocaleString(`en-US`,{month:`short`,day:`numeric`,year:`numeric`});if(t===`ISO`)return e.toISOString().split(`T`)[0];let r={YYYY:e.getUTCFullYear().toString(),MM:n(e.getUTCMonth()+1),DD:n(e.getUTCDate()),HH:n(e.getUTCHours()),mm:n(e.getUTCMinutes()),ss:n(e.getUTCSeconds())};return t.replace(/YYYY|MM|DD|HH|mm|ss/g,e=>r[e])},R=/##COMMIT##\n#HASH# (?<hash>.+)?\n#MSG# (?<message>[\s\S]*?)\n#REFS#\s+(?<tagRefs>.+)?\n#AUTHOR-NAME# (?<authorName>.+)?\n#AUTHOR-EMAIL# (?<authorEmail>.+)?\n#AUTHOR-DATE# (?<authorTs>.+)?\n#COMMITTER-NAME# (?<committerName>.+)?\n#COMMITTER-EMAIL# (?<committerEmail>.+)?\n#COMMITTER-DATE# (?<committerTs>.+)?\n#GPGSIG-CODE# (?<gpgSigCode>.+)?\n#GPGSIG-KEYID# (?<gpgSigKeyId>.+)?/g,z=e=>{let t=a(`git remote get-url origin`,{encoding:`utf8`}).trim(),n=e.exec(t);if(!n?.groups)throw Error(`Couldn't parse remote URL: `+t);let{host:r,owner:i,name:o}=n.groups,s=`https://${r}/${i}/${o}`;return{host:r,owner:i,name:o,homepage:s}},B=(e,t)=>{let n=V(),r=H(t),i=``,o=``,s=``;if(e===`all`)i=`{{firstCommit}}`,o=`HEAD`;else if(e===`unreleased`)i=r[0]??`{{firstCommit}}`,o=`HEAD`;else if(e===`latest-release`)i=r[1]??`{{firstCommit}}`,o=r[0]??`HEAD`;else if(typeof e==`object`){let t=r.indexOf(e.versionTag);if(t===-1)throw Error(`Version tag '${e.versionTag}' not found`);i=r[t+1]??`{{firstCommit}}`,o=r[t]}else s=e;i&&o&&(s=i===`{{firstCommit}}`?`"${i}^!" ${o}`:`"${i}..${o}"`),s=s.replace(`{{firstCommit}}`,n);let c=a(`git log ${s} --pretty="##COMMIT##%n#HASH# %h%n#MSG# %B%n#REFS# %d%n#AUTHOR-NAME# %an%n#AUTHOR-EMAIL# %ae%n#AUTHOR-DATE# %at%n#COMMITTER-NAME# %cn%n#COMMITTER-EMAIL# %ce%n#COMMITTER-DATE# %ct%n#GPGSIG-CODE# %G?%n#GPGSIG-KEYID# %GK%n"`,{encoding:`utf8`});return[...c.matchAll(R)].map(e=>e.groups)},V=()=>a(`git rev-list --max-parents=0 HEAD`,{encoding:`utf8`}).trim(),H=e=>{let t=a(`git tag --sort=-creatordate`,{encoding:`utf8`});return t.split(`
13
- `).filter(t=>e.test(t))};let U=!1;const W=e=>U=e,G=(...e)=>{U||console.log(...e)},K={...c,pick(...e){return Object.fromEntries(e.map(e=>[e,this[e]]))},omit(...e){let t=new Set(e);return Object.fromEntries(Object.entries(this).filter(([e])=>!t.has(e)))}},q=(e,t)=>o.compile(e)(t),J=e=>Object.fromEntries(Object.entries(e).map(([e,t])=>[e,o.compile(t)])),Y=e=>{if(!e.bump)return null;let r=e.bump,i=e.context.newVersion;return r.map(r=>{let a=t(r.filePath,`utf8`),o=r.versionPattern.exec(a)?.[2]??null,s=a.replace(r.versionPattern,`$1${i}$3`);return e.dryRun||n(r.filePath,s,`utf8`),G(`Updated version in '${r.filePath}' to '${i}'`),{...r,oldVersion:o,newVersion:i}})};var X=`{{#>header~}}
14
- ## &ensp; [\` 📦 {{tag}} \`]({{repo.homepage}}/{{#if prevRelease.tag}}compare/{{prevRelease.tag}}...{{tag}}{{else}}commits/{{tag}}{{/if}})
12
+ `)];return{type:a,scope:o||void 0,subject:c,body:f||void 0,breakingChanges:l,footer:p||void 0}},P=(e,t)=>{let n=t.breakingChangesPattern.exec(e)?.groups?.content;if(!n)throw Error(`Failed to extract breaking changes content from '${e}' using pattern "${t.breakingChangesPattern}"`);let r=[...n.matchAll(t.breakingChangeListPattern)];return r.length?r.map(e=>e[1]):n},F=(e,t)=>{let n=t.some(t=>t.email===e.email&&t.name===e.name);return{...e,hasSignedOff:n,ghLogin:e.name,ghUrl:`https://github.com/${e.name}`}},I=(e,t)=>[...e.matchAll(t.refPattern)].map(e=>e.groups).filter(e=>t.refActionPattern.test(e.action)).flatMap(e=>[...e.labels.matchAll(t.refLabelPattern)].map(e=>e.groups).filter(e=>!!e.number).map(t=>({action:e.action,owner:t.owner,repo:t.repo,number:t.number}))),L=(e,t)=>{let n=e=>e.toString().padStart(2,`0`);if(t===`US`)return e.toLocaleString(`en-US`,{month:`short`,day:`numeric`,year:`numeric`});if(t===`ISO`)return e.toISOString().split(`T`)[0];let r={YYYY:e.getUTCFullYear().toString(),MM:n(e.getUTCMonth()+1),DD:n(e.getUTCDate()),HH:n(e.getUTCHours()),mm:n(e.getUTCMinutes()),ss:n(e.getUTCSeconds())};return t.replace(/YYYY|MM|DD|HH|mm|ss/g,e=>r[e])},R=/##COMMIT##\n#HASH# (?<hash>.+)?\n#MSG# (?<message>[\s\S]*?)\n#REFS#\s+(?<tagRefs>.+)?\n#AUTHOR-NAME# (?<authorName>.+)?\n#AUTHOR-EMAIL# (?<authorEmail>.+)?\n#AUTHOR-DATE# (?<authorTs>.+)?\n#COMMITTER-NAME# (?<committerName>.+)?\n#COMMITTER-EMAIL# (?<committerEmail>.+)?\n#COMMITTER-DATE# (?<committerTs>.+)?\n#GPGSIG-CODE# (?<gpgSigCode>.+)?\n#GPGSIG-KEYID# (?<gpgSigKeyId>.+)?/g,z=e=>{let t=a(`git remote get-url origin`,{encoding:`utf8`}).trim(),n=e.exec(t);if(!n?.groups)throw Error(`Couldn't parse remote URL: `+t);let{host:r,owner:i,name:o}=n.groups,s=`https://${r}/${i}/${o}`;return{host:r,owner:i,name:o,homepage:s}},B=(e,t)=>{let n=V(),r=H(t),i=``,o=``,s=``;if(e===`all`)i=`{{firstCommit}}`,o=`HEAD`;else if(e===`unreleased`)i=r[0]??`{{firstCommit}}`,o=`HEAD`;else if(e===`latest-release`)i=r[1]??`{{firstCommit}}`,o=r[0]??`HEAD`;else if(typeof e==`object`){let t=r.indexOf(e.versionTag);if(t===-1)throw Error(`Version tag '${e.versionTag}' not found`);i=r[t+1]??`{{firstCommit}}`,o=r[t]}else s=e;return i&&o&&(s=i===`{{firstCommit}}`?`"${i}^!" ${o}`:`"${i}..${o}"`),s=s.replace(`{{firstCommit}}`,n),[...a(`git log ${s} --pretty="##COMMIT##%n#HASH# %h%n#MSG# %B%n#REFS# %d%n#AUTHOR-NAME# %an%n#AUTHOR-EMAIL# %ae%n#AUTHOR-DATE# %at%n#COMMITTER-NAME# %cn%n#COMMITTER-EMAIL# %ce%n#COMMITTER-DATE# %ct%n#GPGSIG-CODE# %G?%n#GPGSIG-KEYID# %GK%n"`,{encoding:`utf8`}).matchAll(R)].map(e=>e.groups)},V=()=>a(`git rev-list --max-parents=0 HEAD`,{encoding:`utf8`}).trim(),H=e=>a(`git tag --sort=-creatordate`,{encoding:`utf8`}).split(`
13
+ `).filter(t=>e.test(t));let U=!1;const W=e=>U=e,G=(...e)=>{U||console.log(...e)},K={...c,pick(...e){return Object.fromEntries(e.map(e=>[e,this[e]]))},omit(...e){let t=new Set(e);return Object.fromEntries(Object.entries(this).filter(([e])=>!t.has(e)))}},q=(e,t)=>o.compile(e)(t),J=e=>Object.fromEntries(Object.entries(e).map(([e,t])=>[e,o.compile(t)])),Y=e=>{if(!e.bump)return null;let r=e.bump,i=e.context.newVersion;return r.map(r=>{let a=t(r.filePath,`utf8`),o=r.versionPattern.exec(a)?.[2]??null,s=a.replace(r.versionPattern,`$1${i}$3`);return e.dryRun||n(r.filePath,s,`utf8`),G(`Updated version in '${r.filePath}' to '${i}'`),{...r,oldVersion:o,newVersion:i}})};var X=`{{#*inline "compareLink"~}}
14
+ {{repo.homepage~}}
15
+ {{#if prevRelease.tag~}}
16
+ /compare/{{prevRelease.tag}}...
17
+ {{~else~}}
18
+ /commits/
19
+ {{~/if}}
20
+ {{~tag}}
21
+ {{~/inline}}
22
+
23
+ {{~#>header~}}
24
+ ## &ensp; [\` 📦 {{tag}} \`]({{>compareLink}})
15
25
 
16
26
  {{/header}}
17
27
 
@@ -31,8 +41,8 @@ import{existsSync as e,readFileSync as t,writeFileSync as n}from"node:fs";import
31
41
  {{else}}
32
42
  {{#each commits~}}
33
43
  - {{#if scope}}**{{scope}}**: {{/if}}{{{subject}}} {{" "}}
34
- {{~#if ../../commitHyperlink~}}
35
- [\`{{hash}}\`]({{../../repo.homepage}}/commit/{{hash}})
44
+ {{~#if @root.commitHyperlink~}}
45
+ [\`{{hash}}\`]({{@root.repo.homepage}}/commit/{{hash}})
36
46
  {{~else~}}
37
47
  {{hash}}
38
48
  {{~/if~}}
@@ -44,13 +54,7 @@ import{existsSync as e,readFileSync as t,writeFileSync as n}from"node:fs";import
44
54
  {{/main}}
45
55
 
46
56
  {{~#>footer~}}
47
- ##### &emsp;&ensp;&nbsp;&nbsp; [_All Release Commits_]
48
- {{~#if prevRelease.tag~}}
49
- ({{repo.homepage}}/compare/{{prevRelease.tag}}...{{tag}})
50
- {{~else~}}
51
- ({{repo.homepage}}/commits/{{tag}})
52
- {{~/if~}}
53
- {{" "}} &ensp;•&ensp; _{{date}}_
57
+ ##### &emsp;&ensp;&nbsp;&nbsp; [_All Release Commits_]({{>compareLink}}) &ensp;•&ensp; _{{date}}_
54
58
 
55
59
 
56
- {{/footer}}`;const Z=e=>{if(!e.changelog)return null;let t=e.changelog,n=e.context.releases;if(!n)return null;let r=H(e.prevReleaseTagPattern);o.registerPartial(t.compiledPartials),o.registerHelper(t.helpers);let i=t.header;return n.forEach((t,a)=>{let o=n[a+1];if(!o){let n=r.indexOf(t.tag);if(n!==-1){let t=r[n+1];o={tag:t,version:t&&C(t,e.prevReleaseTagPattern)}}else o={tag:e.context.currentTag,version:e.context.currentVersion}}let s={...t,...e.context,prevRelease:o},c=q(X,s);i+=c}),t.output===`stdout`?(G(`Generated changelog:`),console.log(i)):(G(`Writing changelog to file '${t.output}'`),e.dryRun||Q(t.output,i,t.prevReleaseHeaderPattern)),i},Q=(r,i,a)=>{let o=e(r)?t(r,{encoding:`utf8`}):``,s=o.search(a),c=o.slice(s),l=i+c;n(r,l,{encoding:`utf8`})},$=e=>{if(!e.commit)return null;let t=e.commit,n=[t.stageAll&&`git add -A &&`,`git commit -m "${t.message}"`,t.signOff&&`-s`,t.gpgSign&&`-S`,t.extraArgs].filter(Boolean).join(` `);return G(`Committing with command: '${n}'`),e.dryRun||a(n,{stdio:`inherit`}),n},ee=e=>{if(!e.tag)return null;let t=e.tag,n=[`git tag -a ${t.name}`,`-m "${t.message}"`,t.gpgSign&&`-s`,t.force&&`-f`,t.extraArgs].filter(Boolean).join(` `);return G(`Tagging with command: '${n}'`),e.dryRun||a(n,{stdio:`inherit`}),n};async function te(e){W(!!e.silent||!!e.profile&&!!e[`_${e.profile}`]?.silent);let t=await p(e),n=Y(t),r=Z(t),i=$(t),a=ee(t);return{resolvedConfig:t,generatedChangelog:r,commitCommand:i,tagCommand:a,bumpResults:n}}const ne=e=>e;export{K as changelogSectionsSelector,te as default,ne as defineConfig};
60
+ {{/footer}}`;const Z=e=>{if(!e.changelog)return null;let t=e.changelog,n=e.context.releases;if(!n)return null;let r=H(e.prevReleaseTagPattern);o.registerPartial(t.compiledPartials),o.registerHelper(t.helpers);let i=t.header;return n.forEach((t,a)=>{let o=n[a+1];if(!o){let n=r.indexOf(t.tag);if(n!==-1){let t=r[n+1];o={tag:t,version:t&&C(t,e.prevReleaseTagPattern)}}else o={tag:e.context.currentTag,version:e.context.currentVersion}}let s={...t,...e.context,prevRelease:o},c=q(X,s);i+=c}),t.output===`stdout`?(G(`Generated changelog:`),console.log(i)):(G(`Writing changelog to file '${t.output}'`),e.dryRun||Q(t.output,i,t.prevReleaseHeaderPattern)),i},Q=(r,i,a)=>{let o=e(r)?t(r,{encoding:`utf8`}):``,s=o.search(a),c=o.slice(s),l=i+c;n(r,l,{encoding:`utf8`})},$=e=>{if(!e.commit)return null;let t=e.commit,n=[t.stageAll&&`git add -A &&`,`git commit -m "${t.message}"`,t.signOff&&`-s`,t.gpgSign&&`-S`,t.extraArgs].filter(Boolean).join(` `);return G(`Committing with command: '${n}'`),e.dryRun||a(n,{stdio:`inherit`}),n},ee=e=>{if(!e.tag)return null;let t=e.tag,n=[`git tag -a ${t.name}`,`-m "${t.message}"`,t.gpgSign&&`-s`,t.force&&`-f`,t.extraArgs].filter(Boolean).join(` `);return G(`Tagging with command: '${n}'`),e.dryRun||a(n,{stdio:`inherit`}),n};function te(e){W(!!e.silent||!!e.profile&&!!e[`_${e.profile}`]?.silent);let t=p(e),n=Y(t),r=Z(t),i=$(t),a=ee(t);return{resolvedConfig:t,generatedChangelog:r,commitCommand:i,tagCommand:a,bumpResults:n}}const ne=e=>e;export{K as changelogSectionsSelector,te as default,ne as defineConfig};
package/package.json CHANGED
@@ -1,9 +1,12 @@
1
1
  {
2
2
  "name": "relion",
3
- "version": "0.13.0",
3
+ "version": "0.14.1",
4
4
  "description": "Release workflow helper for Node.js projects.",
5
5
  "author": "Kh4f <kh4f.dev@gmail.com>",
6
6
  "license": "MIT",
7
+ "engines": {
8
+ "node": "^24.8.0"
9
+ },
7
10
  "repository": "https://github.com/kh4f/relion",
8
11
  "bugs": "https://github.com/kh4f/relion/issues",
9
12
  "homepage": "https://github.com/kh4f/relion#readme",
@@ -33,15 +36,15 @@
33
36
  "semver": "^7.7.2"
34
37
  },
35
38
  "devDependencies": {
36
- "@eslint/js": "^9.34.0",
37
- "@stylistic/eslint-plugin": "^5.3.1",
39
+ "@eslint/js": "^9.36.0",
40
+ "@stylistic/eslint-plugin": "^5.4.0",
38
41
  "@types/node": "^24.3.1",
39
42
  "@types/semver": "^7.7.1",
40
43
  "eslint": "^9.34.0",
41
44
  "globals": "^16.3.0",
42
45
  "lint-staged": "^16.1.6",
43
46
  "simple-git-hooks": "^2.13.1",
44
- "tsdown": "^0.14.2",
47
+ "tsdown": "^0.15.4",
45
48
  "tsx": "^4.20.5",
46
49
  "typescript": "^5.9.2",
47
50
  "typescript-eslint": "^8.42.0",
@@ -51,7 +54,7 @@
51
54
  "pre-commit": "pnpm lint-staged"
52
55
  },
53
56
  "lint-staged": {
54
- "*.{js,ts}": "pnpm lint:fix"
57
+ "*.ts": "pnpm lint:fix"
55
58
  },
56
59
  "scripts": {
57
60
  "build": "tsdown",
@@ -59,9 +62,10 @@
59
62
  "build:prod": "tsdown --production",
60
63
  "lint": "eslint",
61
64
  "lint:fix": "eslint --fix",
62
- "test": "vitest run index",
63
- "test:watch": "vitest index",
64
- "release": "node dist/cli.js -blct",
65
- "release:github": "node dist/cli.js -l -p github -L"
65
+ "test": "vitest run",
66
+ "test:watch": "vitest",
67
+ "release": "pnpm relion",
68
+ "release:github": "pnpm relion --profile github --latest",
69
+ "relion": "tsx scripts/relion-runner"
66
70
  }
67
71
  }