better-commits 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +29 -4
- package/dist/init.js +1 -0
- package/dist/utils.js +21 -2
- package/dist/zod-state.js +1 -0
- package/package.json +1 -1
- package/readme.md +44 -15
- package/src/index.ts +10 -3
- package/src/utils.ts +20 -0
- package/src/zod-state.ts +2 -0
package/dist/index.js
CHANGED
|
@@ -28,7 +28,7 @@ var p = __toESM(require("@clack/prompts"));
|
|
|
28
28
|
var import_picocolors2 = __toESM(require("picocolors"));
|
|
29
29
|
var import_simple_git = require("simple-git");
|
|
30
30
|
var import_fs = __toESM(require("fs"));
|
|
31
|
-
var
|
|
31
|
+
var import_child_process2 = require("child_process");
|
|
32
32
|
var import_zod_validation_error = require("zod-validation-error");
|
|
33
33
|
|
|
34
34
|
// src/zod-state.ts
|
|
@@ -38,6 +38,7 @@ var import_zod2 = require("zod");
|
|
|
38
38
|
var import_os = require("os");
|
|
39
39
|
var import_zod = require("zod");
|
|
40
40
|
var import_picocolors = __toESM(require("picocolors"));
|
|
41
|
+
var import_child_process = require("child_process");
|
|
41
42
|
var CONFIG_FILE_NAME = ".better-commits.json";
|
|
42
43
|
var SPACE_TO_SELECT = `${import_picocolors.default.dim("(<space> to select)")}`;
|
|
43
44
|
var OPTIONAL_PROMPT = `${import_picocolors.default.dim("(optional)")}`;
|
|
@@ -68,6 +69,22 @@ var COMMIT_FOOTER_OPTIONS = [
|
|
|
68
69
|
];
|
|
69
70
|
var Z_FOOTER_OPTIONS = import_zod.z.enum(["closes", "breaking-change", "deprecated"]);
|
|
70
71
|
var FOOTER_OPTION_VALUES = ["closes", "breaking-change", "deprecated"];
|
|
72
|
+
function infer_type_from_branch(types) {
|
|
73
|
+
let branch = "";
|
|
74
|
+
try {
|
|
75
|
+
branch = (0, import_child_process.execSync)("git branch --show-current", { stdio: "pipe" }).toString();
|
|
76
|
+
} catch (err) {
|
|
77
|
+
return "";
|
|
78
|
+
}
|
|
79
|
+
const found = types.find((t) => {
|
|
80
|
+
const start_dash = new RegExp(`^${t}-`);
|
|
81
|
+
const between_dash = new RegExp(`-${t}-`);
|
|
82
|
+
const before_slash = new RegExp(`${t}/`);
|
|
83
|
+
const re = [branch.match(start_dash), branch.match(between_dash), branch.match(before_slash)].filter((v) => v != null);
|
|
84
|
+
return re?.length;
|
|
85
|
+
});
|
|
86
|
+
return found ?? "";
|
|
87
|
+
}
|
|
71
88
|
function get_default_config_path() {
|
|
72
89
|
return (0, import_os.homedir)() + "/" + CONFIG_FILE_NAME;
|
|
73
90
|
}
|
|
@@ -92,6 +109,7 @@ var Config = import_zod2.z.object({
|
|
|
92
109
|
commit_type: import_zod2.z.object({
|
|
93
110
|
enable: import_zod2.z.boolean().default(true),
|
|
94
111
|
initial_value: import_zod2.z.string().default("feat"),
|
|
112
|
+
infer_type_from_branch: import_zod2.z.boolean().default(true),
|
|
95
113
|
options: import_zod2.z.array(import_zod2.z.object({
|
|
96
114
|
value: import_zod2.z.string(),
|
|
97
115
|
label: import_zod2.z.string().optional(),
|
|
@@ -155,7 +173,7 @@ main(load_setup());
|
|
|
155
173
|
function load_setup() {
|
|
156
174
|
console.clear();
|
|
157
175
|
p.intro(`${import_picocolors2.default.bgCyan(import_picocolors2.default.black(" better-commits "))}`);
|
|
158
|
-
const root = (0,
|
|
176
|
+
const root = (0, import_child_process2.execSync)("git rev-parse --show-toplevel").toString().trim();
|
|
159
177
|
const root_path = `${root}/${CONFIG_FILE_NAME}`;
|
|
160
178
|
if (import_fs.default.existsSync(root_path)) {
|
|
161
179
|
p.log.step("Found repository config");
|
|
@@ -219,10 +237,17 @@ async function main(config) {
|
|
|
219
237
|
process.exit(0);
|
|
220
238
|
}
|
|
221
239
|
if (config.commit_type.enable) {
|
|
240
|
+
let initial_value = config.commit_type.initial_value;
|
|
241
|
+
if (config.commit_type.infer_type_from_branch) {
|
|
242
|
+
const options = config.commit_type.options.map((o) => o.value);
|
|
243
|
+
const type_from_branch = infer_type_from_branch(options);
|
|
244
|
+
if (type_from_branch)
|
|
245
|
+
initial_value = type_from_branch;
|
|
246
|
+
}
|
|
222
247
|
const commit_type = await p.select(
|
|
223
248
|
{
|
|
224
249
|
message: `Select a commit type`,
|
|
225
|
-
initialValue:
|
|
250
|
+
initialValue: initial_value,
|
|
226
251
|
options: config.commit_type.options
|
|
227
252
|
}
|
|
228
253
|
);
|
|
@@ -242,7 +267,7 @@ async function main(config) {
|
|
|
242
267
|
}
|
|
243
268
|
if (config.check_ticket.infer_ticket) {
|
|
244
269
|
try {
|
|
245
|
-
const branch = (0,
|
|
270
|
+
const branch = (0, import_child_process2.execSync)("git branch --show-current", { stdio: "pipe" }).toString();
|
|
246
271
|
const found = [branch.match(REGEX_SLASH_TAG), branch.match(REGEX_SLASH_NUM), branch.match(REGEX_START_TAG), branch.match(REGEX_START_NUM)].filter((v) => v != null).map((v) => v && v.length >= 2 ? v[1] : "");
|
|
247
272
|
if (found.length && found[0]) {
|
|
248
273
|
commit_state.ticket = config.check_ticket.append_hashtag ? "#" + found[0] : found[0];
|
package/dist/init.js
CHANGED
|
@@ -61,6 +61,7 @@ var Config = import_zod2.z.object({
|
|
|
61
61
|
commit_type: import_zod2.z.object({
|
|
62
62
|
enable: import_zod2.z.boolean().default(true),
|
|
63
63
|
initial_value: import_zod2.z.string().default("feat"),
|
|
64
|
+
infer_type_from_branch: import_zod2.z.boolean().default(true),
|
|
64
65
|
options: import_zod2.z.array(import_zod2.z.object({
|
|
65
66
|
value: import_zod2.z.string(),
|
|
66
67
|
label: import_zod2.z.string().optional(),
|
package/dist/utils.js
CHANGED
|
@@ -45,12 +45,14 @@ __export(utils_exports, {
|
|
|
45
45
|
addNewLine: () => addNewLine,
|
|
46
46
|
check_missing_stage: () => check_missing_stage,
|
|
47
47
|
clean_commit_title: () => clean_commit_title,
|
|
48
|
-
get_default_config_path: () => get_default_config_path
|
|
48
|
+
get_default_config_path: () => get_default_config_path,
|
|
49
|
+
infer_type_from_branch: () => infer_type_from_branch
|
|
49
50
|
});
|
|
50
51
|
module.exports = __toCommonJS(utils_exports);
|
|
51
52
|
var import_os = require("os");
|
|
52
53
|
var import_zod = require("zod");
|
|
53
54
|
var import_picocolors = __toESM(require("picocolors"));
|
|
55
|
+
var import_child_process = require("child_process");
|
|
54
56
|
var CONFIG_FILE_NAME = ".better-commits.json";
|
|
55
57
|
var SPACE_TO_SELECT = `${import_picocolors.default.dim("(<space> to select)")}`;
|
|
56
58
|
var OPTIONAL_PROMPT = `${import_picocolors.default.dim("(optional)")}`;
|
|
@@ -81,6 +83,22 @@ var COMMIT_FOOTER_OPTIONS = [
|
|
|
81
83
|
];
|
|
82
84
|
var Z_FOOTER_OPTIONS = import_zod.z.enum(["closes", "breaking-change", "deprecated"]);
|
|
83
85
|
var FOOTER_OPTION_VALUES = ["closes", "breaking-change", "deprecated"];
|
|
86
|
+
function infer_type_from_branch(types) {
|
|
87
|
+
let branch = "";
|
|
88
|
+
try {
|
|
89
|
+
branch = (0, import_child_process.execSync)("git branch --show-current", { stdio: "pipe" }).toString();
|
|
90
|
+
} catch (err) {
|
|
91
|
+
return "";
|
|
92
|
+
}
|
|
93
|
+
const found = types.find((t) => {
|
|
94
|
+
const start_dash = new RegExp(`^${t}-`);
|
|
95
|
+
const between_dash = new RegExp(`-${t}-`);
|
|
96
|
+
const before_slash = new RegExp(`${t}/`);
|
|
97
|
+
const re = [branch.match(start_dash), branch.match(between_dash), branch.match(before_slash)].filter((v) => v != null);
|
|
98
|
+
return re?.length;
|
|
99
|
+
});
|
|
100
|
+
return found ?? "";
|
|
101
|
+
}
|
|
84
102
|
function get_default_config_path() {
|
|
85
103
|
return (0, import_os.homedir)() + "/" + CONFIG_FILE_NAME;
|
|
86
104
|
}
|
|
@@ -115,5 +133,6 @@ function clean_commit_title(title) {
|
|
|
115
133
|
addNewLine,
|
|
116
134
|
check_missing_stage,
|
|
117
135
|
clean_commit_title,
|
|
118
|
-
get_default_config_path
|
|
136
|
+
get_default_config_path,
|
|
137
|
+
infer_type_from_branch
|
|
119
138
|
});
|
package/dist/zod-state.js
CHANGED
|
@@ -70,6 +70,7 @@ var Config = import_zod2.z.object({
|
|
|
70
70
|
commit_type: import_zod2.z.object({
|
|
71
71
|
enable: import_zod2.z.boolean().default(true),
|
|
72
72
|
initial_value: import_zod2.z.string().default("feat"),
|
|
73
|
+
infer_type_from_branch: import_zod2.z.boolean().default(true),
|
|
73
74
|
options: import_zod2.z.array(import_zod2.z.object({
|
|
74
75
|
value: import_zod2.z.string(),
|
|
75
76
|
label: import_zod2.z.string().optional(),
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "better-commits",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.3",
|
|
5
5
|
"description": "A CLI for creating better commits following the conventional commit guidelines",
|
|
6
6
|
"author": "Erik Verduin (https://github.com/everduin94)",
|
|
7
7
|
"keywords": [
|
package/readme.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# 📝 Better Commits
|
|
2
2
|
|
|
3
|
-
A CLI
|
|
3
|
+
A CLI for writing better commits, following the conventional commit guidelines, written with Typescript | ZOD | Clack
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
https://user-images.githubusercontent.com/14320878/224050591-c6035ac5-1120-40c8-97b0-c33ebcb11b3e.mov
|
|
6
6
|
|
|
7
7
|
## ✨ Features
|
|
8
8
|
- Follows the conventional commit guidelines
|
|
@@ -10,7 +10,7 @@ GIF
|
|
|
10
10
|
- Easy install with sane defaults
|
|
11
11
|
- Checks git status with interactive git add
|
|
12
12
|
- Works globally or in your repository
|
|
13
|
-
- Attempts to infer ticket/issue from branch
|
|
13
|
+
- Attempts to infer ticket/issue and type from branch
|
|
14
14
|
- Pretty prints preview in color
|
|
15
15
|
- Validates config at runtime
|
|
16
16
|
|
|
@@ -55,6 +55,7 @@ All properties are optional, they can be removed from your configuration and wil
|
|
|
55
55
|
"commit_type": {
|
|
56
56
|
"enable": true,
|
|
57
57
|
"initial_value": "feat",
|
|
58
|
+
"infer_type_from_branch": true,
|
|
58
59
|
"options": [
|
|
59
60
|
{
|
|
60
61
|
"value": "feat",
|
|
@@ -68,15 +69,15 @@ All properties are optional, they can be removed from your configuration and wil
|
|
|
68
69
|
"value": "docs",
|
|
69
70
|
"label": "docs"
|
|
70
71
|
},
|
|
71
|
-
|
|
72
|
+
{
|
|
72
73
|
"value": "refactor",
|
|
73
74
|
"label": "refactor"
|
|
74
75
|
},
|
|
75
|
-
|
|
76
|
+
{
|
|
76
77
|
"value": "perf",
|
|
77
78
|
"label": "perf"
|
|
78
79
|
},
|
|
79
|
-
|
|
80
|
+
{
|
|
80
81
|
"value": "test",
|
|
81
82
|
"label": "test"
|
|
82
83
|
},
|
|
@@ -102,7 +103,7 @@ All properties are optional, they can be removed from your configuration and wil
|
|
|
102
103
|
"value": "server",
|
|
103
104
|
"label": "server"
|
|
104
105
|
},
|
|
105
|
-
|
|
106
|
+
{
|
|
106
107
|
"value": "tools",
|
|
107
108
|
"label": "tools"
|
|
108
109
|
},
|
|
@@ -116,7 +117,7 @@ All properties are optional, they can be removed from your configuration and wil
|
|
|
116
117
|
"infer_ticket": true,
|
|
117
118
|
"confirm_ticket": true,
|
|
118
119
|
"add_to_title": true,
|
|
119
|
-
|
|
120
|
+
"append_hashtag": false
|
|
120
121
|
},
|
|
121
122
|
"commit_title": {
|
|
122
123
|
"max_size": 70
|
|
@@ -141,16 +142,44 @@ All properties are optional, they can be removed from your configuration and wil
|
|
|
141
142
|
}
|
|
142
143
|
```
|
|
143
144
|
|
|
144
|
-
#### Config Validation
|
|
145
|
-
To simplify the CLI, some rules are enforced at runtime to make sure the program runs properly.
|
|
146
|
-
- any property can be removed,
|
|
147
|
-
- if a property is a string/number/boolean in the default, it must
|
|
148
|
-
- the `initial_value` must be a valid value in `options`
|
|
149
|
-
- `commit_scope` and `commit_type` can be populated with as many or whatever options
|
|
145
|
+
#### ✅ Config Validation
|
|
146
|
+
To simplify the CLI, some rules are enforced at runtime to make sure the program runs properly.
|
|
147
|
+
- any property can be removed from the config, it will be replaced by the default at run-time
|
|
148
|
+
- if a property is a string/number/boolean in the default, it must stay that type
|
|
149
|
+
- the `initial_value` must be a valid value in the corresponding `options`
|
|
150
|
+
- `commit_scope` and `commit_type` can be populated with as many or whatever options
|
|
151
|
+
- must maintain the shape `{value: string, label?: string, hint?: string}`
|
|
150
152
|
- `hint` and `label` are optional
|
|
151
153
|
- to force scope or type to be required, remove `None`
|
|
152
154
|
- `commit_footer` options are supplied from a fixed list, because they have specific functionality
|
|
153
|
-
- thus, you can remove from that list, but you can't add custom
|
|
155
|
+
- thus, you can remove from that list, but you can't add custom values to it
|
|
156
|
+
|
|
157
|
+
#### 🔎 Inference
|
|
158
|
+
|
|
159
|
+
`better-commits` will attempt to infer the ticket/issue and the type from your branch name. It will auto populate the corresponding field if found.
|
|
160
|
+
|
|
161
|
+
**Ticket**
|
|
162
|
+
- `STRING-NUMBER` -- If a string-number is at the start of the branch
|
|
163
|
+
- `/STRING-NUMBER` -- If a string-number comes after a /
|
|
164
|
+
|
|
165
|
+
**Issue**
|
|
166
|
+
- `NUMBER` -- If a number is at the start of the branch
|
|
167
|
+
- `/NUMBER` -- If a number comes after a /
|
|
168
|
+
|
|
169
|
+
**Type**
|
|
170
|
+
- `TYPE-` -- If a type is at the start of the branch
|
|
171
|
+
- `TYPE/` -- If a slash comes after the type
|
|
172
|
+
- `-TYPE-` -- If a type is between two dashes
|
|
173
|
+
|
|
174
|
+
## 😮 Mildly Interesting
|
|
175
|
+
- `better-commits` works with [Semantic Release](https://github.com/semantic-release/semantic-release)
|
|
176
|
+
- if you use `better-commits` to create your *first* commit on a new branch, when you open a PR for that branch, it will properly **auto-populate the title and body**.
|
|
177
|
+
- when you squash / merge with github, if `better-commits` is your *first* commit, all later commits like "addressing comments", "fixing mistake". Will be prefixed with an asterisk for easy deletion. This way you **maintain your pretty commit even when squashing**.
|
|
178
|
+
- if you use a branch name like the ones below, better-commits will be able to infer your ticket/issue and type
|
|
179
|
+
- `TYPE/TICKET-description`
|
|
180
|
+
- `USER/TYPE/TICKET-description`
|
|
181
|
+
- if you're using Github issues to track your work, and select the `closes` footer option when writing your commit. Github will **automatically link and close** that issue when your **pr is merged**
|
|
182
|
+
- [better-commits](https://packagephobia.com/result?p=better-commits) is much smaller than its alternative [commitizen](https://packagephobia.com/result?p=commitizen)
|
|
154
183
|
|
|
155
184
|
## Alternatives
|
|
156
185
|
- Commitizen
|
package/src/index.ts
CHANGED
|
@@ -8,7 +8,8 @@ import { execSync } from 'child_process';
|
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
import { fromZodError } from 'zod-validation-error';
|
|
10
10
|
import { CommitState, Config } from './zod-state';
|
|
11
|
-
import { CONFIG_FILE_NAME, get_default_config_path, check_missing_stage, addNewLine, SPACE_TO_SELECT, REGEX_SLASH_TAG, REGEX_SLASH_NUM, REGEX_START_TAG, REGEX_START_NUM, OPTIONAL_PROMPT, clean_commit_title, COMMIT_FOOTER_OPTIONS } from './utils';
|
|
11
|
+
import { CONFIG_FILE_NAME, get_default_config_path, check_missing_stage, addNewLine, SPACE_TO_SELECT, REGEX_SLASH_TAG, REGEX_SLASH_NUM, REGEX_START_TAG, REGEX_START_NUM, OPTIONAL_PROMPT, clean_commit_title, COMMIT_FOOTER_OPTIONS, infer_type_from_branch } from './utils';
|
|
12
|
+
|
|
12
13
|
|
|
13
14
|
main(load_setup());
|
|
14
15
|
|
|
@@ -90,10 +91,16 @@ async function main(config: z.infer<typeof Config>) {
|
|
|
90
91
|
}
|
|
91
92
|
|
|
92
93
|
if (config.commit_type.enable) {
|
|
94
|
+
let initial_value = config.commit_type.initial_value
|
|
95
|
+
if (config.commit_type.infer_type_from_branch) {
|
|
96
|
+
const options = config.commit_type.options.map(o => o.value)
|
|
97
|
+
const type_from_branch = infer_type_from_branch(options)
|
|
98
|
+
if (type_from_branch) initial_value = type_from_branch
|
|
99
|
+
}
|
|
93
100
|
const commit_type = await p.select(
|
|
94
101
|
{
|
|
95
102
|
message: `Select a commit type`,
|
|
96
|
-
initialValue:
|
|
103
|
+
initialValue: initial_value,
|
|
97
104
|
options: config.commit_type.options,
|
|
98
105
|
}
|
|
99
106
|
) as string
|
|
@@ -113,7 +120,7 @@ async function main(config: z.infer<typeof Config>) {
|
|
|
113
120
|
|
|
114
121
|
if (config.check_ticket.infer_ticket) {
|
|
115
122
|
try {
|
|
116
|
-
const branch = execSync('git
|
|
123
|
+
const branch = execSync('git branch --show-current', {stdio : 'pipe' }).toString();
|
|
117
124
|
const found: string[] = [branch.match(REGEX_SLASH_TAG), branch.match(REGEX_SLASH_NUM) , branch.match(REGEX_START_TAG), branch.match(REGEX_START_NUM)]
|
|
118
125
|
.filter(v => v != null)
|
|
119
126
|
.map(v => v && v.length >= 2 ? v[1] : '')
|
package/src/utils.ts
CHANGED
|
@@ -2,6 +2,7 @@ import {homedir} from 'os';
|
|
|
2
2
|
import { StatusResult } from 'simple-git';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import color from 'picocolors';
|
|
5
|
+
import { execSync } from 'child_process';
|
|
5
6
|
|
|
6
7
|
export const CONFIG_FILE_NAME = '.better-commits.json'
|
|
7
8
|
export const SPACE_TO_SELECT = `${color.dim('(<space> to select)')}`
|
|
@@ -37,6 +38,25 @@ export const COMMIT_FOOTER_OPTIONS = [
|
|
|
37
38
|
export const Z_FOOTER_OPTIONS = z.enum(['closes', 'breaking-change', 'deprecated'])
|
|
38
39
|
export const FOOTER_OPTION_VALUES: FOOTER_OPTIONS[] = ['closes', 'breaking-change', 'deprecated']
|
|
39
40
|
|
|
41
|
+
export function infer_type_from_branch(types: string[]): string {
|
|
42
|
+
let branch = ''
|
|
43
|
+
try {
|
|
44
|
+
branch = execSync('git branch --show-current', {stdio : 'pipe' }).toString();
|
|
45
|
+
} catch (err) {
|
|
46
|
+
return ''
|
|
47
|
+
}
|
|
48
|
+
const found = types.find(t => {
|
|
49
|
+
const start_dash = new RegExp(`^${t}-`)
|
|
50
|
+
const between_dash = new RegExp(`-${t}-`)
|
|
51
|
+
const before_slash = new RegExp(`${t}\/`)
|
|
52
|
+
const re = [branch.match(start_dash), branch.match(between_dash), branch.match(before_slash)]
|
|
53
|
+
.filter(v => v != null)
|
|
54
|
+
return re?.length
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
return found ?? ''
|
|
58
|
+
}
|
|
59
|
+
|
|
40
60
|
export function get_default_config_path(): string {
|
|
41
61
|
return homedir()+'/'+CONFIG_FILE_NAME
|
|
42
62
|
}
|
package/src/zod-state.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { z } from "zod"
|
|
2
2
|
import { DEFAULT_SCOPE_OPTIONS, DEFAULT_TYPE_OPTIONS, FOOTER_OPTION_VALUES, Z_FOOTER_OPTIONS } from "./utils"
|
|
3
3
|
|
|
4
|
+
|
|
4
5
|
// TODO: add "Ref", "Fixes", ability to change phrase "Closes/closes/closes:"
|
|
5
6
|
export const Config = z.object({
|
|
6
7
|
check_status: z.boolean().default(true),
|
|
7
8
|
commit_type: z.object({
|
|
8
9
|
enable: z.boolean().default(true),
|
|
9
10
|
initial_value: z.string().default('feat'),
|
|
11
|
+
infer_type_from_branch: z.boolean().default(true),
|
|
10
12
|
options: z.array(z.object({
|
|
11
13
|
value: z.string(),
|
|
12
14
|
label: z.string().optional(),
|