change-versions 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -2
- package/dist/cli.js +53 -0
- package/docs/commands.md +230 -0
- package/package.json +39 -4
package/README.md
CHANGED
|
@@ -1,3 +1,49 @@
|
|
|
1
|
-
#
|
|
1
|
+
# change-versions
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
只给需要发的包升版本,再按那次提交发布。非正式档位不写 CHANGELOG、不打 git tag。
|
|
4
|
+
|
|
5
|
+
开发用 Bun。装好依赖后用 Node 跑 bin:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun install
|
|
9
|
+
bun run build
|
|
10
|
+
node dist/cli.js
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
开发时也可以不构建:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
bun src/cli.ts changed
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
提示语看 `LC_ALL`、`LC_MESSAGES`、`LANG`。以 `zh` 开头用中文,否则用英文。
|
|
20
|
+
|
|
21
|
+
命令说明见 [docs/commands.md](docs/commands.md)。
|
|
22
|
+
|
|
23
|
+
## 安装使用
|
|
24
|
+
|
|
25
|
+
发布到 registry 后,在使用它的仓库安装对应版本(registry 沿用 npm 配置):
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
bun add --dev change-versions@<version>
|
|
29
|
+
bunx --no-install change-versions init --yes
|
|
30
|
+
bunx --no-install change-versions changed --baseline=<首次基线>
|
|
31
|
+
bunx --no-install change-versions version prerelease --preid=alpha --baseline=<首次基线>
|
|
32
|
+
bunx --no-install change-versions publish --dist-tag=alpha
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
运行 CLI 需要 Node.js,无需 Bun;Bun 用于源码开发与构建。正式档位使用 `version patch|minor|major`。第一次 version 提交建立基线后,可以省略 `--baseline`。version/publish 分开执行,重试发布时不要再升版本。
|
|
36
|
+
|
|
37
|
+
`change-versions.yml` 使用键值配置与 include/exclude 列表,不兼容旧版缩进目录树配置。可先运行 init,在生成的文件中补上源码路径和 hooks。配置 branch 时,version 必须在该分支执行;不配置则不推送。
|
|
38
|
+
|
|
39
|
+
## 本包发布准备
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
bun run check
|
|
43
|
+
npm pack --dry-run
|
|
44
|
+
# 设置本包所需版本后,由维护者执行 npm publish
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`check` 运行类型检查、单测、临时 Git 仓库的 CLI 回归并重新构建。`prepack` 自动做类型检查和构建,保证 npm pack/publish 收录最新 dist。发布物包含 CLI、命令文档与 README,不包含源码测试。
|
|
48
|
+
|
|
49
|
+
CLI 回归通过临时 npm 替身验证发布顺序、部分失败续发、登录与网络失败、dry-run、hook、版本漂移和正式版 tag,不上传真实包。
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var ae=(e,n,t)=>()=>{if(e)try{n=e(e=0)}catch(r){t=[r]}if(t)throw t[0];return n};function ce(){let e=(process.env.LC_ALL||process.env.LC_MESSAGES||process.env.LANG||"").split(".")[0];return/^zh/i.test(e)?"zh":"en"}function i(e,n,t=ce()){let r=pn[e][t];if(n)for(let[s,o]of Object.entries(n))r=r.replaceAll(`{${s}}`,String(o));return r}var pn;var x=ae(()=>{pn={publishHeadChanged:{zh:"发布 hook 改变了 HEAD。下一步: 检查该提交,让 hook 只更新忽略的构建产物后重跑 publish",en:"A publish hook changed HEAD. Review that commit and keep hooks limited to ignored build output before retrying publish"},wrongBranch:{zh:"当前分支不是 {branch}。下一步: 切换到该分支后重跑 version",en:"Current branch is not {branch}. Next: switch to that branch and rerun version"},releaseVersionMismatch:{zh:"{name} 当前版本 {actual} 与 version 提交中的 {expected} 不一致。下一步: 检查提交和 package.json 后再发布",en:"{name} is at {actual}, but the version commit records {expected}. Check the commit and package.json before publishing"},releaseContentsChanged:{zh:"待发布包在 version 提交后又有改动。下一步: 先完成新一轮 version,再发布对应提交",en:"Release packages changed after the version commit. Next: create a new version commit before publishing"},unexpectedRegistryVersion:{zh:"registry 未返回预期版本 {name}@{version},无法确认是否已发布",en:"The registry did not return the expected version {name}@{version}"},dirtyTree:{zh:"工作区不干净。下一步: 提交或还原后,重跑刚才那条命令",en:"Working tree is dirty. Next: commit or restore your changes, then rerun the same command"},gitFailed:{zh:`git 失败。下一步: 在 git 仓库里重跑
|
|
3
|
+
{detail}`,en:`git failed. Next: rerun this inside a git repository
|
|
4
|
+
{detail}`},noPackagesSince:{zh:"自 {rev} 以来没有需要升版的包",en:"No packages to version since {rev}"},changedHeader:{zh:"变更:",en:"Changed:"},dependentsHeader:{zh:"依赖方:",en:"Dependents:"},confirmVersions:{zh:"以上版本是否确认?",en:"Apply these versions?"},cancelledVersion:{zh:"已取消。还没改文件。想继续就再跑同一条命令",en:"Cancelled. No files were changed. Rerun the same command to continue"},branchPushFailed:{zh:`分支推送失败。commit 已在本地。下一步: git push origin {branch},不要重跑 version
|
|
5
|
+
{detail}`,en:`Branch push failed. The commit is local. Next: git push origin {branch}. Do not rerun version
|
|
6
|
+
{detail}`},noVersionCommit:{zh:"没有 version 提交。下一步: 先跑 version,不要直接 publish",en:"No version commit. Next: run version first. Do not publish yet"},packageNotInDir:{zh:"正文里的包不在 {dir}: {name}",en:"Package from the commit body is not in {dir}: {name}"},noGitTag:{zh:"不打 git tag",en:"No git tag"},willPublish:{zh:"将发布:",en:"Will publish:"},privateMark:{zh:"(私有)",en:"(private)"},confirmPublish:{zh:"是否发布?",en:"Publish?"},cancelledPublish:{zh:"已取消。不跑 hook,不上传,不打 git tag",en:"Cancelled. No hooks, no upload, no git tag"},publishInterrupted:{zh:"发布已中断。已经上传的留在 registry,没有打 git tag。下一步: 重跑同一条 publish,不要重跑 version",en:"Publish interrupted. Versions already uploaded stay on the registry. No git tag was created. Next: rerun the same publish. Do not rerun version"},badBaseline:{zh:"修订无法解析: {rev}。下一步: 换成 git rev-parse 能解析的 SHA 或 tag",en:"Cannot resolve revision: {rev}. Next: pass a SHA or tag that git rev-parse accepts"},noBaseline:{zh:"没有基线。下一步: changed 或 version 加上 --baseline=SHA或tag",en:"No baseline. Next: rerun changed or version with --baseline=<sha-or-tag>"},chooseBump:{zh:"选择档位",en:"Select a bump"},versionRestored:{zh:"已退回命令开始时的 HEAD。修好后重跑 version",en:"Restored the tree to HEAD from when the command started. Fix the error, then rerun version"},tagPointsElsewhere:{zh:"git tag {tag} 指向别的 commit。下一步: 人工处理这个同名 tag 后,再重跑 publish。不要重跑 version",en:"git tag {tag} points at another commit. Next: fix that tag by hand, then rerun publish. Do not rerun version"},tagPushFailed:{zh:`git tag 没推上去。包已在 registry。下一步: 重跑同一条 publish,只补 tag,不要重跑 version
|
|
7
|
+
{detail}`,en:`git tag was not pushed. Packages are already on the registry. Next: rerun the same publish to finish tags. Do not rerun version
|
|
8
|
+
{detail}`},networkFailed:{zh:`网络失败,已重试 2 次。后面的包不发,不打 git tag。下一步: 重跑同一条 publish,不要重跑 version
|
|
9
|
+
{detail}`,en:`Network failed after 2 retries. Later packages were not published and no git tag was created. Next: rerun the same publish. Do not rerun version
|
|
10
|
+
{detail}`},notLoggedIn:{zh:"未登录 {registry}。下一步: npm login --registry={registry},然后重跑同一条 publish。不要重跑 version",en:"Not logged in to {registry}. Next: npm login --registry={registry}, then rerun the same publish. Do not rerun version"},registryUnreachable:{zh:`无法访问 {registry}。下一步: 检查网络后重跑同一条 publish。不要重跑 version
|
|
11
|
+
{detail}`,en:`Cannot reach {registry}. Next: check the network, then rerun the same publish. Do not rerun version
|
|
12
|
+
{detail}`},noNpmRegistry:{zh:"读不到 npm registry",en:"Cannot read the npm registry"},npmFailed:{zh:"npm 失败",en:"npm failed"},npmViewFailed:{zh:"npm view 失败",en:"npm view failed"},hookFailed:{zh:`{name} 失败。下一步: 修好 hook 后重跑 publish。不上传,不打 git tag
|
|
13
|
+
{detail}`,en:`{name} failed. Next: fix the hook, then rerun publish. Nothing was uploaded and no git tag was created
|
|
14
|
+
{detail}`},beforePublishDirty:{zh:"beforePublish 改了被跟踪的文件。下一步: hook 只能改 git 忽略的构建产物,弄干净后重跑 publish",en:"beforePublish changed tracked files. Next: the hook may only change gitignored build output. Clean the tree, then rerun publish"},afterPublishDirty:{zh:"afterPublish 改了被跟踪的文件,还没打 git tag。下一步: 让 hook 不改被跟踪的文件,弄干净后重跑 publish",en:"afterPublish changed tracked files, so no git tag was created. Next: keep the hook off tracked files, clean the tree, then rerun publish"},configUnreadable:{zh:"配置读不了: {file}。下一步: 补上 include,删掉不认识的字段",en:"Cannot read config: {file}. Next: add include and remove unknown fields"},packagesDirMissing:{zh:"找不到目录 {dir}",en:"Directory not found: {dir}"},packageJsonIncomplete:{zh:"{folder} 的 package.json 缺少 name 或 version",en:"{folder} package.json is missing name or version"},publicDependsOnPrivate:{zh:"public 包 {name} 不能依赖 private 包 {dep}。下一步: 改依赖后重跑 version",en:"Public package {name} cannot depend on private package {dep}. Next: change the dependency, then rerun version"},missingVersionField:{zh:"{folder} 缺少 version",en:"{folder} is missing version"},badBump:{zh:"档位非法: {bump}。可用 {list}",en:"Invalid bump: {bump}. Use {list}"},preidRequired:{zh:"{kind} 必须带 --preid。预发布用 prepatch 这类档位",en:"{kind} requires --preid. Use a pre* bump for prereleases"},preidForbidden:{zh:"正式版不能带 --preid。预发布用 prepatch 这类档位",en:"A stable bump cannot take --preid. Use a pre* bump for prereleases"},badLine:{zh:"第 {line} 行无法解析",en:"Cannot parse line {line}"},unknownField:{zh:"不认识的字段 {name}",en:"Unknown field {name}"},missingValue:{zh:"{name} 缺少值",en:"{name} is missing a value"},includeRequired:{zh:"include 不能为空。下一步: 补上 include,删掉不认识的字段",en:"include must not be empty. Next: add include and remove unknown fields"},commitMessageNeedsToken:{zh:"commitMessage 需要 %s",en:"commitMessage must contain %s"},patternBang:{zh:"模式不能包含 !: {pattern}",en:"Patterns cannot contain !: {pattern}"},patternClass:{zh:"不支持字符组: {pattern}",en:"Character classes are not supported: {pattern}"},badHook:{zh:"hooks 无法解析: {line}",en:"Cannot parse hooks: {line}"},unknownHook:{zh:"不认识的 hook {name}",en:"Unknown hook {name}"},hookMissingCommand:{zh:"{name} 缺少命令",en:"{name} is missing a command"},badPatternLine:{zh:"路径列表无法解析: {line}",en:"Cannot parse path list: {line}"},badSemver:{zh:"无法解析版本 {version}",en:"Cannot parse version {version}"},dependencyCycle:{zh:"依赖成环: {name}",en:"Dependency cycle: {name}"},bumpRequired:{zh:"非交互环境必须写上档位",en:"A bump is required when not interactive"},chooseIndex:{zh:"请输入序号: ",en:"Enter a number: "},invalidChoice:{zh:"无效选择: {answer}",en:"Invalid choice: {answer}"},emptyAnswer:{zh:"(空)",en:"(empty)"},yesRequired:{zh:"非交互环境需要 --yes",en:"Pass --yes when not interactive"},commandFailed:{zh:"{command} 失败: {detail}",en:"{command} failed: {detail}"},commandFailedShort:{zh:"{command} 失败",en:"{command} failed"},commandExit:{zh:"{command} 退出 {code}",en:"{command} exited {code}"},cliDescription:{zh:"只给需要发的包升版本,再按那次提交发布",en:"Version only the packages that need a release, then publish that commit"},optRoot:{zh:"仓库根目录",en:"Repository root"},optVersionsFile:{zh:"配置文件",en:"Config file"},optPackages:{zh:"覆盖 packagesDir",en:"Override packagesDir"},cmdChanged:{zh:"列出会升版的包",en:"List packages that would be versioned"},optBaseline:{zh:"这一次的比较起点,SHA 或 tag",en:"Comparison start for this run, SHA or tag"},cmdVersion:{zh:"升版本并提交",en:"Bump versions and commit"},argBump:{zh:"patch、minor、major、prerelease、prepatch、preminor、premajor",en:"patch, minor, major, prerelease, prepatch, preminor, or premajor"},optPreid:{zh:"预发布标识,pre* 必填",en:"Prerelease identifier, required for pre*"},optYes:{zh:"跳过确认",en:"Skip confirmation"},optDryRunVersion:{zh:"只打印旧版本到新版本",en:"Print old and new versions only"},optBranch:{zh:"覆盖配置里的 branch",en:"Override branch from the config"},optCommitMessage:{zh:"覆盖 commitMessage",en:"Override commitMessage"},cmdPublish:{zh:"发布最近一次 version 提交里的包",en:"Publish packages listed in the latest version commit"},optDistTag:{zh:"npm dist-tag",en:"npm dist-tag"},optDryRunPublish:{zh:"只打印将执行的 hook、npm publish 和 git tag",en:"Print the hooks, npm publish commands, and git tags without running them"},cmdInit:{zh:"写入带注释的配置",en:"Write a commented config file"},optYesInit:{zh:"不提问,按探测到的目录写默认配置",en:"Write defaults from the detected directory, without prompts"},configExists:{zh:"已有 {file}。下一步: 直接改这个文件,或删掉后重跑 init",en:"Config already exists: {file}. Next: edit that file, or delete it and rerun init"},initIntro:{zh:"写入 {file}",en:"Write {file}"},initFoundDirs:{zh:"发现包目录: {dirs}",en:"Package directories: {dirs}"},initPackagesDir:{zh:"包目录",en:"Package directory"},initInclude:{zh:"源码路径,逗号分隔",en:"Source paths, comma-separated"},initExclude:{zh:"排除路径,逗号分隔",en:"Excluded paths, comma-separated"},initBranch:{zh:"推送分支,回车跳过",en:"Branch to push, Enter to skip"},initBeforeCommit:{zh:"beforeCommit,回车跳过",en:"beforeCommit, Enter to skip"},initBeforePublish:{zh:"beforePublish,回车跳过",en:"beforePublish, Enter to skip"},initWrote:{zh:"已写入 {file}",en:"Wrote {file}"},initNotePackagesDir:{zh:"包所在目录。这次可用 --packages 覆盖",en:"Directory of packages. Override once with --packages"},initNoteCommitMessage:{zh:"%s 换成档位。有 --preid 时再空一格接上,例如 bump: prerelease alpha。查找看正文末尾的 Co-authored-by: change-versions <publish@change-versions.com>,不改提交作者",en:"%s becomes the bump. With --preid, a space and the id follow, for example bump: prerelease alpha. Lookup uses the Co-authored-by: change-versions <publish@change-versions.com> trailer. The commit author stays unchanged"},initNoteBranch:{zh:"不写就不推送。version 只推这个分支,不推 tag",en:"Omit to skip pushing. version pushes this branch only, not tags"},initNoteBeforeCommit:{zh:"版本和 CHANGELOG 写完之后、git commit 之前。失败会退回 HEAD",en:"After versions and CHANGELOG are written, before git commit. Failure restores HEAD"},initNoteBeforePublish:{zh:"确认之后、npm publish 之前。只能改 git 忽略的构建产物",en:"After confirm, before npm publish. May only change gitignored build output"},initNoteAfterPublish:{zh:"要发的包都已在 registry 上之后。不能把工作区弄脏",en:"After every selected package is on the registry. Must leave the tree clean"},initNoteInclude:{zh:"相对仓库根。* 和 ? 不跨过 /,** 可以。命中目录时,目录里的文件也算",en:"Relative to the repo root. * and ? do not cross /, ** may. A matching directory includes files under it"},initNoteExclude:{zh:"命中这里的文件不触发升版。package.json 另比,去掉 devDependencies 后有差异才算",en:"Files that match here do not trigger a bump. package.json is compared separately, after dropping devDependencies"}}});import Pe from"picomatch";import J from"semver";import{YAMLParseError as un,parse as fn}from"yaml";function de(e){return ze.has(e)}function Fe(e,n){if(!Ce.includes(e))throw new c(i("badBump",{bump:e,list:Ce.join(", ")}));let t=e;if(hn.has(t)&&!n)throw new c(i("preidRequired",{kind:t}));if(ze.has(t)&&n)throw new c(i("preidForbidden"));return t}function K(e){let n=yn(e);for(let d of Object.keys(n))if(!bn.has(d))throw new c(i("unknownField",{name:d}));let t=n.packagesDir===void 0?"packages":ge(n.packagesDir,"packagesDir"),r=n.commitMessage===void 0?"bump: %s":ge(n.commitMessage,"commitMessage"),s=n.branch===void 0?void 0:ge(n.branch,"branch"),o=n.hooks==null?{}:kn(n.hooks),a=n.include==null?[]:Se(n.include,"include"),g=n.exclude==null?[]:Se(n.exclude,"exclude");if(!a.length)throw new c(i("includeRequired"));if(!r.includes("%s"))throw new c(i("commitMessageNeedsToken"));for(let d of[...a,...g]){if(d.includes("!"))throw new c(i("patternBang",{pattern:d}));if(/\[[^\]]+\]/.test(d))throw new c(i("patternClass",{pattern:d}))}return{packagesDir:t,commitMessage:r,branch:s,hooks:o,include:a,exclude:g}}function yn(e){try{let n=fn(e);if(n==null)return{};if(!Ne(n))throw new c(i("badLine",{line:1}));return n}catch(n){if(n instanceof c)throw n;if(n instanceof un)throw new c(i("badLine",{line:n.linePos?.[0]?.line??1}));throw n}}function kn(e){if(!Ne(e))throw new c(i("badHook",{line:"hooks"}));let n={};for(let[t,r]of Object.entries(e)){if(!wn.has(t))throw new c(i("unknownHook",{name:t}));if(typeof r!=="string"||!r)throw new c(i("hookMissingCommand",{name:t}));n[t]=r}return n}function Se(e,n){if(!Array.isArray(e))throw new c(i("badPatternLine",{line:n}));return e.map((t)=>{if(typeof t!=="string"||!t)throw new c(i("badPatternLine",{line:n}));return t})}function ge(e,n){if(typeof e!=="string"||!e)throw new c(i("missingValue",{name:n}));return e}function Ne(e){return Boolean(e)&&typeof e==="object"&&!Array.isArray(e)}function $e(e,n){let t={dot:!0};if(Pe(n,t)(e))return!0;if(n.endsWith("/**"))return!1;return Pe(`${n}/**`,t)(e)}function le(e,n,t){return n.some((r)=>$e(e,r))&&!t.some((r)=>$e(e,r))}function je(e,n,t){let r=new Set(t),s=`${n}/`,o=new Map;for(let a of e.split(`
|
|
15
|
+
`)){if(!a.startsWith(s))continue;let g=a.slice(s.length),d=g.split("/")[0];if(!d||!g.includes("/")||!r.has(d))continue;let m=o.get(d)??[];m.push(a),o.set(d,m)}return o}function Re(e,n,t,r,s,o){let a=[],g=[];for(let d of e){let m=n.get(d);if(!m?.length){g.push(d);continue}let p=`${o}/${d}/package.json`;if(m.some((k)=>k!==p&&le(k,t,r))||m.includes(p)&&!s(d))a.push(d);else g.push(d)}return{changed:a,ignored:g}}function Be(e,n){return JSON.stringify(U(De(e)))===JSON.stringify(U(De(n)))}function De(e){if(!e||typeof e!=="object"||Array.isArray(e))return e;let n={...e};return delete n.devDependencies,n}function U(e){if(Array.isArray(e))return e.map(U);if(e&&typeof e==="object"){let n=e;return Object.fromEntries(Object.keys(n).sort().map((t)=>[t,U(n[t])]))}return e}function Ae(e,n,t){let r=t?J.inc(e,n,t):J.inc(e,n);if(!r)throw new c(i("badSemver",{version:e}));return r}function Ee(e,n,t){let r=new Set(n),s=new Map(e.map((a)=>[a,[]]));for(let a of e)for(let g of t(a))s.get(g)?.push(a);let o=[...n];while(o.length){let a=o.pop();if(!a)break;for(let g of s.get(a)??[]){if(r.has(g))continue;r.add(g),o.push(g)}}return e.filter((a)=>r.has(a))}function Te(e,n,t){let r=e.replace("%s",n);return t?`${r} ${t}`:r}function Z(e){return e.length>0&&e.every((n)=>Boolean(J.valid(n.to))&&J.prerelease(n.to)==null)}function Me(e){return/^v\d/.test(e)}function Ie(e){return/^v\d+\.\d+\.\d+$/.test(e)}function Q(e){let n=[];for(let t of e.split(`
|
|
16
|
+
`)){let r=/^(\S+) (\S+) => (\S+)$/.exec(t.trim());if(r)n.push({name:r[1],from:r[2],to:r[3]})}return n}function He(e){let n=new Map(e.map((o)=>[o.folder,o])),t=new Set,r=[],s=(o,a)=>{if(t.has(o.folder))return;if(a.has(o.folder))throw new c(i("dependencyCycle",{name:o.name}));a.add(o.folder);for(let g of o.deps){let d=n.get(g);if(d)s(d,a)}a.delete(o.folder),t.add(o.folder),r.push(o)};for(let o of e)s(o,new Set);return r}function X(e){return/ENEEDAUTH|E401|E403|need auth|not logged in|401 Unauthorized|403 Forbidden/i.test(e)}function me(e){try{return JSON.parse(e)?.error?.code==="E404"}catch{return!1}}var c,Ce,ze,hn,bn,wn,vn="publish@change-versions.com",xn,Y;var P=ae(()=>{x();c=class c extends Error{auth;constructor(e,n=!1){super(e);this.name="Fail",this.auth=n}};Ce=["patch","minor","major","prerelease","prepatch","preminor","premajor"],ze=new Set(["patch","minor","major"]),hn=new Set(["prerelease","prepatch","preminor","premajor"]);bn=new Set(["packagesDir","commitMessage","branch","hooks","include","exclude"]),wn=new Set(["beforeCommit","beforePublish","afterPublish"]);xn=`change-versions <${vn}>`,Y=`Co-authored-by: ${xn}`});import{CommitParser as Ln}from"conventional-commits-parser";import{writeChangelogString as Vn}from"conventional-changelog-writer";function on(e){return e.find((n)=>Z(Q(n.body)))?.hash}function an(e,n,t,r,s,o){let a=`${t}/${n}/package.json`,g=`${t}/${n}/`,d=[];for(let m of e)if(m.files.some((u)=>u!==a&&u.startsWith(g)&&le(u,r,s))||m.files.includes(a)&&o.has(m.hash))d.push({hash:m.hash,body:m.body});return d}async function cn(e){let n=new Date().toISOString().slice(0,10),t=[`## ${e.version} (${n})`];if(e.previousTag){let o=`../../compare/${encodeURIComponent(e.previousTag)}...${encodeURIComponent(e.currentTag)}`;t.push(`[${e.previousTag}...${e.currentTag}](${o})`)}let r=new Ln({noteKeywords:["BREAKING CHANGE","BREAKING-CHANGE"]}),s=[];for(let o of e.messages){let a;try{a=r.parse(o.body)}catch{continue}s.push({...a,hash:o.hash.slice(0,7),notes:a.notes??[],subject:a.subject})}if(s.length){let a=(await Vn(s,{version:e.version,date:n},{groupBy:"type",mainTemplate:qn,transform(g){let m=(g.notes??[]).some((u)=>/breaking/i.test(u.title)),p=g.type??"";if(Gn.has(p)&&!m)return null;if(!rn[p]&&!m)return null;return{type:rn[p]??null}}})).trim();if(a)t.push("",a);else if(e.dependencies.length)t.push("",sn(e.dependencies))}else if(e.dependencies.length)t.push("",sn(e.dependencies).trimEnd());return`${t.join(`
|
|
17
|
+
`).trim()}
|
|
18
|
+
`}function sn(e){return`### Dependencies
|
|
19
|
+
|
|
20
|
+
* update dependencies ${e.map((n)=>`${n.name}@${n.version}`).join(", ")}
|
|
21
|
+
`}var Gn,rn,qn=`{{#each commitGroups}}
|
|
22
|
+
{{#if title}}
|
|
23
|
+
### {{title}}
|
|
24
|
+
|
|
25
|
+
{{/if}}
|
|
26
|
+
{{#each commits}}
|
|
27
|
+
* {{subject}}{{#if hash}} ({{hash}}){{/if}}
|
|
28
|
+
{{/each}}
|
|
29
|
+
|
|
30
|
+
{{/each}}
|
|
31
|
+
{{#each noteGroups}}
|
|
32
|
+
### {{title}}
|
|
33
|
+
|
|
34
|
+
{{#each notes}}
|
|
35
|
+
* {{text}}
|
|
36
|
+
{{/each}}
|
|
37
|
+
|
|
38
|
+
{{/each}}
|
|
39
|
+
`;var gn=ae(()=>{P();Gn=new Set(["docs","style","chore","refactor","test","build","ci"]),rn={feat:"Features",feature:"Features",fix:"Bug Fixes",perf:"Performance Improvements",revert:"Reverts"}});import{Command as et}from"commander";import{readFileSync as nt}from"node:fs";import Sn from"node:path";import{styleText as mn}from"node:util";function N(e,n,t){return mn(e,n,{stream:t})}function D(e){return N(["bold","cyan"],e,process.stdout)}function j(e){return N("bold",e,process.stdout)}function R(e){return N("green",e,process.stdout)}function v(e){return N("dim",e,process.stdout)}function V(e){return N("cyan",e,process.stdout)}function xe(e,n,t){return`${j(e)} ${v(n)} ${v("=>")} ${R(t)}`}function M(e){let[n,...t]=e.split(`
|
|
40
|
+
`),r=N("red",n,process.stderr);if(!t.length)return r;return[r,...t.map((s)=>N("yellow",s,process.stderr))].join(`
|
|
41
|
+
`)}x();x();P();import{spawn as Le,spawnSync as Oe}from"node:child_process";function f(e,n,t){return new Promise((r)=>{let s=Le(e,n,{cwd:t,stdio:["ignore","pipe","pipe"]}),o="",a="";s.stdout.on("data",(g)=>{o+=g}),s.stderr.on("data",(g)=>{a+=g}),s.on("error",(g)=>r({code:1,stdout:o,stderr:`${a}${g.message}`})),s.on("close",(g)=>r({code:g??1,stdout:o,stderr:a}))})}async function w(e,n,t){let r=await f(e,n,t);if(r.code!==0){let s=(r.stderr||r.stdout).trim();throw new c(s?i("commandFailed",{command:e,detail:s}):i("commandFailedShort",{command:e}))}return r.stdout}function ee(e,n,t){return new Promise((r,s)=>{let o=Le(e,n,{cwd:t,stdio:"inherit"});o.on("error",s),o.on("exit",(a)=>{if(a===0)r();else s(new c(i("commandExit",{command:e,code:a??1})))})})}function pe(e,n="HEAD"){Oe("git",["reset","--hard",n],{cwd:e,stdio:"inherit"}),Oe("git",["clean","-fd"],{cwd:e,stdio:"inherit"})}x();P();import I from"node:fs";import ne from"node:path";x();P();function Ve(e){let n=e.packages.map((d)=>d.folder),t=new Map(e.packages.map((d)=>[d.folder,d])),r=new Map(e.packages.map((d)=>[d.name,d])),s=new Map(e.packages.map((d)=>[d.name,d.folder])),{changed:o}=Re(n,e.filesByFolder,e.include,e.exclude,(d)=>e.devOnly.has(d),e.packagesDir),a=Ee(n,o,(d)=>Pn(t.get(d),s));for(let d of a){let m=t.get(d);if(!m||m.private)continue;for(let p of Object.keys(m.dependencies??{}))if(r.get(p)?.private)throw new c(i("publicDependsOnPrivate",{name:m.name,dep:p}))}let g=new Set(o);return{changed:o,dependents:a.filter((d)=>!g.has(d))}}function Pn(e,n){if(!e)return[];return[...Object.keys(e.dependencies??{}),...Object.keys(e.devDependencies??{})].flatMap((r)=>{let s=n.get(r);return s?[s]:[]})}function H(e,n){let t=ne.resolve(e,n);if(!I.existsSync(t))throw new c(i("configUnreadable",{file:n}));return K(I.readFileSync(t,"utf8"))}function O(e,n){let t=ne.join(e,n);if(!I.existsSync(t))throw new c(i("packagesDirMissing",{dir:n}));return I.readdirSync(t).filter((r)=>!r.startsWith(".")&&I.existsSync(ne.join(t,r,"package.json")))}function y(e,n,t){let r=JSON.parse(I.readFileSync(ne.join(e,n,t,"package.json"),"utf8"));if(!r.name||!r.version)throw new c(i("packageJsonIncomplete",{folder:t}));return r}function te(e,n){let t=[];for(let r of["dependencies","devDependencies"])for(let s of Object.keys(e[r]??{})){let o=n.get(s);if(o)t.push(o)}return t}async function L(e){let n=await f("git",["status","--porcelain"],e);if(n.code!==0)throw new c(i("gitFailed",{detail:n.stderr.trim()}));if(n.stdout.trim())throw new c(i("dirtyTree"))}async function ue(e,n){let t=await f("git",["status","--porcelain"],e);if(t.code!==0)throw new c(i("gitFailed",{detail:t.stderr.trim()}));if(t.stdout.trim())throw new c(n)}async function fe(e){return(await w("git",["log","--format=%H%x1f%s"],e)).split(`
|
|
42
|
+
`).filter(Boolean).map((t)=>{let[r,s]=t.split("\x1F");return{hash:r,subject:s??""}})}async function G(e){let n=await w("git",["log","-F",`--grep=${Y}`,"--format=%H%x1f%s%x1f%b%x1e"],e),t=[];for(let r of n.split("\x1E")){let s=r.replace(/^\n/,"").trim();if(!s)continue;let[o,a,g]=s.split("\x1F");if(!o)continue;t.push({hash:o,subject:a??"",body:g??""})}return t}async function he(e,n){if(n){let o=await f("git",["rev-parse","--verify",`${n}^{commit}`],e);if(o.code!==0)throw new c(i("badBaseline",{rev:n}));return o.stdout.trim()}if((await f("git",["rev-parse","--verify","HEAD"],e)).code!==0)throw new c(i("noBaseline"));let r=await G(e);if(r[0])return r[0].hash;return(await fe(e)).find((o)=>Me(o.subject))?.hash??Cn()}async function re(e,n,t){let r=await he(e,t),s=O(e,n.packagesDir),o=await w("git",["diff","--name-only",r,"HEAD"],e),a=je(o,n.packagesDir,s),g=new Set;for(let[p,u]of a){let k=`${n.packagesDir}/${p}/package.json`;if(u.includes(k)&&await be(e,r,"HEAD",k))g.add(p)}let{changed:d,dependents:m}=Ve({packages:s.map((p)=>({...y(e,n.packagesDir,p),folder:p})),filesByFolder:a,devOnly:g,include:n.include,exclude:n.exclude,packagesDir:n.packagesDir});return{baseline:r,changed:d,dependents:m}}async function be(e,n,t,r){let s=await Ge(e,`${n}:${r}`),o=await Ge(e,`${t}:${r}`);if(s===null||o===null)return!1;try{return Be(JSON.parse(s),JSON.parse(o))}catch{return!1}}async function Ge(e,n){let t=await f("git",["show",n],e);return t.code===0?t.stdout:null}function Cn(){throw new c(i("noBaseline"))}async function qe(e){let n=Sn.resolve(e.root),t=H(n,e.versionsFile);if(e.packages)t.packagesDir=e.packages;await L(n);let{baseline:r,changed:s,dependents:o}=await re(n,t,e.baseline);if(!s.length&&!o.length){let a=(await w("git",["rev-parse","--short",r],n)).trim();console.log(v(i("noPackagesSince",{rev:a})));return}console.log(D(i("changedHeader")));for(let a of s)console.log(` ${j(y(n,t.packagesDir,a).name)}`);if(o.length){console.log(D(i("dependentsHeader")));for(let a of o)console.log(` ${R(y(n,t.packagesDir,a).name)}`)}}import C from"node:fs";import A from"node:path";x();P();import $n from"node:readline/promises";import{stdin as We,stdout as _e}from"node:process";x();P();function we(e){let n=$n.createInterface({input:We,output:_e});return n.question(e).finally(()=>n.close())}function q(){return Boolean(We.isTTY&&_e.isTTY)}async function Je(e,n){if(!q())throw new c(i("bumpRequired"));console.log(D(e)),n.forEach((s,o)=>{console.log(` ${j(String(o+1))}) ${s}`)});let t=(await we(i("chooseIndex"))).trim(),r=Number(t)-1;if(!Number.isInteger(r)||r<0||r>=n.length)throw new c(i("invalidChoice",{answer:t||i("emptyAnswer")}));return n[r]}async function B(e,n=""){if(!q())throw new c(i("yesRequired"));let t=n?` [${n}]`:"";return(await we(`${e}${t} `)).trim()||n}async function ie(e){if(!q())throw new c(i("yesRequired"));console.log(D(e));let n=(await we("[y/N] ")).trim().toLowerCase();return n==="y"||n==="yes"}function Dn(e){let n=new Set,t=[];for(let r of[...jn(e),...Rn(e)]){if(n.has(r))continue;n.add(r),t.push(r)}return t}function zn(e,n=ce()){let t=(o,a="")=>i(o,void 0,n).split(`
|
|
43
|
+
`).map((g)=>`${a}# ${g}`).join(`
|
|
44
|
+
`),r=(o,a,g,d)=>[t(d," "),a?` ${o}: ${W(a)}`:` # ${o}: ${g}`].join(`
|
|
45
|
+
`),s=[t("initNotePackagesDir"),`packagesDir: ${W(e.packagesDir)}`,"",t("initNoteCommitMessage"),'commitMessage: "bump: %s"',"",t("initNoteBranch"),e.branch?`branch: ${W(e.branch)}`:"# branch: main","","hooks:",r("beforeCommit",e.beforeCommit,"bun install","initNoteBeforeCommit"),r("beforePublish",e.beforePublish,"bun run build","initNoteBeforePublish"),r("afterPublish",void 0,"echo published","initNoteAfterPublish"),"",t("initNoteInclude"),"include:",...e.include.map((o)=>` - ${W(o)}`),` # - ${e.packagesDir}/*/bin`,"",t("initNoteExclude")];if(e.exclude.length)s.push("exclude:",...e.exclude.map((o)=>` - ${W(o)}`));else s.push("# exclude:",`# - ${e.packagesDir}/*/src/**/__tests__/**`);return`${s.join(`
|
|
46
|
+
`)}
|
|
47
|
+
`}async function Ke(e){let n=A.resolve(e.root),t=A.resolve(n,e.versionsFile);if(C.existsSync(t))throw new c(i("configExists",{file:e.versionsFile}));let r=Dn(n),s=r[0]??"packages",o=e.yes?Fn(s):await Nn(e.versionsFile,r,s);if(!o.include.length)throw new c(i("includeRequired"));let a=zn(o);K(a),C.mkdirSync(A.dirname(t),{recursive:!0}),C.writeFileSync(t,a),console.log(R(i("initWrote",{file:e.versionsFile})))}function Fn(e){return{packagesDir:e,include:[`${e}/*/src`],exclude:[`${e}/*/src/**/__tests__/**`]}}async function Nn(e,n,t){if(!q())throw new c(i("yesRequired"));if(console.log(D(i("initIntro",{file:e}))),n.length)console.log(v(i("initFoundDirs",{dirs:n.join(", ")})));let r=await B(i("initPackagesDir"),t),s=Ue(await B(i("initInclude"),`${r}/*/src`)),o=Ue(await B(i("initExclude"),`${r}/*/src/**/__tests__/**`)),a=await B(i("initBranch")),g=await B(i("initBeforeCommit")),d=await B(i("initBeforePublish"));return{packagesDir:r,branch:a||void 0,beforeCommit:g||void 0,beforePublish:d||void 0,include:s,exclude:o}}function Ue(e){return e.split(",").map((n)=>n.trim()).filter(Boolean)}function W(e){return/^[A-Za-z0-9_./@*+-]+$/.test(e)?e:JSON.stringify(e)}function jn(e){return An(e).flatMap((n)=>{let t=n.replace(/\/\*\*?$/,"");if(!t||t===n||t.includes("*"))return[];return C.existsSync(A.join(e,t))?[t]:[]})}function Rn(e){if(!C.existsSync(e))return[];let n=[];for(let t of C.readdirSync(e)){if(t.startsWith(".")||t==="node_modules")continue;let r=A.join(e,t);if(!C.statSync(r).isDirectory())continue;if(Bn(r))n.push(t)}return n}function Bn(e){return C.readdirSync(e).some((n)=>C.existsSync(A.join(e,n,"package.json")))}function An(e){let n=A.join(e,"package.json");if(!C.existsSync(n))return[];try{let t=JSON.parse(C.readFileSync(n,"utf8")),r=Array.isArray(t.workspaces)?t.workspaces:t.workspaces?.packages;return Array.isArray(r)?r.filter((s)=>typeof s==="string"):[]}catch{return[]}}import _ from"node:path";x();P();P();function Ye(e){let n=[];if(e.beforePublish)n.push({kind:"hook",name:"beforePublish",command:e.beforePublish});for(let t of He(e.packages.filter((r)=>!r.private))){let r=t.registry??"";n.push(t.published?{kind:"dist-tag",name:t.name,version:t.version,folder:t.folder,registry:r,tag:e.distTag}:{kind:"publish",name:t.name,version:t.version,folder:t.folder,registry:r,tag:e.distTag})}if(e.afterPublish)n.push({kind:"hook",name:"afterPublish",command:e.afterPublish});if(e.formal)for(let t of e.packages)n.push({kind:"tag",name:t.name,version:t.version,commit:e.commit});return n}async function nn(e){let n=_.resolve(e.root);await L(n);let t=(await w("git",["rev-parse","HEAD"],n)).trim(),r=H(n,e.versionsFile);if(e.packages)r.packagesDir=e.packages;let s=await Tn(n);if(!s?.lines.length)throw new c(i("noVersionCommit"));let o=O(n,r.packagesDir),a=new Map(o.map((l)=>[y(n,r.packagesDir,l).name,l])),g=s.lines.map((l)=>{let b=a.get(l.name);if(!b)throw new c(i("packageNotInDir",{dir:r.packagesDir,name:l.name}));let z=y(n,r.packagesDir,b);if(z.version!==l.to)throw new c(i("releaseVersionMismatch",{name:l.name,expected:l.to,actual:z.version}));return{...l,folder:b,pkg:z,deps:te(z,a)}}),d=await f("git",["diff","--quiet",s.hash,"HEAD","--",...g.map((l)=>`${r.packagesDir}/${l.folder}`)],n);if(d.code===1)throw new c(i("releaseContentsChanged"));if(d.code!==0)throw new c(i("gitFailed",{detail:d.stderr.trim()}));let m=Z(s.lines);if(m)await tn(n,g,s.hash);let p=new Map;for(let l of g){if(l.pkg.private)continue;p.set(l.folder,await On(_.join(n,r.packagesDir,l.folder),l.pkg))}let u=new Set;for(let l of g){let b=p.get(l.folder);if(!b||u.has(b))continue;u.add(b),await Hn(_.join(n,r.packagesDir,l.folder),b)}let k=new Set;for(let l of g){if(l.pkg.private)continue;let b=p.get(l.folder);if(!b)continue;let z=_.join(n,r.packagesDir,l.folder);await Qe(async()=>{if(await In(z,l.name,l.to,b))k.add(l.folder)})}let h=Ye({packages:g.map((l)=>({name:l.name,version:l.to,folder:l.folder,private:l.pkg.private,deps:l.deps,registry:p.get(l.folder),published:k.has(l.folder)})),distTag:e.distTag,formal:m,commit:s.hash,beforePublish:r.hooks.beforePublish,afterPublish:r.hooks.afterPublish});if(e.dryRun){for(let l of h)console.log(En(l));if(!m)console.log(v(i("noGitTag")));return}console.log(D(i("willPublish")));for(let l of g){let b=l.pkg.private?` ${v(i("privateMark"))}`:"";console.log(` ${j(l.name)} ${R(l.to)}${b}`)}if(!e.yes&&!await ie(i("confirmPublish")))throw new c(i("cancelledPublish"));let F=()=>{console.error(M(i("publishInterrupted"))),process.exit(1)};process.on("SIGINT",F),process.on("SIGTERM",F);try{await en(n,r.hooks.beforePublish,"beforePublish"),await ue(n,i("beforePublishDirty")),await Ze(n,t);for(let l of h){if(l.kind!=="publish"&&l.kind!=="dist-tag")continue;let b=_.join(n,r.packagesDir,l.folder);await Qe(async()=>{if(l.kind==="dist-tag")await Xe(b,["dist-tag","add",`${l.name}@${l.version}`,l.tag,`--registry=${l.registry}`],l.registry);else await Xe(b,["publish",`--tag=${l.tag}`,`--registry=${l.registry}`],l.registry)})}if(await en(n,r.hooks.afterPublish,"afterPublish"),await ue(n,i("afterPublishDirty")),await Ze(n,t),m)await Mn(n,r.branch,g,s.hash)}finally{process.off("SIGINT",F),process.off("SIGTERM",F)}}function En(e){if(e.kind==="hook")return`${v(`${e.name}:`)} ${V(e.command)}`;if(e.kind==="tag")return V(`git tag ${e.name}@${e.version} ${e.commit}`);if(e.kind==="dist-tag")return V(`npm dist-tag add ${e.name}@${e.version} ${e.tag} --registry=${e.registry}`);return V(`npm publish --tag=${e.tag} --registry=${e.registry} ${e.name}@${e.version}`)}async function Tn(e){if((await f("git",["rev-parse","--verify","HEAD"],e)).code!==0)return null;let t=(await G(e))[0];if(!t)return null;let r=Q(t.body);if(!r.length)return null;return{hash:t.hash,subject:t.subject,lines:r}}async function Mn(e,n,t,r){await tn(e,t,r);let s=t.map((a)=>`${a.name}@${a.to}`);for(let a of s){if((await f("git",["rev-parse","--verify",`refs/tags/${a}^{commit}`],e)).code===0)continue;await w("git",["tag",a,r],e)}if(!n)return;let o=await f("git",["push","origin",...s.map((a)=>`refs/tags/${a}`)],e);if(o.code!==0)throw new c(i("tagPushFailed",{detail:o.stderr.trim()}))}async function tn(e,n,t){for(let r of n){let s=`${r.name}@${r.to}`,o=await f("git",["rev-parse","--verify",`refs/tags/${s}^{commit}`],e);if(o.code===0&&o.stdout.trim()!==t)throw new c(i("tagPointsElsewhere",{tag:s}))}}async function Ze(e,n){if((await w("git",["rev-parse","HEAD"],e)).trim()!==n)throw new c(i("publishHeadChanged"))}async function Qe(e){let n="";for(let t=0;t<3;t++)try{await e();return}catch(r){if(r instanceof c&&r.auth)throw r;n=r instanceof Error?r.message:String(r)}throw new c(i("networkFailed",{detail:n}))}async function Xe(e,n,t){let r=await f("npm",n,e);if(r.code===0)return;let s=`${r.stderr}${r.stdout}`;if(process.stderr.write(r.stderr),X(s))throw new c(i("notLoggedIn",{registry:t}),!0);throw Error(s.trim()||i("npmFailed"))}async function In(e,n,t,r){let s=await f("npm",["view",`${n}@${t}`,"version","--json",`--registry=${r}`],e);if(s.code===0){let a;try{a=JSON.parse(s.stdout)}catch{}if(a===t)return!0;throw Error(i("unexpectedRegistryVersion",{name:n,version:t}))}let o=`${s.stderr}${s.stdout}`;if(X(o))throw new c(i("notLoggedIn",{registry:r}),!0);if(me(s.stdout)||me(s.stderr))return!1;throw Error(o.trim()||i("npmViewFailed"))}async function Hn(e,n){let t=await f("npm",["whoami",`--registry=${n}`],e);if(t.code===0)return;let r=`${t.stderr}${t.stdout}`;if(X(r))throw new c(i("notLoggedIn",{registry:n}),!0);throw new c(i("registryUnreachable",{registry:n,detail:r.trim()}))}async function On(e,n){if(n.publishConfig?.registry)return n.publishConfig.registry.replace(/\/$/,"");if(n.name.startsWith("@")&&n.name.includes("/")){let r=n.name.slice(0,n.name.indexOf("/")),s=await f("npm",["config","get",`${r}:registry`],e),o=s.stdout.trim();if(s.code===0&&o&&o!=="undefined")return o.replace(/\/$/,"")}let t=await f("npm",["config","get","registry"],e);if(t.code!==0||!t.stdout.trim())throw new c(i("noNpmRegistry"));return t.stdout.trim().replace(/\/$/,"")}async function en(e,n,t){if(!n)return;try{await ee("sh",["-c",n],e)}catch(r){let s=r instanceof Error?r.message:String(r);throw new c(i("hookFailed",{name:t,detail:s}))}}import E from"node:fs";import se from"node:path";x();P();var Wn=["patch","minor","major"],_n=["prerelease","prepatch","preminor","premajor"];async function dn(e){let n=se.resolve(e.root),t=H(n,e.versionsFile);if(e.packages)t.packagesDir=e.packages;if(e.messageFromCli&&e.commitMessage)t.commitMessage=e.commitMessage;if(e.branchFromCli)t.branch=e.branch||void 0;if(await L(n),t.branch){let m=await f("git",["symbolic-ref","--quiet","--short","HEAD"],n);if(m.code!==0||m.stdout.trim()!==t.branch)throw new c(i("wrongBranch",{branch:t.branch}))}let r=await re(n,t,e.baseline);if(!r.changed.length&&!r.dependents.length){let m=(await w("git",["rev-parse","--short",r.baseline],n)).trim();console.log(v(i("noPackagesSince",{rev:m})));return}let s=await Jn(e.bump,e.preid),o=de(s)?void 0:e.preid,a=[...r.changed,...r.dependents].map((m)=>{let p=y(n,t.packagesDir,m);return{folder:m,name:p.name,from:p.version,to:Ae(p.version,s,o)}});for(let m of a)console.log(xe(m.name,m.from,m.to));if(e.dryRun)return;if(!e.yes&&!await ie(i("confirmVersions")))throw new c(i("cancelledVersion"));let g=Un(n,(await w("git",["rev-parse","HEAD"],n)).trim());try{for(let u of a)Qn(n,t.packagesDir,u.folder,u.to);if(Xn(n,t.packagesDir),de(s))await Kn(n,t,a,e.baseline);if(t.hooks.beforeCommit)await ee("sh",["-c",t.hooks.beforeCommit],n);let m=Te(t.commitMessage,s,o),p=a.map((u)=>`${u.name} ${u.from} => ${u.to}`).join(`
|
|
48
|
+
`);await w("git",["add","--all"],n),await w("git",["commit","-m",m,"-m",p,"-m",Y],n),g.disarm()}catch(m){await g.fail(m)}if(!t.branch)return;let d=await f("git",["push","origin",t.branch],n);if(d.code!==0)throw new c(i("branchPushFailed",{branch:t.branch,detail:d.stderr.trim()}))}async function Jn(e,n){let t=e??await Je(i("chooseBump"),n?_n:Wn);return Fe(t,n)}function Un(e,n){let t=!0,r=()=>{if(!t)return;t=!1,pe(e,n),console.error(M(i("versionRestored"))),process.exit(1)};return process.on("SIGINT",r),process.on("SIGTERM",r),{disarm(){t=!1,process.off("SIGINT",r),process.off("SIGTERM",r)},fail(s){if(t)t=!1,process.off("SIGINT",r),process.off("SIGTERM",r),pe(e,n);throw s}}}async function Kn(e,n,t,r){await Promise.resolve().then(() => gn());let g=await G(e),d=(await fe(e)).find((h)=>Ie(h.subject))?.hash,m=on(g)??d??(r?await he(e,r):void 0),p=await Yn(e,m),u=new Set(t.map((h)=>h.folder)),k=new Map(O(e,n.packagesDir).map((h)=>[y(e,n.packagesDir,h).name,h]));for(let h of t){let F=`${n.packagesDir}/${h.folder}/package.json`,l=new Set;for(let S of p)if(S.files.includes(F)&&await Zn(e,S.hash,F))l.add(S.hash);let b=an(p,h.folder,n.packagesDir,n.include,n.exclude,l),z=y(e,n.packagesDir,h.folder),ln=b.length?[]:te(z,k).filter((S)=>u.has(S)).map((S)=>y(e,n.packagesDir,S)).map((S)=>({name:S.name,version:S.version})),ke=await cn({messages:b,version:h.to,previousTag:`${h.name}@${h.from}`,currentTag:`${h.name}@${h.to}`,dependencies:ln}),oe=se.join(e,n.packagesDir,h.folder,"CHANGELOG.md"),ve=E.existsSync(oe)?E.readFileSync(oe,"utf8"):"";E.writeFileSync(oe,ve?`${ke}
|
|
49
|
+
${ve}`:ke)}}async function Yn(e,n){let t=n?["rev-list","--reverse",`${n}..HEAD`]:["rev-list","--reverse","HEAD"],r=(await w("git",t,e)).split(`
|
|
50
|
+
`).filter(Boolean),s=[];for(let o of r){let a=await w("git",["log","-1","--format=%B",o],e),g=await f("git",["diff-tree","--no-commit-id","--name-only","-r","--root",o],e);s.push({hash:o,body:a,files:g.code===0?g.stdout.split(`
|
|
51
|
+
`).filter(Boolean):[]})}return s}async function Zn(e,n,t){return!await be(e,`${n}^`,n,t)}function Qn(e,n,t,r){let s=se.join(e,n,t,"package.json"),o=E.readFileSync(s,"utf8"),a=JSON.parse(o);if(typeof a.version!=="string")throw new c(i("missingVersionField",{folder:t}));a.version=r;let g=/\n([\t ]+)"/.exec(o)?.[1]??" ";E.writeFileSync(s,JSON.stringify(a,null,g)+`
|
|
52
|
+
`)}function Xn(e,n){let t=O(e,n),r=new Map(t.map((s)=>[y(e,n,s).name,y(e,n,s)]));for(let s of t){let o=se.join(e,n,s,"package.json"),a=E.readFileSync(o,"utf8"),g=JSON.parse(a),d=!1;for(let m of["dependencies","devDependencies"])for(let p of Object.keys(g[m]??{})){let u=r.get(p);if(!u)continue;let k=`^${u.version}`;if(g[m][p]!==k)g[m][p]=k,d=!0}if(d){let m=/\n([\t ]+)"/.exec(a)?.[1]??" ";E.writeFileSync(o,JSON.stringify(g,null,m)+`
|
|
53
|
+
`)}}}x();P();var T=new et;T.name("change-versions").version(JSON.parse(nt(new URL("../package.json",import.meta.url),"utf8")).version).description(i("cliDescription"));function ye(e){return e.option("--root <dir>",i("optRoot"),process.cwd()).option("--versions-file <file>",i("optVersionsFile"),"change-versions.yml").option("--packages <dir>",i("optPackages"))}T.command("init").description(i("cmdInit")).option("--root <dir>",i("optRoot"),process.cwd()).option("--versions-file <file>",i("optVersionsFile"),"change-versions.yml").option("--yes",i("optYesInit")).action(async function(){let e=this.opts();await Ke(e)});ye(T.command("changed").description(i("cmdChanged"))).option("--baseline <rev>",i("optBaseline")).action(async function(){let e=this.opts();await qe(e)});ye(T.command("version").description(i("cmdVersion")).argument("[bump]",i("argBump"))).option("--preid <id>",i("optPreid")).option("--yes",i("optYes")).option("--dry-run",i("optDryRunVersion")).option("--baseline <rev>",i("optBaseline")).option("--branch <name>",i("optBranch")).option("--commit-message <template>",i("optCommitMessage")).action(async function(e){let n=this.opts();await dn({...n,bump:e,branchFromCli:this.getOptionValueSource("branch")==="cli",messageFromCli:this.getOptionValueSource("commitMessage")==="cli"})});ye(T.command("publish").description(i("cmdPublish"))).option("--dist-tag <tag>",i("optDistTag"),"latest").option("--yes",i("optYes")).option("--dry-run",i("optDryRunPublish")).action(async function(){let e=this.opts();await nn(e)});if(process.argv.length<=2)T.help();T.parseAsync(process.argv).catch((e)=>{if(e instanceof c)console.error(M(e.message));else console.error(e);process.exit(1)});
|
package/docs/commands.md
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# 命令
|
|
2
|
+
|
|
3
|
+
对标 Lerna 的 `changed`、`version`、`publish from-package`。不做 `bootstrap`、`run`、`exec`、`add`、`link`。
|
|
4
|
+
|
|
5
|
+
`publish` 不升版,所以没有 `lerna publish patch` 这种一条命令又升版又发布。
|
|
6
|
+
|
|
7
|
+
和 Lerna 差两处:
|
|
8
|
+
|
|
9
|
+
- 非正式档位不写 CHANGELOG,也不打 git tag。`prerelease`、`prepatch`、`preminor`、`premajor` 必须带 `--preid`。`patch` 再带 `--preid` 不接受。
|
|
10
|
+
- 按需升版本。基线是最近一条正文带 `Co-authored-by: change-versions <publish@change-versions.com>` 的提交,不是 `commitMessage`,也不是上一个 git tag。提交作者仍是执行命令的人。命中 `include` 且没有命中 `exclude` 的文件,或去掉 `devDependencies` 后仍有差异的 `package.json`,才让该包入选。入选包的依赖方一并升版。没有入选包就退出,不升任何版本。
|
|
11
|
+
|
|
12
|
+
正式版(`patch`、`minor`、`major`)写各包 CHANGELOG,并把 workspace 依赖订正成 `^` 当前版本,然后提交。git tag 要等 `publish` 把非 private 包全部送到 registry,并且 `afterPublish` 成功,才打 `<name>@<version>`。tag 指向那条 version 提交。
|
|
13
|
+
|
|
14
|
+
## 使用
|
|
15
|
+
|
|
16
|
+
日常预发布:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
change-versions changed
|
|
20
|
+
change-versions version prerelease --preid=alpha
|
|
21
|
+
change-versions publish --dist-tag=alpha
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`changed` 只打印。`version` 改版本和 workspace 依赖范围,提交标题来自 `commitMessage`,例如 `bump: prerelease alpha`。`publish` 把这些版本发到 dist-tag `alpha`。registry 上已经有的版本跳过。
|
|
25
|
+
|
|
26
|
+
正式版:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
change-versions version patch
|
|
30
|
+
change-versions publish
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
`publish` 不传 `--dist-tag` 时是 `latest`。全部成功之后才打 git tag。
|
|
34
|
+
|
|
35
|
+
仓库里还没有这条 `Co-authored-by` 的提交时,不把整段历史当成变更。加上 `--baseline`,值是 `git rev-parse` 能解析的 SHA 或 tag。它不写入配置。在第一条这种提交出现之前,仍把最近一条标题以 `v` 加数字开头的提交当作基线。
|
|
36
|
+
|
|
37
|
+
没有需要发的包时,`changed` 和 `version` 退出 0,不改文件。
|
|
38
|
+
|
|
39
|
+
三条命令在执行变更或访问 registry 前都看 `git status --porcelain`。工作区不干净就退出 1。提示语看 `LC_ALL`、`LC_MESSAGES`、`LANG`:以 `zh` 开头用中文,否则用英文。
|
|
40
|
+
|
|
41
|
+
## init
|
|
42
|
+
|
|
43
|
+
`change-versions init` 在仓库根写入 `change-versions.yml`。已有文件则退出,不覆盖。
|
|
44
|
+
|
|
45
|
+
交互时依次问包目录、源码路径、排除路径、推送分支、`beforeCommit` 和 `beforePublish`。方括号里是默认值,回车就用它。路径可以逗号分隔写多条。`--yes` 不提问:包目录先看根 `package.json` 的 `workspaces`(`packages/*` 这种),再看含有子包的目录,都没有就用 `packages`。默认源码路径是 `<包目录>/*/src`,排除 `__tests__`。
|
|
46
|
+
|
|
47
|
+
文件里的 `#` 注释说明字段,读取时会跳过。
|
|
48
|
+
|
|
49
|
+
## 配置
|
|
50
|
+
|
|
51
|
+
`change-versions.yml` 放在仓库根目录。不认识的字段会失败。路径写在 `include` 和 `exclude` 下面,不写在文件顶层。
|
|
52
|
+
|
|
53
|
+
```yaml
|
|
54
|
+
packagesDir: packages
|
|
55
|
+
commitMessage: "bump: %s"
|
|
56
|
+
branch: v5
|
|
57
|
+
|
|
58
|
+
hooks:
|
|
59
|
+
beforeCommit: bun install
|
|
60
|
+
beforePublish: bun run clean && bun run build
|
|
61
|
+
|
|
62
|
+
include:
|
|
63
|
+
- packages/*/src
|
|
64
|
+
- packages/*/bin
|
|
65
|
+
|
|
66
|
+
exclude:
|
|
67
|
+
- packages/*/src/**/__tests__/**
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
- `packagesDir` 默认 `packages`。
|
|
71
|
+
- `commitMessage` 默认 `bump: %s`。只决定提交标题。`%s` 换成档位;有 `--preid` 时再空一格接上 preid。正文一行一个包:`<name> <old> => <new>`。`version` 在正文末尾追加 `Co-authored-by: change-versions <publish@change-versions.com>`,不覆盖提交作者。下次 `changed`、`version`、`publish` 按这行查找。
|
|
72
|
+
- `branch` 不写就不推送。配置了 branch 时,version 要求当前分支与其一致(包括 dry-run),避免升版提交留在别的分支却推送旧分支。`version` 只推分支,不推 tag。
|
|
73
|
+
- `include` 必填。`exclude` 可以不写。标准 YAML 列表。`*` 和 `?` 不跨过 `/`,`**` 可以。模式相对仓库根。命中目录时,目录里的文件也算命中。不支持 `!` 和方括号字符组。
|
|
74
|
+
- `package.json` 不要求写进路径。只有它变了时,去掉两边的 `devDependencies` 再比。
|
|
75
|
+
|
|
76
|
+
`hooks` 在仓库根用 shell 执行一次,不按包重复。
|
|
77
|
+
|
|
78
|
+
- `beforeCommit`:版本、依赖范围和 CHANGELOG 写完之后、`git commit` 之前。锁文件进同一次提交。失败则把工作区退回命令开始时的 HEAD。
|
|
79
|
+
- `beforePublish`:确认之后、第一个 `npm publish` 之前。只能改 git 忽略的构建产物。
|
|
80
|
+
- `afterPublish`:要发的包都已在 registry 上之后。不能把工作区弄脏。
|
|
81
|
+
|
|
82
|
+
命令行同名参数覆盖配置。`--root` 默认当前目录,`--versions-file` 默认 `change-versions.yml`。这两项不进配置文件。
|
|
83
|
+
|
|
84
|
+
registry 也不进配置。每个包按这个顺序解析,查询、上传、dist-tag 都用同一个地址:
|
|
85
|
+
|
|
86
|
+
1. `package.json` 的 `publishConfig.registry`
|
|
87
|
+
2. 否则,`@scope/name` 用 `.npmrc` 里的 `@scope:registry`
|
|
88
|
+
3. 否则用 `npm config get registry`
|
|
89
|
+
|
|
90
|
+
`"private": true` 的包不上传,正式版成功后仍打 git tag。
|
|
91
|
+
|
|
92
|
+
## 退出后下一步
|
|
93
|
+
|
|
94
|
+
```mermaid
|
|
95
|
+
flowchart TD
|
|
96
|
+
ask{"停在哪一步?"}
|
|
97
|
+
dirtyTree["工作区不干净"]
|
|
98
|
+
noBaseline["没有基线"]
|
|
99
|
+
badRev["baseline 解析失败"]
|
|
100
|
+
badYml["配置读不了或 include 为空"]
|
|
101
|
+
noneChanged["没有要升的包"]
|
|
102
|
+
badBump["档位或 preid 不合法"]
|
|
103
|
+
userNo["确认时回答否"]
|
|
104
|
+
versionRollback["version 已改文件但还没提交成功"]
|
|
105
|
+
killed["version 被强杀, 还原没跑成"]
|
|
106
|
+
branchPush["分支推送失败"]
|
|
107
|
+
noCommit["没有 version 提交"]
|
|
108
|
+
notLoggedIn["目标 registry 未登录"]
|
|
109
|
+
beforePub["beforePublish 失败"]
|
|
110
|
+
partialNpm["部分包已上传"]
|
|
111
|
+
afterDirty["afterPublish 弄脏工作区"]
|
|
112
|
+
tagGap["包已在 registry, git tag 不齐"]
|
|
113
|
+
tagClash["同名 git tag 指向别的 commit"]
|
|
114
|
+
|
|
115
|
+
ask --> dirtyTree
|
|
116
|
+
ask --> noBaseline
|
|
117
|
+
ask --> badRev
|
|
118
|
+
ask --> badYml
|
|
119
|
+
ask --> noneChanged
|
|
120
|
+
ask --> badBump
|
|
121
|
+
ask --> userNo
|
|
122
|
+
ask --> versionRollback
|
|
123
|
+
ask --> killed
|
|
124
|
+
ask --> branchPush
|
|
125
|
+
ask --> noCommit
|
|
126
|
+
ask --> notLoggedIn
|
|
127
|
+
ask --> beforePub
|
|
128
|
+
ask --> partialNpm
|
|
129
|
+
ask --> afterDirty
|
|
130
|
+
ask --> tagGap
|
|
131
|
+
ask --> tagClash
|
|
132
|
+
|
|
133
|
+
dirtyTree --> hDirty["退出 1. 提交或还原后, 重跑刚才那条命令"]
|
|
134
|
+
noBaseline --> hBase["退出 1. changed 或 version 加上 --baseline"]
|
|
135
|
+
badRev --> hRev["退出 1. 换成 git rev-parse 能解析的 SHA 或 tag"]
|
|
136
|
+
badYml --> hYml["退出 1. 补上 include, 删掉不认识的字段"]
|
|
137
|
+
noneChanged --> hNone["退出 0. 不用做"]
|
|
138
|
+
badBump --> hBump["退出 1. pre 档位带 --preid, 正式版不要带"]
|
|
139
|
+
userNo --> hNo["还没写文件也没上传. 想继续就再跑同一条命令"]
|
|
140
|
+
versionRollback --> hRoll["已退回命令开始时的 HEAD. 修好后重跑 version"]
|
|
141
|
+
killed --> hKill["下一步: git reset --hard 回到命令开始时的 HEAD, 再重跑 version"]
|
|
142
|
+
branchPush --> hPush["commit 已在本地. 手动推送该分支, 不要重跑 version"]
|
|
143
|
+
noCommit --> hCommit["退出 1. 先跑 version, 不要直接 publish"]
|
|
144
|
+
notLoggedIn --> hLogin["退出 1. npm login --registry=该地址, 然后重跑同一条 publish"]
|
|
145
|
+
beforePub --> hBefore["还没上传也没打 git tag. 修好 hook 后重跑 publish"]
|
|
146
|
+
partialNpm --> hPartial["不要重跑 version. 重跑同一条 publish, 已在 registry 的跳过"]
|
|
147
|
+
afterDirty --> hAfter["还没打 git tag. 弄干净后重跑 publish"]
|
|
148
|
+
tagGap --> hTag["重跑 publish. 指向同一 commit 的 tag 跳过"]
|
|
149
|
+
tagClash --> hClash["不覆盖. 人工处理这个同名 tag 后, 再重跑 publish"]
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
`version` 在确认之后才写文件。写入、`beforeCommit`、提交失败,以及 SIGINT、SIGTERM,都退回命令开始时的 HEAD。因为开始时工作区是干净的,提交用 `git add --all`,锁文件会一起进去。SIGKILL 来不及还原,自己 `git reset --hard` 回到命令开始时的 HEAD。
|
|
153
|
+
|
|
154
|
+
五个包里三个已经在 registry 上、两个失败时,还没有这五个 git tag。重跑同一条 `publish` 会跳过已有版本,只发剩下的。401、403、ENEEDAUTH 不重试,先 `npm login --registry=<url>`。其余网络错误每个包重试 2 次。只有 npm view 的 JSON 错误明确给出 E404 才视为目标版本不存在;认证失败、DNS/网络错误、无效响应不视为未发布。`npm publish` 和 `dist-tag add` 都算。
|
|
155
|
+
|
|
156
|
+
打 tag 如果停在半路,再跑时指向同一条 version 提交的 tag 跳过,指向别处则退出并且不覆盖。有 `branch` 时再推这些 tag,不用 `git push --tags`。远程已有同一个 tag 算成功。
|
|
157
|
+
|
|
158
|
+
## changed
|
|
159
|
+
|
|
160
|
+
```text
|
|
161
|
+
change-versions changed
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
先看工作区,再按上面的规则列出变更包和依赖方。入选里有 public 包依赖 private 工作区包时失败。不改文件,不访问 npm。
|
|
165
|
+
|
|
166
|
+
选项:`--root`、`--packages`、`--versions-file`、`--baseline`。
|
|
167
|
+
|
|
168
|
+
找到基线且分类成功则退出 0,包括一个包都没有。工作区不干净、没有基线、修订解析失败、配置或 git 失败则退出 1。
|
|
169
|
+
|
|
170
|
+
## version
|
|
171
|
+
|
|
172
|
+
```text
|
|
173
|
+
change-versions version [bump] --preid=<id>
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
`[bump]` 传给 `semver.inc`:`patch`、`minor`、`major`、`prerelease`、`prepatch`、`preminor`、`premajor`。每个包用自己的当前版本。`5.0.0-alpha.28` 加 `--preid=alpha` 时,`prerelease` 得到 `5.0.0-alpha.29`,`prepatch` 得到 `5.0.1-alpha.0`。
|
|
177
|
+
|
|
178
|
+
顺序是:工作区、选包、档位、打印旧版本到新版本、确认、写 `package.json`、订正 workspace 范围、正式版写 CHANGELOG、`beforeCommit`、`git add --all`、提交、按配置推分支。不 `npm publish`,不打 git tag。
|
|
179
|
+
|
|
180
|
+
没写档位时会提问。已有 `--preid` 时选项是四种 `pre*`,否则是 `patch`、`minor`、`major`。`--yes` 跳过确认。非交互环境必须写上档位。`--dry-run` 只打印,不写文件。
|
|
181
|
+
|
|
182
|
+
没有包可升为 0。其余失败为 1。
|
|
183
|
+
|
|
184
|
+
## publish
|
|
185
|
+
|
|
186
|
+
```text
|
|
187
|
+
change-versions publish --dist-tag=<tag>
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
只发布最近一条带这条 `Co-authored-by` 的提交正文里的包。 当前 package.json 的版本必须与该提交记录一致,且这些包的目录在该提交之后没有改动;其他目录的提交可以保留。检查失败时不会访问 npm 或上传。正式版先检查已有本地同名 tag 是否指向这条 version 提交,冲突则在上传前退出。先看工作区,再对每个目标 registry 跑 `npm whoami --registry=<url>`。未登录就不确认、不跑 hook、不上传、不打 tag。`--dry-run` 也先做这次检查,并用 `npm view` 决定打印 `npm publish` 还是 `dist-tag add`。正文里的新版本都没有预发布后缀时才打 git tag。
|
|
191
|
+
|
|
192
|
+
确认后跑 `beforePublish`,再按依赖顺序处理非 private 包。发布 hooks 不得改变 HEAD;即便把改动提交成了干净工作区,也会中止。registry 上没有该版本就 `npm publish --tag=<dist-tag> --registry=<url>`;已经有了就跳过上传,并 `npm dist-tag add`。全部上去之后跑 `afterPublish`,然后正式版才打 git tag。`pre*` 不打 git tag。
|
|
193
|
+
|
|
194
|
+
不升版本,不改 CHANGELOG,不提交,不 unpublish。
|
|
195
|
+
|
|
196
|
+
## CHANGELOG
|
|
197
|
+
|
|
198
|
+
只在正式版 `version` 里生成。`pre*` 不加载解析器。
|
|
199
|
+
|
|
200
|
+
上一次正式版是带这条 `Co-authored-by` 的提交里,正文每个新版本都没有预发布后缀的那一条。还没有这种提交时,认标题为 `v` 加 `主.次.修`、且不含预发布后缀的提交。都没有时,这次若带了 `--baseline` 就从那里算起,否则从仓库根算起。
|
|
201
|
+
|
|
202
|
+
一个提交归给某个包,当它改过的文件命中该包的 `include` 且没有命中 `exclude`,或该包的 `package.json` 在去掉 `devDependencies` 后有差异。只因依赖方被升版的包,写一条依赖更新。`feat` 进 Features,`fix` 进 Bug Fixes,`BREAKING CHANGE` 进破坏性变更。`docs`、`style`、`chore`、`refactor`、`test`、`build`、`ci` 不出现。解析不了的提交跳过。比较链接写 tag 名字,此时 tag 还没打。
|
|
203
|
+
|
|
204
|
+
根目录的 CHANGELOG 不由这个工具改。
|
|
205
|
+
|
|
206
|
+
## 接入
|
|
207
|
+
|
|
208
|
+
最小仓库:
|
|
209
|
+
|
|
210
|
+
```yaml
|
|
211
|
+
include:
|
|
212
|
+
- packages/*/src
|
|
213
|
+
hooks:
|
|
214
|
+
beforeCommit: npm install
|
|
215
|
+
beforePublish: npm run build
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
change-versions version prerelease --preid=alpha --baseline=<首次修订>
|
|
220
|
+
change-versions publish --dist-tag=alpha
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
minipack-cli 的日常预发布把不变的项放在仓库根的 `change-versions.yml`:`packagesDir` 为 `packages`,`commitMessage` 为 `bump: %s`,`branch` 为 `v5`,`beforeCommit` 是 `bun install`,`beforePublish` 是构建。命令只留下档位和 dist-tag。`@tuya-miniapp` 的私有 registry 写在各包的 `publishConfig.registry` 或 `.npmrc`,不写进这个工具。正式版仍可先用现有的 `make release`,以后再换成 `version patch` 加 `publish`。
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
## 工具自身的打包检查
|
|
227
|
+
|
|
228
|
+
`bun run check` 依次执行 typecheck、所有测试和构建。`npm pack` / `npm publish` 会通过 prepack 自动检查类型并构建最新 CLI;只上传 dist、docs、README 和 package.json 等 npm 必要元数据。设置本包发布版本及实际上传由维护者执行。
|
|
229
|
+
|
|
230
|
+
运行安装包可用 `change-versions --version` 检查版本。命令说明与源码开发使用 Bun,安装后的 Node CLI 不要求用户安装 Bun。
|
package/package.json
CHANGED
|
@@ -1,6 +1,41 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "change-versions",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"description": "
|
|
6
|
-
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Version and publish only the workspace packages that changed.",
|
|
6
|
+
"bin": {
|
|
7
|
+
"change-versions": "./dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"docs",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"check": "bun run typecheck && bun test && bun run build",
|
|
16
|
+
"prepack": "bun run typecheck && bun run build",
|
|
17
|
+
"typecheck": "tsc --noEmit",
|
|
18
|
+
"build": "bun build src/cli.ts --outfile dist/cli.js --target node --packages=external --minify",
|
|
19
|
+
"test": "bun test",
|
|
20
|
+
"change-versions": "bun src/cli.ts"
|
|
21
|
+
},
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=20.12"
|
|
24
|
+
},
|
|
25
|
+
"packageManager": "bun@1.4.2",
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"commander": "^14.0.3",
|
|
28
|
+
"conventional-changelog-writer": "^8.4.0",
|
|
29
|
+
"conventional-commits-parser": "^6.3.0",
|
|
30
|
+
"picomatch": "^4.0.3",
|
|
31
|
+
"semver": "^7.8.5",
|
|
32
|
+
"yaml": "^2.9.1"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/node": "^26.6.3",
|
|
36
|
+
"@types/picomatch": "^4.0.2",
|
|
37
|
+
"@types/semver": "^7.7.1",
|
|
38
|
+
"standard-version": "^9.5.0",
|
|
39
|
+
"typescript": "^7.0.2"
|
|
40
|
+
}
|
|
41
|
+
}
|