Skip to content

Commit 93eb75c

Browse files
authored
fix(main): node output & type prompt (#49)
Updated post/pre hook output to be streamed to terminal. Updated type prompt to notify user when a value was inferred.
1 parent 9e92a11 commit 93eb75c

File tree

4 files changed

+151
-132
lines changed

4 files changed

+151
-132
lines changed

.better-commits.json

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,38 +3,43 @@
33
"append_emoji_to_label": true,
44
"append_emoji_to_commit": false
55
},
6-
"commit_scope": {
7-
"enable": true,
8-
"initial_value": "main",
9-
"options": [
10-
{
11-
"value": "main",
12-
"label": "main"
13-
},
6+
"commit_scope": {
7+
"enable": true,
8+
"initial_value": "main",
9+
"options": [
1410
{
15-
"value": "branch",
16-
"label": "branch"
17-
},
18-
{
19-
"value": "init",
20-
"label": "init"
21-
},
11+
"value": "main",
12+
"label": "main"
13+
},
2214
{
23-
"value": "util",
24-
"label": "util"
25-
},
15+
"value": "branch",
16+
"label": "branch"
17+
},
2618
{
27-
"value": "build",
28-
"label": "build"
29-
},
30-
{
31-
"value": "",
32-
"label": "none"
33-
}
34-
]
35-
},
36-
"check_ticket": {
37-
"append_hashtag": true
38-
},
39-
"branch_pre_commands": ["git checkout main", "git pull -r origin main", "npm install"]
19+
"value": "init",
20+
"label": "init"
21+
},
22+
{
23+
"value": "util",
24+
"label": "util"
25+
},
26+
{
27+
"value": "build",
28+
"label": "build"
29+
},
30+
{
31+
"value": "",
32+
"label": "none"
33+
}
34+
]
35+
},
36+
"check_ticket": {
37+
"append_hashtag": true
38+
},
39+
"branch_pre_commands": [
40+
"git stash",
41+
"git checkout main",
42+
"git pull -r origin main",
43+
"npm install"
44+
]
4045
}

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/branch.ts

Lines changed: 107 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,131 +1,141 @@
11
#! /usr/bin/env node
22

33
import { CommitState, Config } from "./zod-state";
4-
import { CACHE_PROMPT, get_git_root, load_setup, OPTIONAL_PROMPT } from "./utils";
4+
import {
5+
CACHE_PROMPT,
6+
get_git_root,
7+
load_setup,
8+
OPTIONAL_PROMPT,
9+
} from "./utils";
510
import simpleGit from "simple-git";
611
import { BranchState } from "./zod-state";
7-
import * as p from '@clack/prompts';
8-
import Configstore from 'configstore';
12+
import * as p from "@clack/prompts";
13+
import Configstore from "configstore";
914
import { z } from "zod";
1015
import { execSync } from "child_process";
1116

12-
main(load_setup(' better-branch '))
17+
main(load_setup(" better-branch "));
1318

1419
async function main(config: z.infer<typeof Config>) {
15-
const branch_state = BranchState.parse({});
16-
17-
if (config.branch_user.enable) {
18-
const cache_user_name = get_user_from_cache()
19-
const user_name_required = config.branch_user.required
20-
const user_name = await p.text({
21-
message: `Type your git username ${user_name_required ? '' : OPTIONAL_PROMPT} ${CACHE_PROMPT}`.trim(),
22-
placeholder: '',
23-
initialValue: cache_user_name,
24-
validate: (val) => {
25-
if (user_name_required && !val) return 'Please enter a username'
26-
}
27-
})
28-
if (p.isCancel(user_name)) process.exit(0)
29-
branch_state.user = user_name?.replace(/\s+/g, '-')?.toLowerCase() ?? '';
30-
set_user_cache(branch_state.user)
31-
}
32-
33-
if (config.branch_type.enable) {
34-
let initial_value = config.commit_type.initial_value
35-
const commit_type = await p.select(
36-
{
37-
message: `Select a branch type`,
38-
initialValue: initial_value,
39-
options: config.commit_type.options,
40-
}
41-
)
42-
if (p.isCancel(commit_type)) process.exit(0)
43-
branch_state.type = commit_type;
44-
}
20+
const branch_state = BranchState.parse({});
21+
22+
if (config.branch_user.enable) {
23+
const cache_user_name = get_user_from_cache();
24+
const user_name_required = config.branch_user.required;
25+
const user_name = await p.text({
26+
message: `Type your git username ${
27+
user_name_required ? "" : OPTIONAL_PROMPT
28+
} ${CACHE_PROMPT}`.trim(),
29+
placeholder: "",
30+
initialValue: cache_user_name,
31+
validate: (val) => {
32+
if (user_name_required && !val) return "Please enter a username";
33+
},
34+
});
35+
if (p.isCancel(user_name)) process.exit(0);
36+
branch_state.user = user_name?.replace(/\s+/g, "-")?.toLowerCase() ?? "";
37+
set_user_cache(branch_state.user);
38+
}
39+
40+
if (config.branch_type.enable) {
41+
let initial_value = config.commit_type.initial_value;
42+
const commit_type = await p.select({
43+
message: `Select a branch type`,
44+
initialValue: initial_value,
45+
options: config.commit_type.options,
46+
});
47+
if (p.isCancel(commit_type)) process.exit(0);
48+
branch_state.type = commit_type;
49+
}
4550

46-
if (config.branch_ticket.enable) {
47-
const ticked_required = config.branch_ticket.required
48-
const ticket = await p.text({
49-
message: `Type ticket / issue number ${ticked_required ? '' : OPTIONAL_PROMPT}`.trim(),
50-
placeholder: '',
51-
validate: (val) => {
52-
if (ticked_required && !val) return 'Please enter a ticket / issue'
53-
}
54-
})
55-
if (p.isCancel(ticket)) process.exit(0)
56-
branch_state.ticket = ticket;
51+
if (config.branch_ticket.enable) {
52+
const ticked_required = config.branch_ticket.required;
53+
const ticket = await p.text({
54+
message: `Type ticket / issue number ${
55+
ticked_required ? "" : OPTIONAL_PROMPT
56+
}`.trim(),
57+
placeholder: "",
58+
validate: (val) => {
59+
if (ticked_required && !val) return "Please enter a ticket / issue";
60+
},
61+
});
62+
if (p.isCancel(ticket)) process.exit(0);
63+
branch_state.ticket = ticket;
64+
}
65+
66+
const description_max_length = config.branch_description.max_length;
67+
const description = await p.text({
68+
message: "Type a short description",
69+
placeholder: "",
70+
validate: (value) => {
71+
if (!value) return "Please enter a description";
72+
if (value.length > description_max_length)
73+
return `Exceeded max length. Description max [${description_max_length}]`;
74+
},
75+
});
76+
if (p.isCancel(description)) process.exit(0);
77+
branch_state.description =
78+
description?.replace(/\s+/g, "-")?.toLowerCase() ?? "";
79+
80+
config.branch_pre_commands.forEach((command) => {
81+
try {
82+
execSync(command, { stdio: "inherit" });
83+
} catch (err) {
84+
p.log.error("Something went wrong when executing pre-commands: " + err);
85+
process.exit(0);
5786
}
58-
59-
60-
const description_max_length = config.branch_description.max_length
61-
const description = await p.text({
62-
message: 'Type a short description',
63-
placeholder: '',
64-
validate: (value) => {
65-
if (!value) return 'Please enter a description'
66-
if (value.length > description_max_length) return `Exceeded max length. Description max [${description_max_length}]`
67-
}
68-
})
69-
if (p.isCancel(description)) process.exit(0)
70-
branch_state.description = description?.replace(/\s+/g, '-')?.toLowerCase() ?? '';
71-
72-
config.branch_pre_commands.forEach(command => {
73-
try {
74-
const output = execSync(command).toString().trim();
75-
p.log.info(output)
76-
} catch (err) {
77-
p.log.error('Something went wrong when executing pre-commands: ' + err);
78-
process.exit(0)
79-
}
80-
})
81-
82-
const branch_name = build_branch(branch_state, config)
83-
const simple_git = simpleGit({ baseDir: get_git_root() })
84-
await simple_git.checkoutLocalBranch(branch_name)
85-
86-
p.log.info(`Switched to a new branch '${branch_name}'`)
87-
88-
config.branch_post_commands.forEach(command => {
89-
try {
90-
const output = execSync(command).toString().trim();
91-
p.log.info(output)
92-
} catch (err) {
93-
p.log.error('Something went wrong when executing post-commands: ' + err);
94-
process.exit(0)
95-
}
96-
})
87+
});
88+
89+
const branch_name = build_branch(branch_state, config);
90+
const simple_git = simpleGit({ baseDir: get_git_root() });
91+
await simple_git.checkoutLocalBranch(branch_name);
9792

93+
p.log.info(`Switched to a new branch '${branch_name}'`);
94+
95+
config.branch_post_commands.forEach((command) => {
96+
try {
97+
execSync(command, { stdio: "inherit" });
98+
} catch (err) {
99+
p.log.error("Something went wrong when executing post-commands: " + err);
100+
process.exit(0);
101+
}
102+
});
98103
}
99104

100-
function build_branch(branch: z.infer<typeof BranchState>, config: z.infer<typeof Config>) {
101-
let res = ''
102-
if (branch.user) res += branch.user + config.branch_user.separator
103-
if (branch.type) res += branch.type + config.branch_type.separator
104-
if (branch.ticket) res += branch.ticket + config.branch_ticket.separator
105-
if (branch.description) res+= branch.description
105+
function build_branch(
106+
branch: z.infer<typeof BranchState>,
107+
config: z.infer<typeof Config>
108+
) {
109+
let res = "";
110+
if (branch.user) res += branch.user + config.branch_user.separator;
111+
if (branch.type) res += branch.type + config.branch_type.separator;
112+
if (branch.ticket) res += branch.ticket + config.branch_ticket.separator;
113+
if (branch.description) res += branch.description;
106114
return res;
107115
}
108116

109117
function get_user_from_cache(): string {
110118
try {
111-
const config_store = new Configstore('better-commits');
112-
return config_store.get('username') ?? ''
119+
const config_store = new Configstore("better-commits");
120+
return config_store.get("username") ?? "";
113121
} catch (err) {
114-
p.log.warn('There was an issue accessing username from cache. Check that the folder "~/.config" exists')
122+
p.log.warn(
123+
'There was an issue accessing username from cache. Check that the folder "~/.config" exists'
124+
);
115125
}
116126

117-
return ''
127+
return "";
118128
}
119129

120130
function set_user_cache(val: string): void {
121131
try {
122-
const config_store = new Configstore('better-commits');
123-
config_store.set('username', val)
132+
const config_store = new Configstore("better-commits");
133+
config_store.set("username", val);
124134
} catch (err) {
125135
// fail silently, user has likely already seen guidance via get exceptions at this point
126136
}
127137
}
128138

129139
// TODO: No idea what's happening here
130140
// If you don't use CommitState, (even in unreachable code), parse fails on Config
131-
CommitState
141+
CommitState;

src/index.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,18 +43,22 @@ export async function main(config: z.infer<typeof Config>) {
4343
}
4444

4545
if (config.commit_type.enable) {
46+
let message = 'Select a commit type';
4647
let initial_value = config.commit_type.initial_value
4748
if (config.commit_type.infer_type_from_branch) {
4849
const options = config.commit_type.options.map(o => o.value)
4950
const type_from_branch = infer_type_from_branch(options)
50-
if (type_from_branch) initial_value = type_from_branch
51+
if (type_from_branch) {
52+
message = `Commit type inferred from branch ${color.dim('(confirm / edit)')}`
53+
initial_value = type_from_branch
54+
}
5155
}
5256
const value_to_emoji: Record<string,string> = config.commit_type.options.reduce(
5357
(acc, curr) => ({ ...acc, [curr.value]: curr.emoji ?? '' }), {}
5458
)
5559
const commit_type = await p.select(
5660
{
57-
message: `Select a commit type`,
61+
message,
5862
initialValue: initial_value,
5963
options: config.commit_type.options,
6064
}

0 commit comments

Comments
 (0)