better-commits 1.20.1-temp.0 → 1.21.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/.better-commits.json +52 -0
- package/.github/workflows/publish.yml +34 -0
- package/.github/workflows/test.yml +27 -0
- package/.prettierignore +5 -0
- package/.prettierrc +1 -0
- package/dist/branch.js +1 -1
- package/dist/{chunk-QPUTIRGU.js → chunk-2JVEMMKH.js} +5 -5
- package/dist/{chunk-LPU7O52G.js → chunk-EANV5ZZP.js} +1 -1
- package/dist/index.js +1 -1
- package/dist/init.js +1 -1
- package/package.json +1 -6
- package/readme.md +1 -1
- package/src/args.test.ts +102 -0
- package/src/args.ts +106 -0
- package/src/branch-args.test.ts +72 -0
- package/src/branch-args.ts +106 -0
- package/src/branch-help.ts +114 -0
- package/src/branch.ts +95 -0
- package/src/default-config-template.ts +242 -0
- package/src/git.ts +60 -0
- package/src/help.ts +131 -0
- package/src/index.test.ts +7 -0
- package/src/index.ts +100 -0
- package/src/init.test.ts +123 -0
- package/src/init.ts +46 -0
- package/src/prompts/branch-checkout.prompt.ts +36 -0
- package/src/prompts/branch-confirm.prompt.ts +134 -0
- package/src/prompts/branch-description.prompt.ts +37 -0
- package/src/prompts/branch-runnable.ts +13 -0
- package/src/prompts/branch-ticket.prompt.ts +41 -0
- package/src/prompts/branch-type.prompt.ts +43 -0
- package/src/prompts/branch-user.prompt.ts +50 -0
- package/src/prompts/branch-version.prompt.ts +41 -0
- package/src/prompts/commit-body.prompt.ts +57 -0
- package/src/prompts/commit-confirm.prompt.ts +119 -0
- package/src/prompts/commit-footer.prompt.ts +195 -0
- package/src/prompts/commit-scope.prompt.ts +73 -0
- package/src/prompts/commit-status.prompt.ts +75 -0
- package/src/prompts/commit-ticket.prompt.ts +82 -0
- package/src/prompts/commit-title.prompt.ts +98 -0
- package/src/prompts/commit-type.prompt.ts +93 -0
- package/src/prompts/runnable.ts +13 -0
- package/src/utils/build-branch.test.ts +141 -0
- package/src/utils/build-branch.ts +46 -0
- package/src/utils/build-commit-string.test.ts +253 -0
- package/src/utils/build-commit-string.ts +158 -0
- package/src/utils/commit-title-size.ts +24 -0
- package/src/utils/infer.test.ts +83 -0
- package/src/utils/infer.ts +114 -0
- package/src/utils/messages.ts +25 -0
- package/src/utils/no-interactive-branch-validation.test.ts +170 -0
- package/src/utils/no-interactive-validation.test.ts +174 -0
- package/src/utils/no-interactive-validation.ts +190 -0
- package/src/utils.test.ts +164 -0
- package/src/utils.ts +235 -0
- package/src/valibot-consts.ts +114 -0
- package/src/valibot-state.test.ts +48 -0
- package/src/valibot-state.ts +265 -0
- package/tsconfig.json +15 -0
- package/tsup.config.ts +12 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"commit_type": {
|
|
3
|
+
"append_emoji_to_label": true,
|
|
4
|
+
"append_emoji_to_commit": false
|
|
5
|
+
},
|
|
6
|
+
"commit_body": {
|
|
7
|
+
"split_by_period": true
|
|
8
|
+
},
|
|
9
|
+
"commit_scope": {
|
|
10
|
+
"enable": true,
|
|
11
|
+
"initial_value": "commit",
|
|
12
|
+
"options": [
|
|
13
|
+
{
|
|
14
|
+
"value": "commit",
|
|
15
|
+
"label": "commit"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"value": "branch",
|
|
19
|
+
"label": "branch"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"value": "init",
|
|
23
|
+
"label": "init"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"value": "util",
|
|
27
|
+
"label": "util"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"value": "build",
|
|
31
|
+
"label": "build"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"value": "help",
|
|
35
|
+
"label": "help"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"value": "",
|
|
39
|
+
"label": "none"
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
"check_ticket": {
|
|
44
|
+
"prepend_hashtag": "Always"
|
|
45
|
+
},
|
|
46
|
+
"branch_pre_commands": [
|
|
47
|
+
"git stash",
|
|
48
|
+
"git checkout main",
|
|
49
|
+
"git pull -r origin main",
|
|
50
|
+
"npm install"
|
|
51
|
+
]
|
|
52
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: Publish to NPM
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
publish:
|
|
10
|
+
name: Publish
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
permissions:
|
|
13
|
+
contents: write
|
|
14
|
+
issues: write
|
|
15
|
+
pull-requests: write
|
|
16
|
+
id-token: write
|
|
17
|
+
steps:
|
|
18
|
+
- name: Checkout
|
|
19
|
+
uses: actions/checkout@v4
|
|
20
|
+
with:
|
|
21
|
+
fetch-depth: 0
|
|
22
|
+
- name: Setup Node.js
|
|
23
|
+
uses: actions/setup-node@v4
|
|
24
|
+
with:
|
|
25
|
+
node-version: "lts/*"
|
|
26
|
+
registry-url: "https://registry.npmjs.org"
|
|
27
|
+
- name: Install dependencies
|
|
28
|
+
run: npm ci
|
|
29
|
+
- name: Build package
|
|
30
|
+
run: npm run build
|
|
31
|
+
- name: Release
|
|
32
|
+
env:
|
|
33
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
34
|
+
run: npx semantic-release
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: Test
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
push:
|
|
6
|
+
branches:
|
|
7
|
+
- main
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
name: npm test
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- name: Checkout
|
|
15
|
+
uses: actions/checkout@v4
|
|
16
|
+
|
|
17
|
+
- name: Setup Node.js
|
|
18
|
+
uses: actions/setup-node@v4
|
|
19
|
+
with:
|
|
20
|
+
node-version: "lts/*"
|
|
21
|
+
cache: npm
|
|
22
|
+
|
|
23
|
+
- name: Install dependencies
|
|
24
|
+
run: npm ci
|
|
25
|
+
|
|
26
|
+
- name: Run tests
|
|
27
|
+
run: npm run test
|
package/.prettierignore
ADDED
package/.prettierrc
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|
package/dist/branch.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#! /usr/bin/env node
|
|
2
|
-
import{c as V,e as H,f as D,i as h}from"./chunk-
|
|
2
|
+
import{c as V,e as H,f as D,i as h}from"./chunk-EANV5ZZP.js";import{e as T,j as A,k as F,l as E,m as u,o as _,r as G,s as L}from"./chunk-2JVEMMKH.js";import at from"configstore";import{chdir as ct}from"process";import{ValiError as pt,parse as U}from"valibot";var a=class{constructor(t,r,n){this.config=t;this.branch_state=r;this.prompt_cache=n}};import*as l from"@clack/prompts";var f=class extends a{async run(){if(this.#e){let t=await l.select({message:this.#t,initialValue:this.#r,options:A});l.isCancel(t)&&process.exit(),this.#n(t)}}get#t(){return"Checkout a branch or create a worktree?"}get#e(){return this.config.worktrees.enable}get#r(){return this.branch_state.checkout||this.config.branch_action_default}#n(t){this.branch_state.checkout=t}};import*as b from"@clack/prompts";var d=class extends a{async run(){if(!this.#t)return;let t=await b.text({message:this.#r,placeholder:"",initialValue:this.#n,validate:r=>this.#i(r)});b.isCancel(t)&&process.exit(0),this.#o(t??"")}get#t(){return this.config.branch_user.enable}get#e(){return this.config.branch_user.required}get#r(){return this.#e?"Type your git username":h("Type your git username")}get#n(){return this.branch_state.user||G(this.prompt_cache,"username")}#i(t){if(this.#e&&!t)return"Please enter a username"}#o(t){this.branch_state.user=t.replace(/\s+/g,"-").toLowerCase(),L(this.prompt_cache,"username",this.branch_state.user)}};import*as v from"@clack/prompts";var y=class extends a{async run(){if(!this.#t)return;let t=await v.select({message:this.#e,initialValue:this.#r,options:this.#n});v.isCancel(t)&&process.exit(0),this.#i(t)}get#t(){return this.config.branch_type.enable}get#e(){return"Select a branch type"}get#r(){return this.branch_state.type||this.config.commit_type.initial_value}get#n(){return this.config.commit_type.options}#i(t){this.branch_state.type=t}};import*as w from"@clack/prompts";var k=class extends a{async run(){if(!this.#t)return;let t=await w.text({message:this.#r,placeholder:"",validate:r=>this.#n(r),initialValue:this.branch_state.ticket});w.isCancel(t)&&process.exit(0),this.#i(t??"")}get#t(){return this.config.branch_ticket.enable}get#e(){return this.config.branch_ticket.required}get#r(){return this.#e?"Type ticket / issue number":h("Type ticket / issue number")}#n(t){if(this.#e&&!t)return"Please enter a ticket / issue"}#i(t){this.branch_state.ticket=t}};import*as C from"@clack/prompts";var x=class extends a{async run(){if(!this.#t)return;let t=await C.text({message:this.#r,placeholder:"",validate:r=>this.#n(r),initialValue:this.branch_state.version});C.isCancel(t)&&process.exit(0),this.#i(t??"")}get#t(){return this.config.branch_version.enable}get#e(){return this.config.branch_version.required}get#r(){return this.#e?"Type version number":h("Type version number")}#n(t){if(this.#e&&!t)return"Please enter a version"}#i(t){this.branch_state.version=t}};import*as I from"@clack/prompts";var $=class extends a{async run(){let t=await I.text({message:this.#t,placeholder:"",validate:r=>this.#r(r),initialValue:this.branch_state.description});I.isCancel(t)&&process.exit(0),this.#n(t??"")}get#t(){return"Type a short description"}get#e(){return this.config.branch_description.max_length}#r(t){if(!t)return"Please enter a description";if(t.length>this.#e)return`Exceeded max length. Description max [${this.#e}]`}#n(t){this.branch_state.description=t.replace(/\s+/g,"-").toLowerCase()}};import*as m from"@clack/prompts";import{execSync as S}from"child_process";import p from"picocolors";import{chdir as rt}from"process";import{parse as X}from"@bomb.sh/args";var q=["user","type","description","ticket","branch-version","checkout"],Y=["git-dir","work-tree"],Z=["interactive","dry-run","help","version"],P=class{#t;constructor(t){this.#t=t}get interactive(){return!this.#t.no_interactive}get dry_run(){return this.#t.dry_run}get help(){return this.#t.help}get version(){return this.#t.version}get git_args(){return this.#t.git_args}get branch_state(){return this.#t.branch_state}},s=new P(tt(process.argv.slice(2)));function tt(e){let t=X(e,{alias:{h:"help",v:"version"},boolean:Z,string:[...q,...Y]}),r={};return q.forEach(n=>{let i=t[n];if(i){let o=n==="branch-version"?"version":n.replace("-","_");o==="checkout"?r[o]=i??"branch":r[o]=i}}),{help:t.help===!0,version:t.version===!0,git_args:et(t["git-dir"],t["work-tree"]),no_interactive:t.interactive===!1,dry_run:t["dry-run"]===!0,branch_state:r}}function et(e,t){return`${e?`--git-dir=${e}`:""} ${t?`--work-tree=${t}`:""}`.trim()}function j(e,t){let r="";return t.branch_order.forEach(n=>{let i=`branch_${n}`;e[n]&&(r+=e[n]+t[i].separator)}),r.endsWith("-")||r.endsWith("/")||r.endsWith("_")?r.slice(0,-1).trim():r.trim()}function W(e,t,r){let n=r.split("/").pop()||"repo",i=t.worktrees.folder_template;i=i.replace("{{repo_name}}",n).replace("{{branch_description}}",e.description).replace("{{user}}",e.user||"").replace("{{type}}",e.type||"").replace("{{ticket}}",e.ticket||"").replace("{{version}}",e.version||""),i=i.replace(/\s/g,"").replace(/--+/g,"-").replace(/^-+|-+$/g,"");let o=t.worktrees.base_path;return`${o}${o.endsWith("/")?"":"/"}${i}`}var g=class extends a{async run(){this.#i(),this.#o(),this.#a()}get#t(){return this.branch_state.checkout==="worktree"}get#e(){return this.#t?this.config.worktree_pre_commands:this.config.branch_pre_commands}get#r(){return this.#t?this.config.worktree_post_commands:this.config.branch_post_commands}get#n(){return j(this.branch_state,this.config)}#i(){this.#s(this.#e,"Something went wrong when executing pre-commands: ")}#o(){let t=this.#n,r=this.#c(t);if(!this.#t){try{S(`git ${s.git_args} checkout ${r} ${t}`,{stdio:"inherit"}),m.log.info(`Switched to a new branch '${p.bgGreen(" "+p.black(t)+" ")}'`)}catch{process.exit(0)}return}try{let n=W(this.branch_state,this.config,u(s.git_args));S(`git ${s.git_args} worktree add ${n} ${r} ${t}`,{stdio:"inherit"}),m.log.info(`Created a new worktree ${p.bgGreen(" "+p.black(n)+" ")}, checked out branch ${p.bgGreen(" "+p.black(t)+" ")}`),m.log.info(p.bgMagenta(p.black(` cd ${n} `))+" to navigate to your new worktree"),rt(n)}catch{process.exit(0)}}#a(){this.#s(this.#r,"Something went wrong when executing post-commands: ")}#s(t,r){t.forEach(n=>{try{S(n,{stdio:"inherit"})}catch(i){m.log.error(r+i),process.exit(0)}})}#c(t){let r="";try{S(`git ${s.git_args} show-ref ${t}`,{encoding:"utf-8"}),m.log.warning(p.yellow(`${t} already exists! Checking out existing branch.`))}catch{r="-b"}return r}};import{execSync as nt}from"child_process";import c from"picocolors";var it={"--interactive":"Run in interactive prompt mode (default behavior).","--dry-run":"Print branch commands without creating a branch or worktree.","--help":"Show help information and exit."},ot={"--user":"Set branch username segment.","--type":"Set branch type (for example feat, fix, docs).","--description":"Set branch description segment.","--ticket":"Set branch ticket/issue segment.","--branch-version":"Set branch version segment.","--checkout":"Choose branch or worktree checkout mode."},st={"--git-dir":"Set the path to the .git directory.","--work-tree":"Set the path to the working tree root."};function N(e){let n=" ";return Object.entries(e).map(([i,o])=>{let B=Math.max(2,26-i.length);return`${n}${i}${" ".repeat(B)}${o}`}).join(`
|
|
3
3
|
`)}function M(e,t){let r=_(),n="(none)";try{n=nt(`git ${s.git_args} branch --show-current`,{stdio:"pipe"}).toString().trim()||"(none)"}catch{}let i=H(e.commit_type.options,s.git_args)||"Unknown",o=e.check_ticket.infer_ticket?D({append_hashtag:e.check_ticket.append_hashtag,prepend_hashtag:e.check_ticket.prepend_hashtag},s.git_args)||"Unknown":"Infer Disabled",B=e.commit_type.options.map(R=>R.value).join(", ").trim(),z=e.commit_scope.options.map(R=>R.value).join(", ").trim(),J=N(it),K=N(st),Q=N(ot);console.log(`
|
|
4
4
|
${c.green("\uF489 better-branch")} ${c.gray("v"+r)}
|
|
5
5
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import*as e from"valibot";import*as l from"valibot";var s="custom",
|
|
1
|
+
import*as e from"valibot";import*as l from"valibot";var s="custom",h=["closes","trailer","breaking-change","deprecated","custom"],u=l.picklist(["branch","worktree"]),m=l.picklist(["closes","trailer","breaking-change","deprecated","custom"]),d=l.picklist(["user","version","type","ticket","description"]),K=l.picklist(["branch_user","branch_version","branch_type","branch_ticket","branch_description"]),C=["user","version","type","ticket","description"],y=[{value:"app",label:"app"},{value:"shared",label:"shared"},{value:"server",label:"server"},{value:"tools",label:"tools"},{value:"",label:"none"}],k=[{value:"feat",label:"feat",hint:"A new feature",emoji:"\u{1F31F}",trailer:"Changelog: feature"},{value:"fix",label:"fix",hint:"A bug fix",emoji:"\u{1F41B}",trailer:"Changelog: fix"},{value:"docs",label:"docs",hint:"Documentation only changes",emoji:"\u{1F4DA}",trailer:"Changelog: documentation"},{value:"refactor",label:"refactor",hint:"A code change that neither fixes a bug nor adds a feature",emoji:"\u{1F528}",trailer:"Changelog: refactor"},{value:"perf",label:"perf",hint:"A code change that improves performance",emoji:"\u{1F680}",trailer:"Changelog: performance"},{value:"test",label:"test",hint:"Adding missing tests or correcting existing tests",emoji:"\u{1F6A8}",trailer:"Changelog: test"},{value:"build",label:"build",hint:"Changes that affect the build system or external dependencies",emoji:"\u{1F6A7}",trailer:"Changelog: build"},{value:"ci",label:"ci",hint:"Changes to our CI configuration files and scripts",emoji:"\u{1F916}",trailer:"Changelog: ci"},{value:"chore",label:"chore",hint:"Other changes that do not modify src or test files",emoji:"\u{1F9F9}",trailer:"Changelog: chore"},{value:"",label:"none"}];var N=e.pipe(e.optional(e.object({enable:e.optional(e.boolean(),!0),initial_value:e.optional(e.string(),"feat"),max_items:e.optional(e.pipe(e.number(),e.minValue(1)),20),infer_type_from_branch:e.optional(e.boolean(),!0),append_emoji_to_label:e.optional(e.boolean(),!1),append_emoji_to_commit:e.optional(e.boolean(),!1),emoji_commit_position:e.optional(e.picklist(["Start","After-Colon"]),"Start"),options:e.optional(e.array(e.object({value:e.string(),label:e.optional(e.string()),hint:e.optional(e.string()),emoji:e.optional(e.pipe(e.string(),e.emoji())),trailer:e.optional(e.string())})),k)}),{}),e.rawCheck(({dataset:o,addIssue:t})=>{o.typed&&!o.value.options.some(r=>r.value===o.value.initial_value)&&t({message:`Type: initial_value "${o.value.initial_value}" must exist in options`})}),e.transform(o=>({...o,options:o.options.map(t=>({...t,label:t.emoji&&o.append_emoji_to_label?`${t.emoji} ${t.label}`:t.label}))}))),R=e.pipe(e.optional(e.object({enable:e.optional(e.boolean(),!0),custom_scope:e.optional(e.boolean(),!1),max_items:e.optional(e.pipe(e.number(),e.minValue(1)),20),initial_value:e.optional(e.string(),"app"),options:e.optional(e.array(e.object({value:e.string(),label:e.optional(e.string()),hint:e.optional(e.string())})),y)}),{}),e.rawCheck(({dataset:o,addIssue:t})=>{if(!o.typed)return;let r=o.value.options.map(i=>i.value);o.value.custom_scope&&r.push(s),r.includes(o.value.initial_value)||t({message:`Scope: initial_value "${o.value.initial_value}" must exist in options`})}),e.transform(o=>{let t=o.options.map(r=>r.value);return o.custom_scope&&!t.includes(s)?{...o,options:[...o.options,{label:s,value:s,hint:"Write a custom scope"}]}:o})),_=e.object({check_status:e.optional(e.boolean(),!0),commit_type:N,commit_scope:R,check_ticket:e.optional(e.object({infer_ticket:e.optional(e.boolean(),!0),confirm_ticket:e.optional(e.boolean(),!0),add_to_title:e.optional(e.boolean(),!0),append_hashtag:e.optional(e.boolean(),!1),prepend_hashtag:e.optional(e.picklist(["Never","Always","Prompt"]),"Never"),surround:e.optional(e.picklist(["","()","[]","{}"]),""),title_position:e.optional(e.picklist(["start","end","before-colon","beginning"]),"start")}),{}),commit_title:e.optional(e.object({max_size:e.optional(e.pipe(e.number(),e.minValue(1)),70)}),{}),commit_body:e.optional(e.object({enable:e.optional(e.boolean(),!0),required:e.optional(e.boolean(),!1),split_by_period:e.optional(e.boolean(),!1)}),{}),commit_footer:e.optional(e.object({enable:e.optional(e.boolean(),!0),initial_value:e.optional(e.array(m),[]),options:e.optional(e.array(m),h)}),{}),breaking_change:e.optional(e.object({add_exclamation_to_title:e.optional(e.boolean(),!0)}),{}),cache_last_value:e.optional(e.boolean(),!0),confirm_with_editor:e.optional(e.boolean(),!1),confirm_commit:e.optional(e.boolean(),!0),print_commit_output:e.optional(e.boolean(),!0),branch_pre_commands:e.optional(e.array(e.string()),[]),branch_post_commands:e.optional(e.array(e.string()),[]),worktree_pre_commands:e.optional(e.array(e.string()),[]),worktree_post_commands:e.optional(e.array(e.string()),[]),branch_user:e.optional(e.object({enable:e.optional(e.boolean(),!0),required:e.optional(e.boolean(),!1),separator:e.optional(e.picklist(["/","-","_"]),"/")}),{}),branch_type:e.optional(e.object({enable:e.optional(e.boolean(),!0),separator:e.optional(e.picklist(["/","-","_"]),"/")}),{}),branch_version:e.optional(e.object({enable:e.optional(e.boolean(),!1),required:e.optional(e.boolean(),!1),separator:e.optional(e.picklist(["/","-","_"]),"/")}),{}),branch_ticket:e.optional(e.object({enable:e.optional(e.boolean(),!0),required:e.optional(e.boolean(),!1),separator:e.optional(e.picklist(["/","-","_"]),"-")}),{}),branch_description:e.optional(e.object({max_length:e.optional(e.pipe(e.number(),e.minValue(1)),70),separator:e.optional(e.picklist(["","/","-","_"]),"")}),{}),branch_action_default:e.optional(u,"branch"),branch_order:e.optional(e.array(d),C),enable_worktrees:e.optional(e.boolean(),!0),worktrees:e.optional(e.object({enable:e.optional(e.boolean(),!0),base_path:e.optional(e.string(),".."),folder_template:e.optional(e.string(),"{{repo_name}}-{{ticket}}-{{branch_description}}")}),{}),overrides:e.optional(e.object({shell:e.optional(e.string())}),{})}),P={type:e.optional(e.string(),""),scope:e.optional(e.string(),""),title:e.optional(e.string(),""),body:e.optional(e.string(),""),closes:e.optional(e.string(),""),ticket:e.optional(e.string(),""),breaking_title:e.optional(e.string(),""),breaking_body:e.optional(e.string(),""),deprecates:e.optional(e.string(),""),deprecates_title:e.optional(e.string(),""),deprecates_body:e.optional(e.string(),""),custom_footer:e.optional(e.string(),""),trailer:e.optional(e.string(),"")},Q=e.optional(e.object(P),{}),F={user:e.optional(e.string(),""),type:e.optional(e.string(),""),ticket:e.optional(e.string(),""),description:e.optional(e.string(),""),version:e.optional(e.string(),""),checkout:e.optional(u,"branch")},X=e.optional(e.object(F),{});import{parse as L}from"@bomb.sh/args";var O=["type","scope","title","body","closes","ticket","trailer","deprecates","breaking-title","breaking-body","deprecates-title","deprecates-body","custom-footer"],D=["git-dir","work-tree"],$=["interactive","dry-run","help","version"],g=class{#e;constructor(t){this.#e=t}get git_args(){return this.#e.git_args}get interactive(){return!this.#e.no_interactive}get dry_run(){return this.#e.dry_run}get help(){return this.#e.help}get version(){return this.#e.version}get commit_state(){return this.#e.commit_state}},f=new g(V(process.argv.slice(2)));function V(o){let t=L(o,{alias:{h:"help",v:"version"},boolean:$,string:[...O,...D]}),r={};return O.forEach(i=>{let a=t[i];if(a){let p=i.replace("-","_");r[p]=a}}),{help:t.help===!0,version:t.version===!0,git_args:M(t["git-dir"],t["work-tree"]),no_interactive:t.interactive===!1,dry_run:t["dry-run"]===!0,commit_state:r}}function M(o,t){return`${o?`--git-dir=${o}`:""} ${t?`--work-tree=${t}`:""}`.trim()}var x=`{
|
|
2
2
|
// Run interactive \`git status\` before composing a commit
|
|
3
3
|
"check_status": true,
|
|
4
4
|
|
|
@@ -239,7 +239,7 @@ import*as e from"valibot";import*as l from"valibot";var s="custom",b=["closes","
|
|
|
239
239
|
"shell": "/bin/sh"
|
|
240
240
|
}
|
|
241
241
|
}
|
|
242
|
-
`;import*as n from"@clack/prompts";import{execSync as B}from"child_process";import c from"fs";import{homedir as S}from"os";import{parse as H}from"jsonc-parser";import
|
|
243
|
-
`+r),process.exit(0)}return G(t)}function G(o){try{return T(_,o)}catch(t){if(t instanceof U){let i=(t.issues[0].path??[]).map(a=>a.key).filter(a=>typeof a=="string"||typeof a=="number").join(".");n.log.error(`Invalid Configuration: ${
|
|
244
|
-
`+t.message)}process.exit(0)}}function q(o=f.git_args){let t=".";try{t=B(`git ${o} rev-parse --show-toplevel`).toString().trim()}catch{n.log.warn("Could not find git root. If in a --bare repository, ignore this warning.")}return t}function W(){return j(S())??S()+"/"+E}function Y(o){return j(o)}function j(o){for(let t of A){let r=`${o}/${t}`;if(c.existsSync(r))return r}return null}function
|
|
245
|
-
`}function de(o){let t=o.trim();return t.endsWith(".")?t.substring(0,t.length-1).trim():o.trim()}function
|
|
242
|
+
`;import*as n from"@clack/prompts";import{execSync as B}from"child_process";import c from"fs";import{homedir as S}from"os";import{parse as H}from"jsonc-parser";import b from"picocolors";import{ValiError as U,parse as T}from"valibot";var A=[".better-commits.jsonc",".better-commits.json"],E=A[0],me=[{value:"closes",label:"closes <issue/ticket>",hint:"Attempts to infer ticket from branch"},{value:"trailer",label:"trailer",hint:"Appends trailer based on commit type"},{value:"breaking-change",label:"breaking change",hint:"Add breaking change"},{value:"deprecated",label:"deprecated",hint:"Add deprecated change"},{value:"custom",label:"custom",hint:"Add a custom footer"}],_e=[{value:"branch",label:"Branch"},{value:"worktree",label:"Worktree"}],ge={get:()=>"",set:(o,t)=>{},clear:()=>{}};function fe(o=" better-commits ",t=f.git_args){console.clear(),n.intro(`${b.bgCyan(b.black(o))}`);let r=null,i=W();c.existsSync(i)&&(r=I(i));let a=q(t),p=Y(a);if(p){n.log.step("Reading from Repository Config");let v=I(p);return{config:r?{...v,overrides:r.overrides.shell?r.overrides:v.overrides,confirm_with_editor:r.confirm_with_editor,cache_last_value:r.cache_last_value}:v,config_source:"repository"}}if(r)return n.log.step("Reading from Global Config"),{config:r,config_source:"global"};let w=T(_,{});return n.log.step(`Config not found. Generating default ${E} at $HOME`),c.writeFileSync(i,x),{config:w,config_source:"none"}}function I(o){let t=null;try{t=H(c.readFileSync(o,"utf8"))}catch(r){n.log.error(`Invalid JSON/JSONC config file at ${o}. Exiting.
|
|
243
|
+
`+r),process.exit(0)}return G(t)}function G(o){try{return T(_,o)}catch(t){if(t instanceof U){let i=(t.issues[0].path??[]).map(a=>a.key).filter(a=>typeof a=="string"||typeof a=="number").join(".");n.log.error(`Invalid Configuration: ${b.red(i)}
|
|
244
|
+
`+t.message)}process.exit(0)}}function q(o=f.git_args){let t=".";try{t=B(`git ${o} rev-parse --show-toplevel`).toString().trim()}catch{n.log.warn("Could not find git root. If in a --bare repository, ignore this warning.")}return t}function W(){return j(S())??S()+"/"+E}function Y(o){return j(o)}function j(o){for(let t of A){let r=`${o}/${t}`;if(c.existsSync(r))return r}return null}function be(){try{return JSON.parse(c.readFileSync(new URL("../package.json",import.meta.url),"utf8")).version??"unknown"}catch{return"unknown"}}function he(o,t){return t===o.length-1?"":`
|
|
245
|
+
`}function de(o){let t=o.trim();return t.endsWith(".")?t.substring(0,t.length-1).trim():o.trim()}function Ce(o,t){try{return o.get(t)??""}catch{n.log.warn(`Could not access ${t} from cache. Check that "~/.config" exists. Set "cache_last_value" to false to disable.`)}return""}function ye(o,t,r){try{o.set(t,r)}catch{n.log.warn(`Could not access ${t} from cache. Check that "~/.config" exists. Set "cache_last_value" to false to disable.`)}}export{s as a,P as b,Q as c,F as d,X as e,f,x as g,E as h,me as i,_e as j,ge as k,fe as l,q as m,Y as n,be as o,he as p,de as q,Ce as r,ye as s};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{b as m,d as u,f as p}from"./chunk-
|
|
1
|
+
import{b as m,d as u,f as p}from"./chunk-2JVEMMKH.js";import*as s from"valibot";function _(t,n){let i=t.scope?t.scope.length+2:0,e=t.type?.length??0,r=n.include_ticket?t.ticket?.length??0:0,c=t.title?.length??0;return i+e+r+c}function a(t){return t.map(i=>i===""?'"" (none)':`"${i}"`).join(", ")}function R(t){let n=t.commit_type.options.map(e=>e.value),i=t.commit_scope.options.map(e=>e.value);return s.pipe(s.object(m),s.rawCheck(({dataset:e,addIssue:r})=>{if(!e.typed)return;let c=e.value.type?`"${e.value.type}"`:"(empty)";e.value.type&&!n.includes(e.value.type)&&r({message:`Invalid --type ${c}. Valid types: ${a(n)}.`})}),s.rawCheck(({dataset:e,addIssue:r})=>{if(!e.typed)return;let c=e.value.scope?`"${e.value.scope}"`:"(empty)";e.value.scope&&!t.commit_scope.custom_scope&&!i.includes(e.value.scope)&&r({message:`Invalid --scope ${c}. Valid scopes: ${a(i)}.`})}),s.rawCheck(({dataset:e,addIssue:r})=>{!e.typed||e.value.title.trim()||r({message:"Missing --title. Provide a non-empty commit title."})}),s.rawCheck(({dataset:e,addIssue:r})=>{if(!e.typed)return;let c=_(e.value,{include_ticket:t.check_ticket.add_to_title});c>t.commit_title.max_size&&r({message:`Title exceeds max width. Current size is ${c}, max is ${t.commit_title.max_size} (includes type, scope, and ticket when enabled).`})}),s.rawCheck(({dataset:e,addIssue:r})=>{e.typed&&t.commit_body.required&&!e.value.body.trim()&&r({message:"Missing --body. commit_body.required is enabled in config."})}),s.rawCheck(({dataset:e,addIssue:r})=>{e.typed&&e.value.closes&&!e.value.ticket&&r({message:'Invalid footer values: --closes requires --ticket (for example: --ticket "ABC-123").'})}),s.rawCheck(({dataset:e,addIssue:r})=>{e.typed&&e.value.breaking_body&&!e.value.breaking_title&&r({message:"Invalid breaking change values: --breaking-body requires --breaking-title."})}),s.rawCheck(({dataset:e,addIssue:r})=>{e.typed&&e.value.deprecates_body&&!e.value.deprecates_title&&r({message:"Invalid deprecation values: --deprecates-body requires --deprecates-title."})}))}function q(t){let n=t.commit_type.options.map(i=>i.value);return s.pipe(s.object(u),s.rawCheck(({dataset:i,addIssue:e})=>{if(!i.typed)return;let r=i.value.type?`"${i.value.type}"`:"(empty)";i.value.type&&!n.includes(i.value.type)&&e({message:`Invalid --type ${r}. Valid types: ${a(n)}.`})}),s.rawCheck(({dataset:i,addIssue:e})=>{!i.typed||i.value.description.trim()||e({message:"Missing --description. Provide a non-empty branch description."})}),s.rawCheck(({dataset:i,addIssue:e})=>{if(!i.typed)return;let r=i.value.description.trim();r.length>t.branch_description.max_length&&e({message:`Description exceeds max length. Current length is ${r.length}, max is ${t.branch_description.max_length}.`})}),s.rawCheck(({dataset:i,addIssue:e})=>{i.typed&&t.branch_user.required&&!i.value.user.trim()&&e({message:"Missing --user. branch_user.required is enabled in config."})}),s.rawCheck(({dataset:i,addIssue:e})=>{i.typed&&t.branch_ticket.required&&!i.value.ticket.trim()&&e({message:"Missing --ticket. branch_ticket.required is enabled in config."})}),s.rawCheck(({dataset:i,addIssue:e})=>{i.typed&&t.branch_version.required&&!i.value.version.trim()&&e({message:"Missing --branch-version. branch_version.required is enabled in config."})}))}import{execSync as h}from"child_process";var f=/\/(\w+-\d+)/,v=/^(\w+-\d+)/,y=/^([A-Z]+-[\[a-zA-Z\]\d]+)_/,k=/\/([A-Z]+-[\[a-zA-Z\]\d]+)_/,b=/\/(\d+)/,$=/^(\d+)/;function H(t){if(p.interactive)return;let n={ticket:"",type:""};if(t.check_ticket.infer_ticket){let e=w({append_hashtag:t.check_ticket.append_hashtag,prepend_hashtag:t.check_ticket.prepend_hashtag},p.git_args);n.ticket=e}let i=C(t.commit_type.options,p.git_args);return n.type=i,n}function C(t,n){let i=l(n);return i?E(i,t.map(e=>e.value)):""}function w(t,n){let i=l(n);return i?x(i,t):""}function x(t,n){let i=[t.match(y),t.match(k),t.match(f),t.match(b),t.match(v),t.match($)].filter(e=>e!=null).map(e=>e&&e.length>=2?e[1]:"");return!i.length||!i[0]?"":n.append_hashtag||n.prepend_hashtag==="Always"?`#${i[0]}`:i[0]}function E(t,n){return n.find(e=>{let r=new RegExp(`^${e}-`),c=new RegExp(`-${e}-`),g=new RegExp(`${e}/`);return[t.match(r),t.match(c),t.match(g)].filter(d=>d!=null).length>0})??""}function l(t){try{return h(`git ${t} branch --show-current`,{stdio:"pipe"}).toString().trim()}catch{return""}}import o from"picocolors";function X(t){return`${t} ${o.dim("\xB7 restored from cache")}`}function U(t){return`${t} ${o.dim("\xB7 inferred from branch")}`}function Z(t){return`${t} ${o.dim("\xB7 optional")}`}function j(t){return`${t} ${o.dim("\xB7 <space> to select")}`}function D(t){return`${t} ${o.dim("\xB7 dry run - changes will not be committed")}`}export{_ as a,R as b,q as c,H as d,C as e,w as f,X as g,U as h,Z as i,j,D as k};
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#! /usr/bin/env node
|
|
2
|
-
import{a as nt,b as at,d as ct,e as F,f as P,g as f,h as A,i as y,j as $,k as Y}from"./chunk-
|
|
2
|
+
import{a as nt,b as at,d as ct,e as F,f as P,g as f,h as A,i as y,j as $,k as Y}from"./chunk-EANV5ZZP.js";import{a as Z,c as z,f as s,i as tt,k as et,l as it,m as ot,o as I,p as rt,q as st,r as g,s as u}from"./chunk-2JVEMMKH.js";import{chdir as kt}from"process";import*as H from"@clack/prompts";import{ValiError as vt,parse as ut}from"valibot";import Ct from"configstore";import*as T from"@clack/prompts";var m=class{constructor(t,e,o){this.config=t;this.commit_state=e;this.prompt_cache=o}};var R=class extends m{async run(){if(this.#o){let{initial_value:t,message:e}=this.#e,o=await T.select({message:e,initialValue:t,maxItems:this.#r,options:this.#t});T.isCancel(o)&&process.exit(0),this.#s(o)}}get#o(){return this.config.commit_type.enable}get#e(){let t=g(this.prompt_cache,"commit_type");if(t)return{initial_value:t,message:f("Commit type")};if(this.config.commit_type.infer_type_from_branch){let e=F(this.#t,s.git_args);if(e)return{message:A("Commit type"),initial_value:e}}return{initial_value:this.config.commit_type.initial_value,message:"Select a commit type"}}get#t(){return this.config.commit_type.options}get#i(){return this.#t.reduce((t,e)=>({...t,[e.value]:{emoji:e.emoji??"",trailer:e.trailer??""}}),{})}get#r(){return this.config.commit_type.max_items}#s(t){u(this.prompt_cache,"commit_type",t);let e=this.#i;this.commit_state.trailer=e[t].trailer,this.commit_state.type=this.config.commit_type.append_emoji_to_commit&&this.config.commit_type.emoji_commit_position==="Start"?`${e[t].emoji} ${t}`.trim():t}};import*as k from"@clack/prompts";var j=class extends m{async run(){if(!this.#o)return;let{initial_value:t,message:e}=this.#e(),o=await k.select({message:e,initialValue:t,maxItems:this.#t,options:this.#i});k.isCancel(o)&&process.exit(0),await this.#s(o)}get#o(){return this.config.commit_scope.enable}#e(){let t=g(this.prompt_cache,"commit_scope");return t?{initial_value:t,message:f("Commit scope")}:{initial_value:this.config.commit_scope.initial_value,message:"Select a commit scope"}}get#t(){return this.config.commit_scope.max_items}get#i(){return this.config.commit_scope.options}get#r(){return this.config.commit_scope.custom_scope}async#s(t){u(this.prompt_cache,"commit_scope",t);let e=t;if(e===Z&&this.#r){let o=await k.text({message:"Write a custom scope",placeholder:""});k.isCancel(o)&&process.exit(0),e=o??""}this.commit_state.scope=e}};import*as N from"@clack/prompts";var E=class extends m{async run(){let{initial_value:t,message:e}=this.#i();if(this.commit_state.ticket=t,this.#e){let o=await N.text({message:e,placeholder:"",initialValue:t});N.isCancel(o)&&process.exit(0),u(this.prompt_cache,"commit_ticket",o),this.commit_state.ticket=o??""}this.#t&&this.commit_state.ticket&&!this.commit_state.ticket.startsWith("#")&&(this.commit_state.ticket="#"+this.commit_state.ticket)}get#o(){return this.config.check_ticket.infer_ticket}get#e(){return this.config.check_ticket.confirm_ticket}get#t(){return this.config.check_ticket.prepend_hashtag==="Always"}#i(){let t=g(this.prompt_cache,"commit_ticket");if(t)return{initial_value:t,message:f("Ticket / issue")};if(this.#o){let e=P({append_hashtag:this.config.check_ticket.append_hashtag,prepend_hashtag:this.config.check_ticket.prepend_hashtag},s.git_args);if(e)return{initial_value:e,message:A("Ticket / issue")}}return{initial_value:this.commit_state.ticket,message:y("Add ticket / issue")}}};import*as G from"@clack/prompts";var D=class extends m{async run(){let{initial_value:t,message:e}=this.#o(),o=await G.text({message:e,initialValue:t,placeholder:"",validate:a=>this.#e(a)});G.isCancel(o)&&process.exit(0),this.#n(o??"")}#o(){let t=g(this.prompt_cache,"commit_title");return t?{initial_value:t,message:f("Commit title")}:{initial_value:this.commit_state.title,message:"Write a brief title describing the commit"}}#e(t){if(!t)return"Please enter a title";if(this.#i(t)>this.#t)return`Exceeded max length. Title max [${this.#t}]`}get#t(){return this.config.commit_title.max_size}#i(t){return nt({type:this.commit_state.type,scope:this.commit_state.scope,ticket:this.commit_state.ticket,title:t},{include_ticket:this.config.check_ticket.add_to_title})}get#r(){return this.config.commit_type.options.reduce((t,e)=>({...t,[e.value]:{emoji:e.emoji??""}}),{})}#s(t){return this.config.commit_type.append_emoji_to_commit&&this.config.commit_type.emoji_commit_position==="After-Colon"?`${this.#r[this.commit_state.type]?.emoji??""} ${t}`.trim():t}#n(t){u(this.prompt_cache,"commit_title",t),this.commit_state.title=st(this.#s(t))}};import*as L from"@clack/prompts";var M=class extends m{async run(){if(!this.#o)return;let{initial_value:t,message:e}=this.#e(),o=await L.text({message:e,initialValue:t,placeholder:"",validate:a=>this.#t(a)});L.isCancel(o)&&process.exit(0),this.#r(o??"")}get#o(){return this.config.commit_body.enable}#e(){let t=g(this.prompt_cache,"commit_body");return t?{initial_value:t,message:f("Commit body")}:{initial_value:"",message:y("Write a detailed description of the changes")}}#t(t){if(this.config.commit_body.required&&!t)return"Please enter a description"}#i(t){return this.config.commit_body.split_by_period?t.split(/\.\s+/).map(o=>o.trim()).join(`.
|
|
3
3
|
`):t}#r(t){u(this.prompt_cache,"commit_body",t),this.commit_state.body=this.#i(t)}};import*as h from"@clack/prompts";var V=class extends m{async run(){if(!this.#o)return;let{initial_values:t,message:e}=this.#i(),o=await h.multiselect({message:e,initialValues:t,options:this.#e,required:!1});h.isCancel(o)&&process.exit(0);let a=this.#s(o),r=await this.#n(a);this.#m(o,a,r)}get#o(){return this.config.commit_footer.enable}get#e(){let t=new Set(this.config.commit_footer.options);return tt.filter(e=>t.has(e.value))}get#t(){return this.#e.map(t=>t.value)}#i(){let t=g(this.prompt_cache,"commit_footer");return t?{initial_values:this.#r(t),message:$(f("Commit footers"))}:{initial_values:this.config.commit_footer.initial_value.filter(o=>this.#t.includes(o)),message:$(y("Select optional footers"))}}#r(t){return t.split(",").map(e=>e.trim()).filter(e=>this.#t.includes(e))}#s(t){return{includes_breaking_change:t.includes("breaking-change"),includes_deprecated:t.includes("deprecated"),includes_closes:t.includes("closes"),includes_custom:t.includes("custom"),includes_trailer:t.includes("trailer")}}async#n(t){let e={breaking_title:"",breaking_body:"",deprecated_title:"",deprecated_body:"",custom_footer:""};return t.includes_breaking_change&&(e.breaking_title=await this.#c("Breaking changes: Write a short title / summary"),e.breaking_body=await this.#a(y("Breaking Changes: Write a description & migration instructions"))),t.includes_deprecated&&(e.deprecated_title=await this.#c("Deprecated: Write a short title / summary"),e.deprecated_body=await this.#a(y("Deprecated: Write a description"))),t.includes_custom&&(e.custom_footer=await this.#a("Write a custom footer")),e}async#c(t){let e=await h.text({message:t,placeholder:"",validate:o=>{if(!o)return"Please enter a title / summary"}});return h.isCancel(e)&&process.exit(0),e??""}async#a(t){let e=await h.text({message:t,placeholder:""});return h.isCancel(e)&&process.exit(0),e??""}#m(t,e,o){u(this.prompt_cache,"commit_footer",t.join(",")),this.commit_state.breaking_title=o.breaking_title,this.commit_state.breaking_body=o.breaking_body,this.commit_state.deprecates_title=o.deprecated_title,this.commit_state.deprecates_body=o.deprecated_body,this.commit_state.custom_footer=o.custom_footer,this.commit_state.closes=e.includes_closes?"Closes:":"",e.includes_trailer||(this.commit_state.trailer="")}};import*as d from"@clack/prompts";import{execSync as mt}from"child_process";import p from"picocolors";function J({commit_state:i,config:t,colorize:e=!1,escape_quotes:o=!1,include_trailer:a=!1}){let r="";if(i.type&&(r+=e?p.blue(i.type):i.type),i.scope){let c=e?p.cyan(i.scope):i.scope;r+=`(${c})`}let n=i.ticket,l=t.check_ticket.surround;if(i.ticket&&l){let c=l.charAt(0),C=l.charAt(1);n=`${c}${i.ticket}${C}`}let v=t.check_ticket.title_position==="beginning";n&&t.check_ticket.add_to_title&&v&&(r=`${e?p.magenta(n):n} ${r}`);let w=t.check_ticket.title_position==="before-colon";if(n&&t.check_ticket.add_to_title&&w){let c=i.scope||i.type&&!t.check_ticket.surround?" ":"";r+=e?p.magenta(c+n):c+n}i.breaking_title&&t.breaking_change.add_exclamation_to_title&&(r+=e?p.red("!"):"!"),(i.scope||i.type||n&&w)&&(r+=": ");let U=t.check_ticket.title_position==="start",K=t.check_ticket.title_position==="end";if(n&&t.check_ticket.add_to_title&&U&&(r+=e?p.magenta(n)+" ":n+" "),i.title&&(r+=e?p.reset(i.title):i.title),n&&t.check_ticket.add_to_title&&K&&(r+=" "+(e?p.magenta(n):n)),i.body){let C=i.body.split("\\n").map(x=>e?p.reset(x.trim()):x.trim()).join(`
|
|
4
4
|
`);r+=`
|
|
5
5
|
|
package/dist/init.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#! /usr/bin/env node
|
|
2
|
-
import{g as c,h as e,m as a,n as p}from"./chunk-
|
|
2
|
+
import{g as c,h as e,m as a,n as p}from"./chunk-2JVEMMKH.js";import*as t from"@clack/prompts";import l from"fs";import o from"picocolors";await m();async function m(){console.clear(),t.intro(`${o.bgCyan(o.black(" better-commits-init "))}`);let r=a(),i=p(r),s=`${r}/${e}`;if(i){let n=await t.confirm({message:`${i.split("/").pop()} already exists. Replace with default ${e}?`});if(t.isCancel(n)||!n){t.outro("Cancelled");return}}try{l.writeFileSync(s,c)}catch{t.log.error(`${o.red("Could not determine git root folder. better-commits-init must be used in a git repository")}`)}t.log.success(`${o.green(`Successfully created ${s.split("/").pop()}`)}`),t.outro(`Run ${o.bgBlack(o.white("better-commits"))} to start the CLI`)}export{m as create_init_config};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "better-commits",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.21.0",
|
|
5
5
|
"description": "A CLI for creating better commits following the conventional commits specification",
|
|
6
6
|
"author": "Erik Verduin (https://github.com/everduin94)",
|
|
7
7
|
"type": "module",
|
|
@@ -20,11 +20,6 @@
|
|
|
20
20
|
"bcommits": "./dist/index.js",
|
|
21
21
|
"git-bc": "./dist/index.js"
|
|
22
22
|
},
|
|
23
|
-
"files": [
|
|
24
|
-
"dist",
|
|
25
|
-
"LICENSE",
|
|
26
|
-
"readme.md"
|
|
27
|
-
],
|
|
28
23
|
"license": "MIT",
|
|
29
24
|
"repository": {
|
|
30
25
|
"type": "git",
|
package/readme.md
CHANGED
|
@@ -442,7 +442,7 @@ better-branch --no-interactive --type feat --ticket TAC-123 --description "add p
|
|
|
442
442
|
|
|
443
443
|
#### Multi-line
|
|
444
444
|
|
|
445
|
-
If
|
|
445
|
+
If you are having issues with multilines for commits on windows, you can override the shell via your `.better-commits.jsonc` config.
|
|
446
446
|
|
|
447
447
|
Example
|
|
448
448
|
|
package/src/args.test.ts
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { parse_runtime_flags } from "./args";
|
|
3
|
+
|
|
4
|
+
describe("parse_runtime_flags", () => {
|
|
5
|
+
it("uses interactive mode by default", () => {
|
|
6
|
+
const parsed = parse_runtime_flags([]);
|
|
7
|
+
|
|
8
|
+
expect(parsed.no_interactive).toBe(false);
|
|
9
|
+
expect(parsed.dry_run).toBe(false);
|
|
10
|
+
expect(parsed.git_args).toBe("");
|
|
11
|
+
expect(parsed.commit_state).toEqual({});
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("parses --no-interactive and --dry-run", () => {
|
|
15
|
+
const parsed = parse_runtime_flags(["--no-interactive", "--dry-run"]);
|
|
16
|
+
|
|
17
|
+
expect(parsed.no_interactive).toBe(true);
|
|
18
|
+
expect(parsed.dry_run).toBe(true);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("parses --version and -v", () => {
|
|
22
|
+
const long_flag = parse_runtime_flags(["--version"]);
|
|
23
|
+
const short_flag = parse_runtime_flags(["-v"]);
|
|
24
|
+
|
|
25
|
+
expect(long_flag.version).toBe(true);
|
|
26
|
+
expect(short_flag.version).toBe(true);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("maps commit flags into commit_state keys", () => {
|
|
30
|
+
const parsed = parse_runtime_flags([
|
|
31
|
+
"--type",
|
|
32
|
+
"feat",
|
|
33
|
+
"--title",
|
|
34
|
+
"ship feature",
|
|
35
|
+
"--breaking-title",
|
|
36
|
+
"api changed",
|
|
37
|
+
"--custom-footer",
|
|
38
|
+
"Reviewed-by: Jane",
|
|
39
|
+
]);
|
|
40
|
+
|
|
41
|
+
expect(parsed.commit_state).toEqual({
|
|
42
|
+
type: "feat",
|
|
43
|
+
title: "ship feature",
|
|
44
|
+
breaking_title: "api changed",
|
|
45
|
+
custom_footer: "Reviewed-by: Jane",
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("builds git args from --git-dir and --work-tree", () => {
|
|
50
|
+
const parsed = parse_runtime_flags([
|
|
51
|
+
"--git-dir",
|
|
52
|
+
"/tmp/repo/.git",
|
|
53
|
+
"--work-tree",
|
|
54
|
+
"/tmp/repo",
|
|
55
|
+
]);
|
|
56
|
+
|
|
57
|
+
expect(parsed.git_args).toBe(
|
|
58
|
+
"--git-dir=/tmp/repo/.git --work-tree=/tmp/repo",
|
|
59
|
+
);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("builds git args when only one git location flag is provided", () => {
|
|
63
|
+
const with_git_dir = parse_runtime_flags(["--git-dir", "/tmp/repo/.git"]);
|
|
64
|
+
const with_work_tree = parse_runtime_flags(["--work-tree", "/tmp/repo"]);
|
|
65
|
+
|
|
66
|
+
expect(with_git_dir.git_args).toBe("--git-dir=/tmp/repo/.git");
|
|
67
|
+
expect(with_work_tree.git_args).toBe("--work-tree=/tmp/repo");
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("maps dashed commit flags to snake_case commit_state keys", () => {
|
|
71
|
+
const parsed = parse_runtime_flags([
|
|
72
|
+
"--breaking-body",
|
|
73
|
+
"major impact",
|
|
74
|
+
"--deprecates-title",
|
|
75
|
+
"legacy endpoint",
|
|
76
|
+
"--deprecates-body",
|
|
77
|
+
"use v2 endpoint",
|
|
78
|
+
"--custom-footer",
|
|
79
|
+
"Reviewed-by: Alex",
|
|
80
|
+
"--breaking-title",
|
|
81
|
+
"v1 removed",
|
|
82
|
+
]);
|
|
83
|
+
|
|
84
|
+
expect(parsed.commit_state).toEqual({
|
|
85
|
+
breaking_body: "major impact",
|
|
86
|
+
deprecates_title: "legacy endpoint",
|
|
87
|
+
deprecates_body: "use v2 endpoint",
|
|
88
|
+
custom_footer: "Reviewed-by: Alex",
|
|
89
|
+
breaking_title: "v1 removed",
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("honors interactive flag semantics", () => {
|
|
94
|
+
const default_flags = parse_runtime_flags([]);
|
|
95
|
+
const explicit_interactive = parse_runtime_flags(["--interactive"]);
|
|
96
|
+
const no_interactive = parse_runtime_flags(["--no-interactive"]);
|
|
97
|
+
|
|
98
|
+
expect(default_flags.no_interactive).toBe(false);
|
|
99
|
+
expect(explicit_interactive.no_interactive).toBe(false);
|
|
100
|
+
expect(no_interactive.no_interactive).toBe(true);
|
|
101
|
+
});
|
|
102
|
+
});
|
package/src/args.ts
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { parse } from "@bomb.sh/args";
|
|
2
|
+
import { InferOutput } from "valibot";
|
|
3
|
+
import { CommitState } from "./valibot-state";
|
|
4
|
+
|
|
5
|
+
type CommitStateRuntime = InferOutput<typeof CommitState>;
|
|
6
|
+
|
|
7
|
+
type ParsedRuntimeFlags = {
|
|
8
|
+
help: boolean;
|
|
9
|
+
version: boolean;
|
|
10
|
+
git_args: string;
|
|
11
|
+
no_interactive: boolean;
|
|
12
|
+
dry_run: boolean;
|
|
13
|
+
commit_state: Partial<CommitStateRuntime>;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const COMMIT_OPTIONS = [
|
|
17
|
+
"type",
|
|
18
|
+
"scope",
|
|
19
|
+
"title",
|
|
20
|
+
"body",
|
|
21
|
+
"closes",
|
|
22
|
+
"ticket",
|
|
23
|
+
"trailer",
|
|
24
|
+
"deprecates",
|
|
25
|
+
"breaking-title",
|
|
26
|
+
"breaking-body",
|
|
27
|
+
"deprecates-title",
|
|
28
|
+
"deprecates-body",
|
|
29
|
+
"custom-footer",
|
|
30
|
+
] as const;
|
|
31
|
+
|
|
32
|
+
export const GIT_OPTIONS = ["git-dir", "work-tree"] as const;
|
|
33
|
+
|
|
34
|
+
export const BOOLEAN_FLAGS = [
|
|
35
|
+
"interactive",
|
|
36
|
+
"dry-run",
|
|
37
|
+
"help",
|
|
38
|
+
"version",
|
|
39
|
+
] as const;
|
|
40
|
+
|
|
41
|
+
class Flags {
|
|
42
|
+
#runtime: ParsedRuntimeFlags;
|
|
43
|
+
|
|
44
|
+
constructor(runtime: ParsedRuntimeFlags) {
|
|
45
|
+
this.#runtime = runtime;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
get git_args(): string {
|
|
49
|
+
return this.#runtime.git_args;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
get interactive(): boolean {
|
|
53
|
+
return !this.#runtime.no_interactive;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
get dry_run(): boolean {
|
|
57
|
+
return this.#runtime.dry_run;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
get help(): boolean {
|
|
61
|
+
return this.#runtime.help;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
get version(): boolean {
|
|
65
|
+
return this.#runtime.version;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
get commit_state(): Partial<CommitStateRuntime> {
|
|
69
|
+
return this.#runtime.commit_state;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export const flags = new Flags(parse_runtime_flags(process.argv.slice(2)));
|
|
74
|
+
|
|
75
|
+
export function parse_runtime_flags(argv: string[]): ParsedRuntimeFlags {
|
|
76
|
+
const parsed = parse(argv, {
|
|
77
|
+
alias: { h: "help", v: "version" },
|
|
78
|
+
boolean: BOOLEAN_FLAGS,
|
|
79
|
+
string: [...COMMIT_OPTIONS, ...GIT_OPTIONS],
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const commit_state: Partial<CommitStateRuntime> = {};
|
|
83
|
+
COMMIT_OPTIONS.forEach((value) => {
|
|
84
|
+
const cli_value = parsed[value];
|
|
85
|
+
if (cli_value) {
|
|
86
|
+
const str = value.replace("-", "_") as keyof CommitStateRuntime;
|
|
87
|
+
commit_state[str] = cli_value;
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
help: parsed["help"] === true,
|
|
93
|
+
version: parsed["version"] === true,
|
|
94
|
+
git_args: get_git_args(parsed["git-dir"], parsed["work-tree"]),
|
|
95
|
+
no_interactive: parsed.interactive === false,
|
|
96
|
+
dry_run: parsed["dry-run"] === true,
|
|
97
|
+
commit_state,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function get_git_args(
|
|
102
|
+
git_dir: string | undefined,
|
|
103
|
+
work_tree: string | undefined,
|
|
104
|
+
): string {
|
|
105
|
+
return `${git_dir ? `--git-dir=${git_dir}` : ""} ${work_tree ? `--work-tree=${work_tree}` : ""}`.trim();
|
|
106
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { parse_branch_runtime_flags } from "./branch-args";
|
|
3
|
+
|
|
4
|
+
describe("parse_branch_runtime_flags", () => {
|
|
5
|
+
it("maps branch flags into branch_state keys", () => {
|
|
6
|
+
const parsed = parse_branch_runtime_flags([
|
|
7
|
+
"--user",
|
|
8
|
+
"erik",
|
|
9
|
+
"--type",
|
|
10
|
+
"feat",
|
|
11
|
+
"--ticket",
|
|
12
|
+
"ABC-123",
|
|
13
|
+
"--description",
|
|
14
|
+
"add-parser",
|
|
15
|
+
"--branch-version",
|
|
16
|
+
"1.2.0",
|
|
17
|
+
]);
|
|
18
|
+
|
|
19
|
+
expect(parsed.branch_state).toEqual({
|
|
20
|
+
user: "erik",
|
|
21
|
+
type: "feat",
|
|
22
|
+
ticket: "ABC-123",
|
|
23
|
+
description: "add-parser",
|
|
24
|
+
version: "1.2.0",
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("maps --checkout into checkout", () => {
|
|
29
|
+
const parsed = parse_branch_runtime_flags(["--checkout", "worktree"]);
|
|
30
|
+
|
|
31
|
+
expect(parsed.branch_state).toEqual({
|
|
32
|
+
checkout: "worktree",
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("does not set checkout when --checkout is omitted", () => {
|
|
37
|
+
const parsed = parse_branch_runtime_flags([
|
|
38
|
+
"--type",
|
|
39
|
+
"feat",
|
|
40
|
+
"--description",
|
|
41
|
+
"add-parser",
|
|
42
|
+
]);
|
|
43
|
+
|
|
44
|
+
expect(parsed.branch_state).toEqual({
|
|
45
|
+
type: "feat",
|
|
46
|
+
description: "add-parser",
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("honors interactive flag semantics", () => {
|
|
51
|
+
const default_flags = parse_branch_runtime_flags([]);
|
|
52
|
+
const explicit_interactive = parse_branch_runtime_flags(["--interactive"]);
|
|
53
|
+
const no_interactive = parse_branch_runtime_flags(["--no-interactive"]);
|
|
54
|
+
|
|
55
|
+
expect(default_flags.no_interactive).toBe(false);
|
|
56
|
+
expect(explicit_interactive.no_interactive).toBe(false);
|
|
57
|
+
expect(no_interactive.no_interactive).toBe(true);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("parses git-dir and work-tree into git_args", () => {
|
|
61
|
+
const parsed = parse_branch_runtime_flags([
|
|
62
|
+
"--git-dir",
|
|
63
|
+
"/tmp/repo/.git",
|
|
64
|
+
"--work-tree",
|
|
65
|
+
"/tmp/repo",
|
|
66
|
+
]);
|
|
67
|
+
|
|
68
|
+
expect(parsed.git_args).toBe(
|
|
69
|
+
"--git-dir=/tmp/repo/.git --work-tree=/tmp/repo",
|
|
70
|
+
);
|
|
71
|
+
});
|
|
72
|
+
});
|