relion 0.21.0 → 0.23.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/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";const i=async n=>{try{return(await import(t(e(process.cwd(),n)).href)).default}catch(e){throw Error(`Error loading config: ${e.message}`)}};import.meta.main&&await a();async function a(e,t){typeof e==`string`&&(e=e.split(` `)),e&&=[e].flat();let a=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(a)return t??=await i(a.flags.config),t.bump||=a.flags.bump,t.changelog||=a.flags.changelog,t.commit||=a.flags.commit,t.tag||=a.flags.tag,t.profile??=a.flags.profile,t.dryRun??=a.flags.dry,a.flags.latest&&t.changelog&&(t.changelog===!0&&(t.changelog={}),t.changelog.commitRange=`latest-release`),{inputConfig:t,...await n(t)}}export{a 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";const i=async n=>{try{return(await import(t(e(process.cwd(),n)).href)).default}catch(e){throw Error(`Error loading config: ${e.message}`)}},a=e=>{if(e===`all`)return`all`;let t={b:`bump`,l:`changelog`,m:`commit`,t:`tag`};return e.split(``).map(e=>{if(!(e in t))throw Error(`Invalid lifecycle step alias: '${e}'`);return t[e]})};import.meta.main&&await o();async function o(e,t){typeof e==`string`&&(e=e.split(` `)),e=e?[e].flat():process.argv.slice(2);let o=r({name:`relion`,flags:{lifecycle:{alias:`f`,type:String,description:`Lifecycle steps to run in order ((b)ump, change(l)og, co(m)mit, (t)ag, or "all").`},config:{alias:`c`,type:String,description:`Path to the config file`,default:`relion.config.ts`},profile:{alias:`p`,type:String,description:`Use config profile`},dry:{alias:`d`,type:Boolean,description:`Run without making any changes`},latest:{alias:`L`,type:Boolean,description:`Use the latest-release commit range in changelog`,default:!1}}},void 0,[...e]);if(!o)return;t=t?structuredClone(t):await i(o.flags.config);let s,c=o.flags.profile??t.profile;if(c){let e=t[`_${c}`];if(!e)throw Error(`Profile '${c}' not found in config`);t.profile=c,s=e}else s=t._default??={};return o.flags.lifecycle&&(s.lifecycle=a(o.flags.lifecycle)),o.flags.dry&&(s.dryRun=!0),o.flags.latest&&(s.changelog??={},s.changelog.commitRange=`latest-release`),{inputConfig:t,...await n(t)}}export{o as runCli};
package/dist/index.d.ts CHANGED
@@ -1,12 +1,12 @@
1
1
  import { HelperDeclareSpec } from "handlebars";
2
2
 
3
3
  //#region src/types/config.d.ts
4
- type FalseOrComplete<T> = false | Required<T>;
5
4
  interface UserConfig {
6
- bump?: boolean | BumpFiles;
7
- changelog?: boolean | ChangelogOptions;
8
- commit?: boolean | CommitOptions;
9
- tag?: boolean | TagOptions;
5
+ lifecycle?: LifecycleStep[] | 'all';
6
+ bump?: (string | Bumper)[];
7
+ changelog?: ChangelogOptions;
8
+ commit?: CommitOptions;
9
+ tag?: TagOptions;
10
10
  newTagPrefix?: string;
11
11
  newTagFormat?: string;
12
12
  versionSource?: 'versionSourceFile' | 'latest-release-tag';
@@ -22,37 +22,40 @@ interface UserConfig {
22
22
  logLevel?: 'info' | 'info-clean' | 'silent';
23
23
  [profile: `_${string}`]: UserConfig | undefined;
24
24
  }
25
- type OptionalKeys = 'releaseType' | 'context' | 'profile' | 'newTagPrefix';
25
+ type OptionalKeys = LifecycleStep | 'releaseType' | 'profile' | 'newTagPrefix';
26
26
  interface MergedConfig extends Omit<Required<UserConfig>, OptionalKeys>, Pick<UserConfig, OptionalKeys> {
27
- changelog: FalseOrComplete<ChangelogOptions>;
28
- commit: FalseOrComplete<CommitOptions>;
29
- tag: FalseOrComplete<TagOptions>;
27
+ lifecycle: LifecycleStep[];
28
+ changelog?: CompleteChangelogOptions;
29
+ commit?: CompleteCommitOptions;
30
+ tag?: CompleteTagOptions;
30
31
  commitsParser: CompleteCommitsParser;
31
32
  }
32
33
  interface TransformedConfig extends Omit<MergedConfig, 'changelog'> {
33
34
  versionSourceFile: Bumper;
34
- bump: FalseOrComplete<Bumper[]>;
35
- changelog: false | ResolvedChangelogOptions;
35
+ bump?: Required<Bumper[]>;
36
+ changelog?: ResolvedChangelogOptions;
36
37
  }
37
38
  interface ResolvedConfig extends TransformedConfig {
38
39
  context: ResolvedContext;
39
40
  }
40
- type BumpFiles = (string | Bumper)[];
41
41
  interface ChangelogOptions {
42
- output?: 'stdout' | (string & {});
42
+ file?: string;
43
+ output?: 'file' | 'stdout';
43
44
  commitRange?: CommitRange;
45
+ extractFromFile?: boolean;
44
46
  sections?: TypeGroupsMap;
45
47
  header?: string;
46
- prevReleaseHeaderPattern?: RegExp;
48
+ latestReleasePattern?: RegExp;
49
+ commitRefLinkPattern?: RegExp;
47
50
  groupCommitsByScope?: boolean;
48
51
  maxLinesPerRelease?: number;
49
52
  helpers?: HelperDeclareSpec;
50
- partials?: Record<string, string | ((fallback: string) => string)>;
53
+ partials?: Record<string, 'from-file' | (string & {}) | ((fallback: string) => string)>;
51
54
  review?: boolean;
52
55
  }
53
56
  type CompleteChangelogOptions = Required<ChangelogOptions>;
54
57
  interface ResolvedChangelogOptions extends Omit<CompleteChangelogOptions, 'partials'> {
55
- compiledPartials: Record<string, HandlebarsTemplateDelegate>;
58
+ compiledPartials: Record<string, HandlebarsTemplateDelegate> | string;
56
59
  }
57
60
  interface CommitOptions {
58
61
  message?: string;
@@ -100,12 +103,15 @@ interface Context {
100
103
  newVersion?: string;
101
104
  newTag?: string;
102
105
  repo?: RepoInfo;
106
+ commitRefLinks?: boolean;
107
+ footerChangelogUrl?: boolean;
103
108
  [key: string]: unknown;
104
109
  }
105
110
  interface ResolvedContext extends Required<Context> {
106
111
  commits: ResolvedCommit[];
107
112
  releases: ReleaseWithTypeGroups[] | null;
108
113
  }
114
+ type LifecycleStep = 'bump' | 'changelog' | 'commit' | 'tag';
109
115
  type LogLevel = 'info' | 'info-clean' | 'silent';
110
116
  type CommitRange = 'all' | 'unreleased' | 'latest-release' | {
111
117
  releaseTag: string;
@@ -313,9 +319,9 @@ interface SectionsSelector extends DefaultChangelogSections {
313
319
  //#region src/types/result.d.ts
314
320
  interface RelionResult {
315
321
  resolvedConfig: ResolvedConfig;
316
- generatedChangelog: string | null;
317
- commitCommand: string | null;
318
- tagCommand: string | null;
322
+ generatedChangelog?: string;
323
+ commitCommand?: string;
324
+ tagCommand?: string;
319
325
  }
320
326
  //#endregion
321
327
  //#region src/relion.d.ts
@@ -327,4 +333,4 @@ declare const sectionsSelector: SectionsSelector;
327
333
  //#region src/index.d.ts
328
334
  declare const defineConfig: (config: UserConfig) => UserConfig;
329
335
  //#endregion
330
- export { BumpFiles, Bumper, ChangelogOptions, CommitMessage, CommitOptions, CommitRange, CommitsParser, CompleteChangelogOptions, CompleteCommitOptions, CompleteCommitsParser, CompleteTagOptions, Context, Contributor, DefaultBumper, DefaultChangelogSections, FalseOrComplete, FilledTypeGroup, FilledTypeGroupMap, GithubUserInfo, GpgSig, GpgSigCode, LogLevel, MergedConfig, ParsedCommit, RawCommit, RawReference, RefLabel, Reference, ReleaseContext, ReleaseType, ReleaseWithFlatCommits, ReleaseWithTypeGroups, RelionResult, RepoInfo, ResolvedChangelogOptions, ResolvedCommit, ResolvedConfig, ResolvedContext, ScopeGroup, SectionsSelector, TagOptions, TransformedConfig, TypeGroupDefinition, TypeGroupsMap, UserConfig, relion as default, defineConfig, sectionsSelector };
336
+ export { Bumper, ChangelogOptions, CommitMessage, CommitOptions, CommitRange, CommitsParser, CompleteChangelogOptions, CompleteCommitOptions, CompleteCommitsParser, CompleteTagOptions, Context, Contributor, DefaultBumper, DefaultChangelogSections, FilledTypeGroup, FilledTypeGroupMap, GithubUserInfo, GpgSig, GpgSigCode, LifecycleStep, LogLevel, MergedConfig, ParsedCommit, RawCommit, RawReference, RefLabel, Reference, ReleaseContext, ReleaseType, ReleaseWithFlatCommits, ReleaseWithTypeGroups, RelionResult, RepoInfo, ResolvedChangelogOptions, ResolvedCommit, ResolvedConfig, ResolvedContext, ScopeGroup, SectionsSelector, TagOptions, TransformedConfig, TypeGroupDefinition, TypeGroupsMap, UserConfig, relion as default, defineConfig, sectionsSelector };
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
- import{existsSync as e,readFileSync as t,writeFileSync as n}from"node:fs";import r from"handlebars";import i from"semver";import{createHash as a}from"node:crypto";import{execSync as o}from"node:child_process";import s from"node:readline";const c={bump:!1,changelog:!1,commit:!1,tag:!1,versionSource:`versionSourceFile`,versionSourceFile:`./package.json`,newTagFormat:`v{{version}}`,commitsScope:`.`,prevReleaseTagPattern:/^v?(?<version>\d+\.\d+\.\d+)/,zeroMajorBreakingIsMinor:!0,dryRun:!1,logLevel:`info`,context:{commitHyperlink:!0,refHyperlink:!0,footerChangelogUrl:!1},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}},l={breaking:{title:`⚠️ BREAKING CHANGES`,commitType:`breaking`,show:`always`},feat:{title:`✨ Features`,commitType:`feat`,show:`always`},fix:{title:`🩹 Fixes`,commitType:`fix`,show:`always`},perf:{title:`⚡ Performance`,commitType:`perf`,show:`always`},revert:{title:`♻️ Reverts`,commitType:`revert`,show:`always`},refactor:{title:`🚜 Refactoring`,commitType:`refactor`},build:{title:`📦 Build`,commitType:`build`},docs:{title:`📚 Documentation`,commitType:`docs`},style:{title:`🎨 Style`,commitType:`style`},test:{title:`🧪 Tests`,commitType:`test`},ci:{title:`🚀 CI`,commitType:`ci`},types:{title:`🏷️ Types`,commitType:`types`},deps:{title:`🧩 Dependencies`,commitType:`chore`,filter:e=>!!e.scope?.includes(`deps`)},chore:{title:`🛠️ Chores`,commitType:`chore`},misc:{title:`⚙️ Miscellaneous`,commitType:`*`,filter:e=>e.type!==`release`&&e.scope!==`release`}},u={output:`CHANGELOG.md`,commitRange:`unreleased`,sections:l,header:`# Changelog
1
+ import{existsSync as e,readFileSync as t,writeFileSync as n}from"node:fs";import r from"handlebars";import i from"semver";import{createHash as a}from"node:crypto";import{execSync as o}from"node:child_process";import s from"node:readline";const c={breaking:{title:`⚠️ BREAKING CHANGES`,commitType:`breaking`,show:`always`},feat:{title:`✨ Features`,commitType:`feat`,show:`always`},fix:{title:`🩹 Fixes`,commitType:`fix`,show:`always`},perf:{title:`⚡ Performance`,commitType:`perf`,show:`always`},revert:{title:`♻️ Reverts`,commitType:`revert`,show:`always`},refactor:{title:`🚜 Refactoring`,commitType:`refactor`},build:{title:`📦 Build`,commitType:`build`},docs:{title:`📚 Documentation`,commitType:`docs`},style:{title:`🎨 Style`,commitType:`style`},test:{title:`🧪 Tests`,commitType:`test`},ci:{title:`🚀 CI`,commitType:`ci`},types:{title:`🏷️ Types`,commitType:`types`},deps:{title:`🧩 Dependencies`,commitType:`chore`,filter:e=>!!e.scope?.includes(`deps`)},chore:{title:`🛠️ Chores`,commitType:`chore`},misc:{title:`⚙️ Miscellaneous`,commitType:`*`,filter:e=>e.type!==`release`&&e.scope!==`release`}},l={file:`CHANGELOG.md`,output:`file`,commitRange:`unreleased`,extractFromFile:!1,sections:c,header:`# Changelog
2
2
 
3
3
 
4
- `,prevReleaseHeaderPattern:/^##.*?\d+\.\d+\.\d+/m,groupCommitsByScope:!0,maxLinesPerRelease:20,review:!1,helpers:{eq:(e,t)=>e===t,repeat:(e,t)=>e.repeat(t),isArray:e=>Array.isArray(e),isSingle:e=>e.length===1,or:(...e)=>e.slice(0,-1).some(Boolean),not:e=>!e,tagToUrlFragment:e=>`--${e.replace(` `,`-`).replace(/\./g,``)}-`},partials:{br:`
4
+ `,latestReleasePattern:/(?<header>##.*?)(?<body>###.*?)(?<footer>####.*?)##/s,commitRefLinkPattern:/\[`?(#?\w+?)`?\]\(.+?\)/g,groupCommitsByScope:!0,maxLinesPerRelease:20,review:!1,helpers:{eq:(e,t)=>e===t,repeat:(e,t)=>e.repeat(t),isArray:e=>Array.isArray(e),isSingle:e=>e.length===1,or:(...e)=>e.slice(0,-1).some(Boolean),not:e=>!e,tagToUrlFragment:e=>`--${e.replace(` `,`-`).replace(/\./g,``)}-`,toSentenceCase:function(e){let t=e.fn(this);return`${t.charAt(0).toUpperCase()}${t.slice(1)}${t.endsWith(`.`)?``:`.`}`}},partials:{br:`
5
5
  `,scope:`{{#if scope}}**{{scope}}**: {{/if}}`,commit:`{{{subject}}} {{" "}}
6
- {{~#if @root.commitHyperlink~}}
6
+ {{~#if @root.commitRefLinks~}}
7
7
  [\`{{hash}}\`]({{@root.repo.homepage}}/commit/{{hash}})
8
8
  {{~else~}}
9
9
  {{hash}}
@@ -16,36 +16,36 @@ import{existsSync as e,readFileSync as t,writeFileSync as n}from"node:fs";import
16
16
  /commits/
17
17
  {{~/if}}
18
18
  {{~tag}}`,refs:`({{#each refs~}}
19
- {{#if @root.refHyperlink~}}
19
+ {{#if @root.commitRefLinks~}}
20
20
  [{{raw}}]({{@root.repo.homepage}}/issues/{{number}})
21
21
  {{~else~}}
22
22
  {{raw}}
23
23
  {{~/if}}
24
24
  {{~#if @last}}){{else}}, {{/if}}
25
- {{~/each}}`,changelogUrl:`{{repo.homepage}}/blob/main/CHANGELOG.md#{{tagToUrlFragment tag}}`,breakingChangesIndicator:`<sup>[{{breakingChangeIndex}}]</sup>`}},d={message:`chore(release): {{newTag}}`,signOff:!1,gpgSign:!1,stageAll:!0,extraArgs:null},f={name:`{{newTag}}`,message:d.message,gpgSign:!1,force:!1,extraArgs:null},p=[{file:/package\.json$/,pattern:/(^.*?"version".*?")(.*?)(")/s,replacement:`$1{{newVersion}}$3`},{file:/package-lock\.json$/,pattern:/(^.*?"version".*?"|"packages".*?"".*"version".*?")(.*?)(")/gs,replacement:`$1{{newVersion}}$3`}],m=e=>C(v(_(g(h(e))))),h=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`)}},g=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{...c,...e,commitsParser:{...c.commitsParser,...e.commitsParser},changelog:t(`changelog`,e.changelog,u,`partials`,`helpers`),commit:t(`commit`,e.commit,d),tag:t(`tag`,e.tag,f),context:{...c.context,...e.context}}},_=e=>{let t=e=>{let t=p.find(t=>t.file.test(e));if(t)return{...t,file:e};throw Error(`File ${e} doesn't match any default versioned files. Please provide a custom pattern for this file.`)},n=e=>{if(e===!1)return!1;if(e===!0)return[r];if(Array.isArray(e))return 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:Q(e.changelog.partials)}}},v=e=>{let t=e.context??{},n=H(e.commitsParser.remoteUrlPattern),r=t.currentVersion??(e.versionSource===`latest-release-tag`?T(G(e.prevReleaseTagPattern)[0],e.prevReleaseTagPattern)??`0.0.0`:w(e.versionSourceFile));J(`Current version (from ${e.versionSource===`latest-release-tag`?`latest release tag`:`'${e.versionSourceFile.file}'`}): '${r}'`);let i=t.currentTag??G(e.prevReleaseTagPattern)[0],a=t.newVersion??E(e,r,e.commitsScope),o=t.newTag??(e.newTagPrefix===void 0?e.newTagFormat.replace(`{{version}}`,a):e.newTagPrefix+a),s=e.changelog?e.changelog.commitRange:`unreleased`,c=y(t.commits?t.commits.map(t=>typeof t==`object`&&`message`in t||typeof t==`string`?N(t,e.commitsParser,e.prevReleaseTagPattern):t).filter(e=>e!=null):M(s,e.commitsParser,e.prevReleaseTagPattern,e.commitsScope),o,e.commitsParser.revertCommitBodyPattern),l=e.changelog?b(c,e.changelog.sections,e.prevReleaseTagPattern,e.changelog.groupCommitsByScope,e.changelog.maxLinesPerRelease):null,{commits:u,...d}=t;return{...e,context:{currentVersion:r,currentTag:i,newVersion:a,newTag:o,commits:c,releases:l,...d,repo:{...n,...e.context?.repo}}}},y=(e,t,n)=>{let r=0,i=[];return e.map(a=>{let o=null,s=e.findIndex(e=>e.type===`revert`&&n.exec(e.body??``)?.groups?.hash===a.hash),c=s===-1?void 0:e[s];if(c&&(o=c.associatedReleaseTag===a.associatedReleaseTag?`inTheSameRelease`:`inOtherRelease`),o===`inTheSameRelease`){i.push(s);return}return{...a,associatedReleaseTag:a.associatedReleaseTag??t,isReverted:a.isReverted??o,breakingChangeIndex:a.breakingChanges?++r:void 0}}).filter((e,t)=>!!e&&!i.includes(t))},b=(e,t,n,r,i)=>{i??=u.maxLinesPerRelease;let a={};return e.forEach(e=>{let t=e.associatedReleaseTag;t in a?a[t].commits.push(e):a[t]={tag:t,version:T(t,n),date:e.date,commits:[e]}}),Object.values(a).map(({commits:e,...n})=>{let a=x(e,t,r);if(Object.keys(a).length===0)return;let o=0,s=!1,c={};for(let[e,t]of Object.entries(a))t.show??=`limit-or-breaking`,o+t.commits.length>i&&Object.keys(c).length&&(s=!0),t.show!==`never`&&(t.show===`only-breaking`||t.show===`limit-or-breaking`&&s?(t.commits=t.commits.filter(e=>!!e.breakingChanges),t.commits.length&&(t.scopeGroups=S(t.commits),c[e]=t,o+=t.commits.length)):(t.show===`always`||!s)&&(c[e]=t,o+=t.commits.length));return{...n,commitTypeGroups:c}}).filter(e=>!!e)},x=(e,t,n)=>{let r=Object.fromEntries(Object.entries(t).map(([e,{filter:t,...n}])=>[e,{...n,commits:[]}]));e.forEach(e=>{let n=!!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(n&&!a&&s.includes(`breaking`)){r[o].commits.push(e),a=!0;continue}if(!i&&(s.includes(e.type)||s.includes(`*`))&&(r[o].commits.push(e),i=!0),i&&(!n||a))return}});let i=Object.entries(r).filter(([e,t])=>t.commits.length);return Object.fromEntries(n?i.map(([e,t])=>[e,{...t,scopeGroups:S(t.commits)}]):i)},S=e=>{let t={};return e.forEach(e=>{let n=e.scope??``;t[n]??=[],t[n].push(e)}),Object.entries(t).map(([e,t])=>({scope:e,commits:t}))},C=e=>({...e,commit:e.commit?{...e.commit,message:r.compile(e.commit.message)(e.context)}:e.commit,tag:e.tag?{...e.tag,name:r.compile(e.tag.name)(e.context),message:r.compile(e.tag.message)(e.context)}:e.tag}),w=e=>{let n=t(e.file,`utf8`),r=e.pattern.exec(n)?.[2];if(!r)throw Error(`Version not found in '${e.file}' with pattern '${e.pattern}'`);if(!i.valid(r))throw Error(`Invalid version format in '${e.file}': '${r}'`);return r},T=(e,t)=>t.exec(e)?.groups?.version,E=(e,t,n)=>{if(e.context?.newVersion){if(!i.valid(e.context.newVersion))throw Error(`Invalid release version format: '${e.context.newVersion}'`);return e.context.newVersion}let r;e.releaseType?r=e.releaseType:(r=D(M(`unreleased`,e.commitsParser,e.prevReleaseTagPattern,n)),e.zeroMajorBreakingIsMinor&&i.major(t)===0&&r===`major`&&(r=`minor`));let a=O(t,r);return J(`Determined new version: '${a}' (release type: '${r}')`),a},D=e=>e.some(e=>e.breakingChanges)?`major`:e.some(e=>e.type===`feat`)?`minor`:`patch`,O=(e,t)=>i.inc(e,t)??(()=>{throw Error(`Failed to calculate new version from '${e}' with release type '${t}'`)})();let k=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 A=new Map;let j;const M=(e,t,n,r)=>{n??=c.prevReleaseTagPattern;let i=Array.isArray(e)?e:U(e,n,r),a=t??c.commitsParser,o=i.map(e=>N(e,a,n)).filter(e=>e!==null);return j=void 0,o},N=(e,t,n)=>{t??=c.commitsParser,n??=c.prevReleaseTagPattern,typeof e==`string`&&(e={message:e});let{tagRefs:r,hash:i=P(e.message)}=e;if(A.has(i))return A.get(i)??null;let a=e.message.trim();if(!a)throw Error(`Message is missing for commit: ${JSON.stringify(e)}`);let o;try{o=F(a,t)}catch(e){return Y(`Error parsing commit '${i}':`,e.message),null}let{type:s,scope:l,subject:u,body:d,breakingChanges:f,footer:p}=o,m=r?[...r.matchAll(t.tagPattern)].map(e=>e.groups?.tag??``):[],h=p?[...p.matchAll(t.signerPattern)].map(e=>e.groups):[],g=[],_=e=>{g.some(t=>t.email===e.email)||g.push(e)},v=e.authorName&&e.authorEmail?L({name:e.authorName,email:e.authorEmail},h):void 0;v&&_(v);let y=e.committerName&&e.committerEmail?L({name:e.committerName,email:e.committerEmail},h):void 0;y&&_(y),(p?[...p.matchAll(t.coAuthorPattern)].map(e=>e.groups).map(e=>L(e,h)):[]).forEach(e=>_(e));let b=R(p??``,t),x=e.gpgSigCode?{code:e.gpgSigCode,label:k[e.gpgSigCode],keyId:e.gpgSigKeyId}:void 0,S=e[t.dateSource===`committerDate`?`committerTs`:`authorTs`];typeof S==`string`&&(S=z(new Date(S*1e3),t.dateFormat));let C=m.find(e=>n.exec(e)),w=C??j;w&&(j=w);let T={hash:i,type:s,scope:l,subject:u,body:d,breakingChanges:f,footer:p,committer:y,gpgSig:x,date:S,releaseTag:C,associatedReleaseTag:w,tags:m.length?m:void 0,authors:g.length?g:void 0,refs:b.length?b:void 0};return i&&!A.has(i)&&A.set(i,T),T},P=e=>`fake_`+a(`sha256`).update(e,`utf8`).digest(`hex`).slice(0,7),F=(e,t)=>{let[n,...r]=e.split(`
25
+ {{~/each}}`,changelogUrl:`{{repo.homepage}}/blob/main/CHANGELOG.md#{{tagToUrlFragment tag}}`,breakingChangesIndicator:`<sup>[{{breakingChangeIndex}}]</sup>`}},u={message:`chore(release): {{newTag}}`,signOff:!1,gpgSign:!1,stageAll:!0,extraArgs:null},d={name:`{{newTag}}`,message:u.message,gpgSign:!1,force:!1,extraArgs:null},f=[{file:/package\.json$/,pattern:/(^.*?"version".*?")(.*?)(")/s,replacement:`$1{{newVersion}}$3`},{file:/package-lock\.json$/,pattern:/(^.*?"version".*?"|"packages".*?"".*"version".*?")(.*?)(")/gs,replacement:`$1{{newVersion}}$3`}],p={lifecycle:[`bump`,`changelog`,`commit`,`tag`],bump:[`package.json`],versionSource:`versionSourceFile`,versionSourceFile:`./package.json`,newTagFormat:`v{{version}}`,commitsScope:`.`,prevReleaseTagPattern:/^v?(?<version>\d+\.\d+\.\d+)/,zeroMajorBreakingIsMinor:!0,dryRun:!1,logLevel:`info`,context:{commitRefLinks:!0,footerChangelogUrl:!1},commitsParser:{headerPattern:/^(?<type>\w+)(?:\((?<scope>.+)\))?(?<bang>!)?: (?<subject>.+)/s,breakingChangesPattern:/^BREAKING CHANGES?:\s*(?<content>.+)/ms,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}},m=e=>C(v(_(g(h(e))))),h=e=>{let t=e.profile??`default`,n=e[`_${t}`];if(!n){if(e.profile===void 0)return e;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`)}},g=e=>{let t=e.lifecycle??p.lifecycle;return t=t===`all`?[`bump`,`changelog`,`commit`,`tag`]:[...new Set(t)],{...p,...e,lifecycle:t,commitsParser:{...p.commitsParser,...e.commitsParser},bump:t.includes(`bump`)?e.bump??p.bump:void 0,changelog:t.includes(`changelog`)?{...l,...e.changelog,partials:{...l.partials,...e.changelog?.partials},helpers:{...l.helpers,...e.changelog?.helpers}}:void 0,commit:t.includes(`commit`)?{...u,...e.commit}:void 0,tag:t.includes(`tag`)?{...d,...e.tag}:void 0,context:{...p.context,...e.context}}},_=e=>{let t=e=>{if(typeof e==`object`)return e;let t=f.find(t=>t.file.test(e));if(t)return{...t,file:e};throw Error(`File ${e} doesn't match any default versioned files. Please provide a custom pattern for this file.`)},n=t(e.versionSourceFile);return{...e,versionSourceFile:n,bump:e.lifecycle.includes(`bump`)?e.bump?e.bump.map(t):[n]:void 0,changelog:e.changelog?{...e.changelog,compiledPartials:Z(e.changelog,e.context)}:void 0}},v=e=>{let t=e.context,n=V(e.commitsParser.remoteUrlPattern),r=t.currentVersion??(e.versionSource===`latest-release-tag`?T(W(e.prevReleaseTagPattern)[0],e.prevReleaseTagPattern)??`0.0.0`:w(e.versionSourceFile));q(`Current version (from ${e.versionSource===`latest-release-tag`?`latest release tag`:`'${e.versionSourceFile.file}'`}): '${r}'`);let i=t.currentTag??W(e.prevReleaseTagPattern)[0],a=t.newVersion??ee(e,r,e.commitsScope),o=t.newTag??(e.newTagPrefix===void 0?e.newTagFormat.replace(`{{version}}`,a):e.newTagPrefix+a),s=e.changelog?e.changelog.commitRange:`unreleased`,c=y(t.commits?t.commits.map(t=>typeof t==`object`&&`message`in t||typeof t==`string`?M(t,e.commitsParser,e.prevReleaseTagPattern):t).filter(e=>e!=null):j(s,e.commitsParser,e.prevReleaseTagPattern,e.commitsScope),o,e.commitsParser.revertCommitBodyPattern),l=e.changelog?b(c,e.changelog.sections,e.prevReleaseTagPattern,e.changelog.groupCommitsByScope,e.changelog.maxLinesPerRelease):null,{commits:u,...d}=t;return{...e,context:{currentVersion:r,currentTag:i,newVersion:a,newTag:o,commits:c,releases:l,commitRefLinks:t.commitRefLinks??!0,footerChangelogUrl:t.footerChangelogUrl??!1,...d,repo:{...n,...e.context.repo}}}},y=(e,t,n)=>{let r=0,i=[];return e.map(a=>{let o=null,s=e.findIndex(e=>e.type===`revert`&&n.exec(e.body??``)?.groups?.hash===a.hash),c=s===-1?void 0:e[s];if(c&&(o=c.associatedReleaseTag===a.associatedReleaseTag?`inTheSameRelease`:`inOtherRelease`),o===`inTheSameRelease`){i.push(s);return}return{...a,associatedReleaseTag:a.associatedReleaseTag??t,isReverted:a.isReverted??o,breakingChangeIndex:a.breakingChanges?++r:void 0}}).filter((e,t)=>!!e&&!i.includes(t))},b=(e,t,n,r,i)=>{i??=l.maxLinesPerRelease;let a={};return e.forEach(e=>{let t=e.associatedReleaseTag;t in a?a[t].commits.push(e):a[t]={tag:t,version:T(t,n),date:e.date,commits:[e]}}),Object.values(a).map(({commits:e,...n})=>{let a=x(e,t,r);if(Object.keys(a).length===0)return;let o=0,s=!1,c={};for(let[e,t]of Object.entries(a))t.show??=`limit-or-breaking`,o+t.commits.length>i&&Object.keys(c).length&&(s=!0),t.show!==`never`&&(t.show===`only-breaking`||t.show===`limit-or-breaking`&&s?(t.commits=t.commits.filter(e=>!!e.breakingChanges),t.commits.length&&(t.scopeGroups=S(t.commits),c[e]=t,o+=t.commits.length)):(t.show===`always`||!s)&&(c[e]=t,o+=t.commits.length));return{...n,commitTypeGroups:c}}).filter(e=>!!e)},x=(e,t,n)=>{let r=Object.fromEntries(Object.entries(t).map(([e,{filter:t,...n}])=>[e,{...n,commits:[]}]));e.forEach(e=>{let n=!!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(n&&!a&&s.includes(`breaking`)){r[o].commits.push(e),a=!0;continue}if(!i&&(s.includes(e.type)||s.includes(`*`))&&(r[o].commits.push(e),i=!0),i&&(!n||a))return}});let i=Object.entries(r).filter(([e,t])=>t.commits.length);return Object.fromEntries(n?i.map(([e,t])=>[e,{...t,scopeGroups:S(t.commits)}]):i)},S=e=>{let t={};return e.forEach(e=>{let n=e.scope??``;t[n]??=[],t[n].push(e)}),Object.entries(t).map(([e,t])=>({scope:e,commits:t}))},C=e=>({...e,commit:e.commit?{...e.commit,message:r.compile(e.commit.message)(e.context)}:e.commit,tag:e.tag?{...e.tag,name:r.compile(e.tag.name)(e.context),message:r.compile(e.tag.message)(e.context)}:e.tag}),w=e=>{let n=t(e.file,`utf8`),r=e.pattern.exec(n)?.[2];if(!r)throw Error(`Version not found in '${e.file}' with pattern '${e.pattern}'`);if(!i.valid(r))throw Error(`Invalid version format in '${e.file}': '${r}'`);return r},T=(e,t)=>t.exec(e)?.groups?.version,ee=(e,t,n)=>{if(e.context.newVersion){if(!i.valid(e.context.newVersion))throw Error(`Invalid release version format: '${e.context.newVersion}'`);return e.context.newVersion}let r;e.releaseType?r=e.releaseType:(r=E(j(`unreleased`,e.commitsParser,e.prevReleaseTagPattern,n)),e.zeroMajorBreakingIsMinor&&i.major(t)===0&&r===`major`&&(r=`minor`));let a=D(t,r);return q(`Determined new version: '${a}' (release type: '${r}')`),a},E=e=>e.some(e=>e.breakingChanges)?`major`:e.some(e=>e.type===`feat`)?`minor`:`patch`,D=(e,t)=>i.inc(e,t)??(()=>{throw Error(`Failed to calculate new version from '${e}' with release type '${t}'`)})();let O=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 k=new Map;let A;const j=(e,t,n,r)=>{n??=p.prevReleaseTagPattern;let i=Array.isArray(e)?e:H(e,n,r),a=t??p.commitsParser,o=i.map(e=>M(e,a,n)).filter(e=>e!==null);return A=void 0,o},M=(e,t,n)=>{t??=p.commitsParser,n??=p.prevReleaseTagPattern,typeof e==`string`&&(e={message:e});let{tagRefs:r,hash:i=N(e.message)}=e;if(k.has(i))return k.get(i)??null;let a=e.message.trim();if(!a)throw Error(`Message is missing for commit: ${JSON.stringify(e)}`);let o;try{o=P(a,t)}catch(e){return J(`Error parsing commit '${i}':`,e.message),null}let{type:s,scope:c,subject:l,body:u,breakingChanges:d,footer:f}=o,m=r?[...r.matchAll(t.tagPattern)].map(e=>e.groups?.tag??``):[],h=f?[...f.matchAll(t.signerPattern)].map(e=>e.groups):[],g=[],_=e=>{g.some(t=>t.email===e.email)||g.push(e)},v=e.authorName&&e.authorEmail?I({name:e.authorName,email:e.authorEmail},h):void 0;v&&_(v);let y=e.committerName&&e.committerEmail?I({name:e.committerName,email:e.committerEmail},h):void 0;y&&_(y),(f?[...f.matchAll(t.coAuthorPattern)].map(e=>e.groups).map(e=>I(e,h)):[]).forEach(e=>_(e));let b=L(f??``,t),x=e.gpgSigCode?{code:e.gpgSigCode,label:O[e.gpgSigCode],keyId:e.gpgSigKeyId}:void 0,S=e[t.dateSource===`committerDate`?`committerTs`:`authorTs`];typeof S==`string`&&(S=R(new Date(S*1e3),t.dateFormat));let C=m.find(e=>n.exec(e)),w=C??A;w&&(A=w);let T={hash:i,type:s,scope:c,subject:l,body:u,breakingChanges:d,footer:f,committer:y,gpgSig:x,date:S,releaseTag:C,associatedReleaseTag:w,tags:m.length?m:void 0,authors:g.length?g:void 0,refs:b.length?b:void 0};return i&&!k.has(i)&&k.set(i,T),T},N=e=>`fake_`+a(`sha256`).update(e,`utf8`).digest(`hex`).slice(0,7),P=(e,t)=>{let[n,...r]=e.split(`
26
26
 
27
- `),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=I(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(`
27
+ `),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=F(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(`
28
28
 
29
29
  `),``]:[r.slice(0,d).join(`
30
30
 
31
31
  `),r.slice(d).join(`
32
32
 
33
- `)];return{type:a,scope:o||void 0,subject:c,body:f||void 0,breakingChanges:l,footer:p||void 0}},I=(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},L=(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}`}},R=(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=>({label:e.groups,raw:e.input})).filter(({label:e})=>!!e.number).map(({label:t,raw:n})=>({raw:n,action:e.action,owner:t.owner,repo:t.repo,number:t.number}))),z=(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])},B=/##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,V=new Map,H=e=>{let t=o(`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:a}=n.groups;return{host:r,owner:i,name:a,homepage:`https://${r}/${i}/${a}`}},U=(e,t,n)=>{let r=W(),i=G(t),a=``,s=``,c=``;if(e===`all`)a=`{{firstCommit}}`,s=`HEAD`;else if(e===`unreleased`)a=i[0]??`{{firstCommit}}`,s=`HEAD`;else if(e===`latest-release`)a=i[1]??`{{firstCommit}}`,s=i[0]??`HEAD`;else if(typeof e==`object`){let t=i.indexOf(e.releaseTag);if(t===-1)throw Error(`Release tag '${e.releaseTag}' not found`);a=i[t+1]??`{{firstCommit}}`,s=i[t]}else c=e;return a&&s&&(c=a===`{{firstCommit}}`?`"${a}^!" ${s}`:`"${a}..${s}"`),c=c.replace(`{{firstCommit}}`,r),[...o(`git log ${c} --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" -- ${n??`.`}`,{encoding:`utf8`}).matchAll(B)].map(e=>e.groups)},W=()=>o(`git rev-list --max-parents=0 HEAD`,{encoding:`utf8`}).trim(),G=e=>{e??=c.prevReleaseTagPattern;let t=e.toString();if(V.has(t))return V.get(t)??[];let n=o(`git tag --sort=-creatordate`,{encoding:`utf8`}).split(`
34
- `).filter(t=>e.test(t));return V.set(t,n),n};let K=`info`;const q=e=>K=e,J=(...e)=>{K!==`silent`&&console.log(...e)},Y=(...e)=>{K===`info`&&console.warn(...e)},X={...l,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)))},modify(e,t){return{...this,[e]:t(this[e])}}};var Z=`{{~#>header~}}
33
+ `)];return{type:a,scope:o||void 0,subject:c,body:f||void 0,breakingChanges:l,footer:p||void 0}},F=(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},I=(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}`}},L=(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=>({label:e.groups,raw:e.input})).filter(({label:e})=>!!e.number).map(({label:t,raw:n})=>({raw:n,action:e.action,owner:t.owner,repo:t.repo,number:t.number}))),R=(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])},z=/##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,B=new Map,V=e=>{let t=o(`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:a}=n.groups;return{host:r,owner:i,name:a,homepage:`https://${r}/${i}/${a}`}},H=(e,t,n)=>{let r=U(),i=W(t),a=``,s=``,c=``;if(e===`all`)a=`{{firstCommit}}`,s=`HEAD`;else if(e===`unreleased`)a=i[0]??`{{firstCommit}}`,s=`HEAD`;else if(e===`latest-release`)a=i[1]??`{{firstCommit}}`,s=i[0]??`HEAD`;else if(typeof e==`object`){let t=i.indexOf(e.releaseTag);if(t===-1)throw Error(`Release tag '${e.releaseTag}' not found`);a=i[t+1]??`{{firstCommit}}`,s=i[t]}else c=e;return a&&s&&(c=a===`{{firstCommit}}`?`"${a}^!" ${s}`:`"${a}..${s}"`),c=c.replace(`{{firstCommit}}`,r),[...o(`git log ${c} --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" -- ${n??`.`}`,{encoding:`utf8`}).matchAll(z)].map(e=>e.groups)},U=()=>o(`git rev-list --max-parents=0 HEAD`,{encoding:`utf8`}).trim(),W=e=>{e??=p.prevReleaseTagPattern;let t=e.toString();if(B.has(t))return B.get(t)??[];let n=o(`git tag --sort=-creatordate`,{encoding:`utf8`}).split(`
34
+ `).filter(t=>e.test(t));return B.set(t,n),n};let G=`info`;const K=e=>G=e,q=(...e)=>{G!==`silent`&&console.log(...e)},J=(...e)=>{G===`info`&&console.warn(...e)},Y={...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)))},modify(e,t){return{...this,[e]:t(this[e])}}};var X=`{{~#>header~}}
35
35
  ## &ensp; [\` 📦 {{tag}} \`]({{>compareLink}}){{>br}}
36
36
  {{/header}}
37
37
 
38
- {{~#>main~}}
38
+ {{~#>body~}}
39
39
  {{#each commitTypeGroups~}}
40
40
  ### {{{repeat '&nbsp;' 5}}}{{title}}
41
41
  {{#if (eq @key 'breaking')}}
42
42
  {{#each commits}}
43
43
  {{#if (isArray breakingChanges)}}
44
44
  {{~#each breakingChanges~}}
45
- - {{{this}}} {{>breakingChangesIndicator ../this}}
45
+ - {{#toSentenceCase}}{{{this}}}{{/toSentenceCase}} {{>breakingChangesIndicator ../this}}
46
46
  {{/each}}
47
47
  {{else~}}
48
- - {{{breakingChanges}}} {{>breakingChangesIndicator}}
48
+ - {{#toSentenceCase}}{{{breakingChanges}}}{{/toSentenceCase}} {{>breakingChangesIndicator}}
49
49
  {{/if}}
50
50
  {{/each}}
51
51
  {{else}}
@@ -69,8 +69,8 @@ import{existsSync as e,readFileSync as t,writeFileSync as n}from"node:fs";import
69
69
  {{/if}}
70
70
 
71
71
  {{/each}}
72
- {{/main}}
72
+ {{/body}}
73
73
 
74
74
  {{~#>footer~}}
75
75
  ##### &emsp;&ensp;&nbsp;&nbsp; {{#if footerChangelogUrl}}[_Release Changelog_]({{>changelogUrl}}) &ensp;•&ensp; {{/if}}[_All Release Commits_]({{>compareLink}}) &ensp;•&ensp; _{{date}}_{{>br}}{{>br}}
76
- {{/footer}}`;const Q=e=>{let t=Object.fromEntries(Object.entries(e).map(([e,t])=>[e,typeof t==`function`?$(e,t):t]));return Object.fromEntries(Object.entries(t).map(([e,t])=>[e,r.compile(t)]))},$=(e,t)=>{let n=RegExp(`${e}.*?}}\\s*(.*?){{~?/${e}`,`s`).exec(Z)?.[1];if(!n)throw Error(`Partial "${e}" not found in the release template.`);return t(n)},ee=async e=>{let t=s.createInterface({input:process.stdin,output:process.stdout});await new Promise(n=>{t.question(e,()=>{t.close(),n()})})},te=e=>{if(!e.bump)return null;let r=e.bump,i=e.context.newVersion;r.forEach(r=>{let a=t(r.file,`utf8`).replace(r.pattern,r.replacement.replace(`{{newVersion}}`,i));e.dryRun||n(r.file,a,`utf8`),J(`Updated version in '${r.file}' to '${i}'`)})},ne=async e=>{if(!e.changelog)return null;let t=e.changelog,n=e.context.releases;if(!n)return null;let i=G(e.prevReleaseTagPattern),a=r.create();a.registerPartial(t.compiledPartials),a.registerHelper(t.helpers);let o=t.header;return n.forEach((t,r)=>{let s=n[r+1];if(!s){let n=i.indexOf(t.tag);if(n!==-1){let t=i[n+1];s={tag:t,version:t&&T(t,e.prevReleaseTagPattern)}}else s={tag:e.context.currentTag,version:e.context.currentVersion}}let c={...t,...e.context,prevRelease:s},l=a.compile(Z)(c);o+=l}),t.output===`stdout`||e.dryRun?(J(`Generated changelog:`),console.log(o)):(J(`Writing changelog to file '${t.output}'`),re(t.output,o,t.prevReleaseHeaderPattern)),t.review&&t.output!==`stdout`&&(e.commit||e.tag)&&await ee(`Please review the changelog and press Enter to continue...`),o},re=(r,i,a)=>{let o=e(r)?t(r,{encoding:`utf8`}):``,s=o.search(a);n(r,i+o.slice(s),{encoding:`utf8`})},ie=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 J(`Committing with command: '${n}'`),e.dryRun||o(n,{stdio:`inherit`}),n},ae=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 J(`Tagging with command: '${n}'`),e.dryRun||o(n,{stdio:`inherit`}),n};async function oe(e){q((e.logLevel??(!!e.profile&&e[`_${e.profile}`]?.logLevel))||`info`);let t=m(e);return te(t),{resolvedConfig:t,generatedChangelog:await ne(t),commitCommand:ie(t),tagCommand:ae(t)}}const se=e=>e;export{oe as default,se as defineConfig,X as sectionsSelector};
76
+ {{/footer}}`;const Z=(e,n)=>{let i,a,o=Object.keys(e.partials).find(t=>e.partials[t]===`from-file`);if((e.extractFromFile||o)&&(i=t(e.file,`utf-8`),a=e.latestReleasePattern.exec(i)?.groups??{},e.extractFromFile))return Q(Object.values(a).join(``),n,e.commitRefLinkPattern);let s=Object.fromEntries(Object.entries(e.partials).map(([t,r])=>{let i;if(typeof r==`function`)i=te(t,r);else if(r===`from-file`){if(i=a?.[t]??``,!i)throw Error(`Partial '${t}' not found in the latest release changelog.`);i=Q(i,n,e.commitRefLinkPattern)}else i=r;return[t,i]}));return Object.fromEntries(Object.entries(s).map(([e,t])=>[e,r.compile(t)]))},Q=(e,t,n)=>(t.commitRefLinks===!1&&(e=e.replace(n,`$1`)),e),te=(e,t)=>{let n=RegExp(`${e}.*?}}\\s*(.*?){{~?/${e}`,`s`).exec(X)?.[1];if(!n)throw Error(`Partial "${e}" not found in the release template.`);return t(n)},ne=async e=>{let t=s.createInterface({input:process.stdin,output:process.stdout});await new Promise(n=>{t.question(e,()=>{t.close(),n()})})},re=e=>{if(!e.bump)return null;let r=e.bump,i=e.context.newVersion;r.forEach(r=>{let a=t(r.file,`utf8`).replace(r.pattern,r.replacement.replace(`{{newVersion}}`,i));e.dryRun||n(r.file,a,`utf8`),q(`Updated version in '${r.file}' to '${i}'`)})},ie=async e=>{if(!e.changelog)return null;let t=e.changelog.extractFromFile?e.changelog.compiledPartials:ae(e);return t&&await oe(e.changelog,e,t),t},ae=e=>{let t=e.changelog,n=e.context.releases;if(!n)return null;let i=W(e.prevReleaseTagPattern),a=r.create();a.registerPartial(t.compiledPartials),a.registerHelper(t.helpers);let o=t.header;return n.forEach((t,r)=>{let s=n[r+1];if(!s){let n=i.indexOf(t.tag);if(n!==-1){let t=i[n+1];s={tag:t,version:t&&T(t,e.prevReleaseTagPattern)}}else s={tag:e.context.currentTag,version:e.context.currentVersion}}let c={...t,...e.context,prevRelease:s},l=a.compile(X)(c);o+=l}),o},oe=async(e,t,n)=>{e.output===`stdout`||t.dryRun?(q(`Generated changelog:`),console.log(n)):(q(`Writing changelog to file '${e.file}'`),$(e.file,n,e.latestReleasePattern)),e.review&&e.output===`file`&&(t.commit||t.tag)&&await ne(`Please review the changelog and press Enter to continue...`)},$=(r,i,a)=>{let o=e(r)?t(r,{encoding:`utf8`}):``,s=o.search(a);n(r,i+o.slice(s),{encoding:`utf8`})},se=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 q(`Committing with command: '${n}'`),e.dryRun||o(n,{stdio:`inherit`}),n},ce=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 q(`Tagging with command: '${n}'`),e.dryRun||o(n,{stdio:`inherit`}),n};async function le(e){K((e.logLevel??(!!e.profile&&e[`_${e.profile}`]?.logLevel))||`info`);let t=m(e),n,r,i;for(let e of t.lifecycle)await{bump:()=>re(t),changelog:async()=>n=await ie(t),commit:()=>r=se(t),tag:()=>i=ce(t)}[e]();return{resolvedConfig:t,generatedChangelog:n,commitCommand:r,tagCommand:i}}const ue=e=>e;export{le as default,ue as defineConfig,Y as sectionsSelector};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "relion",
3
- "version": "0.21.0",
3
+ "version": "0.23.0",
4
4
  "description": "Release workflow helper.",
5
5
  "author": "Kh4f <kh4f.dev@gmail.com>",
6
6
  "license": "MIT",
@@ -38,11 +38,11 @@
38
38
  "devDependencies": {
39
39
  "@eslint/js": "^9.37.0",
40
40
  "@stylistic/eslint-plugin": "^5.4.0",
41
- "@types/node": "^24.7.1",
41
+ "@types/node": "^24.7.2",
42
42
  "@types/semver": "^7.7.1",
43
43
  "eslint": "^9.37.0",
44
44
  "globals": "^16.4.0",
45
- "lint-staged": "^16.2.3",
45
+ "lint-staged": "^16.2.4",
46
46
  "simple-git-hooks": "^2.13.1",
47
47
  "tsdown": "^0.15.6",
48
48
  "tsx": "^4.20.6",
@@ -64,7 +64,7 @@
64
64
  "lint:fix": "eslint --fix",
65
65
  "test": "vitest run",
66
66
  "test:watch": "vitest",
67
- "release": "pnpm relion -p local",
67
+ "release": "pnpm relion",
68
68
  "release:github": "pnpm relion -p github",
69
69
  "relion": "tsx scripts/relion-runner"
70
70
  }