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 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 import_child_process = require("child_process");
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, import_child_process.execSync)("git rev-parse --show-toplevel").toString().trim();
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: config.commit_type.initial_value,
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, import_child_process.execSync)("git rev-parse --abbrev-ref HEAD", { stdio: "pipe" }).toString();
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.1",
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 to write better commits, written with Typescript | ZOD | Clack
3
+ A CLI for writing better commits, following the conventional commit guidelines, written with Typescript | ZOD | Clack
4
4
 
5
- GIF
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
- "append_hashtag": false
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. Most of these are fairly straight forward.
146
- - any property can be removed, but it will be replaced by the default
147
- - if a property is a string/number/boolean in the default, it must maintain that type when modified
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 you like, as long as they maintain the shape `{value: string, label?: string, hint?: string}`
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 strings to it
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: config.commit_type.initial_value,
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 rev-parse --abbrev-ref HEAD', {stdio : 'pipe' }).toString();
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(),