better-commits 1.19.1 → 1.20.0-cli-flags

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.
Files changed (65) hide show
  1. package/.better-commits.json +4 -0
  2. package/.github/workflows/test.yml +27 -0
  3. package/.opencode/package-lock.json +115 -0
  4. package/.opencode/plans/cli-args.md +182 -0
  5. package/.svelte-kit/ambient.d.ts +289 -0
  6. package/.svelte-kit/generated/client/app.js +28 -0
  7. package/.svelte-kit/generated/client/matchers.js +1 -0
  8. package/.svelte-kit/generated/client/nodes/0.js +1 -0
  9. package/.svelte-kit/generated/client/nodes/1.js +1 -0
  10. package/.svelte-kit/tsconfig.json +49 -0
  11. package/0001-feat-branch-124-update-worktrees-feature.patch +316 -0
  12. package/dist/branch.js +27 -1
  13. package/dist/chunk-OFJCRS3N.js +4 -0
  14. package/dist/chunk-SIF4LZUS.js +1 -0
  15. package/dist/index.js +44 -19
  16. package/dist/init.js +1 -1
  17. package/docs/ai-skills.yaml +48 -0
  18. package/docs/clack.md +143 -0
  19. package/docs/valibot.md +228 -0
  20. package/package.json +12 -9
  21. package/readme.md +18 -2
  22. package/src/args.test.ts +102 -0
  23. package/src/args.ts +101 -7
  24. package/src/branch-args.test.ts +72 -0
  25. package/src/branch-args.ts +106 -0
  26. package/src/branch-help.ts +114 -0
  27. package/src/branch.ts +67 -238
  28. package/src/help.ts +131 -0
  29. package/src/index.test.ts +7 -0
  30. package/src/index.ts +73 -495
  31. package/src/prompts/branch-checkout.prompt.ts +36 -0
  32. package/src/prompts/branch-confirm.prompt.ts +134 -0
  33. package/src/prompts/branch-description.prompt.ts +37 -0
  34. package/src/prompts/branch-runnable.ts +13 -0
  35. package/src/prompts/branch-ticket.prompt.ts +41 -0
  36. package/src/prompts/branch-type.prompt.ts +43 -0
  37. package/src/prompts/branch-user.prompt.ts +50 -0
  38. package/src/prompts/branch-version.prompt.ts +41 -0
  39. package/src/prompts/commit-body.prompt.ts +57 -0
  40. package/src/prompts/commit-confirm.prompt.ts +119 -0
  41. package/src/prompts/commit-footer.prompt.ts +195 -0
  42. package/src/prompts/commit-scope.prompt.ts +73 -0
  43. package/src/prompts/commit-status.prompt.ts +75 -0
  44. package/src/prompts/commit-ticket.prompt.ts +82 -0
  45. package/src/prompts/commit-title.prompt.ts +98 -0
  46. package/src/prompts/commit-type.prompt.ts +93 -0
  47. package/src/prompts/runnable.ts +13 -0
  48. package/src/utils/build-branch.test.ts +141 -0
  49. package/src/utils/build-branch.ts +46 -0
  50. package/src/utils/build-commit-string.test.ts +253 -0
  51. package/src/utils/build-commit-string.ts +158 -0
  52. package/src/utils/commit-title-size.ts +24 -0
  53. package/src/utils/infer.test.ts +83 -0
  54. package/src/utils/infer.ts +114 -0
  55. package/src/utils/messages.ts +25 -0
  56. package/src/utils/no-interactive-branch-validation.test.ts +170 -0
  57. package/src/utils/no-interactive-validation.test.ts +174 -0
  58. package/src/utils/no-interactive-validation.ts +190 -0
  59. package/src/utils.ts +59 -66
  60. package/src/valibot-consts.ts +2 -2
  61. package/src/valibot-state.test.ts +48 -0
  62. package/src/valibot-state.ts +133 -130
  63. package/tsconfig.json +3 -2
  64. package/vitest.config.ts +8 -0
  65. package/dist/chunk-K2RPF2JY.js +0 -4
@@ -0,0 +1,114 @@
1
+ import { execSync } from "child_process";
2
+ import { flags } from "../args";
3
+ import { InferOutput } from "valibot";
4
+ import { Config } from "../valibot-state";
5
+
6
+ type PrependHashtag = "Never" | "Always" | "Prompt";
7
+
8
+ const REGEX_SLASH_TAG = /\/(\w+-\d+)/;
9
+ const REGEX_START_TAG = /^(\w+-\d+)/;
10
+ const REGEX_START_UND = /^([A-Z]+-[\[a-zA-Z\]\d]+)_/;
11
+ const REGEX_SLASH_UND = /\/([A-Z]+-[\[a-zA-Z\]\d]+)_/;
12
+ const REGEX_SLASH_NUM = /\/(\d+)/;
13
+ const REGEX_START_NUM = /^(\d+)/;
14
+
15
+ // TODO: Hypothetically, we could just do this, then remove code from prompts?
16
+ export function infer_not_interactive(config: InferOutput<typeof Config>) {
17
+ if (flags.interactive) return;
18
+
19
+ let inferred_state = { ticket: "", type: "" };
20
+
21
+ if (config.check_ticket.infer_ticket) {
22
+ const inferred_ticket = infer_ticket_from_git(
23
+ {
24
+ append_hashtag: config.check_ticket.append_hashtag,
25
+ prepend_hashtag: config.check_ticket.prepend_hashtag,
26
+ },
27
+ flags.git_args,
28
+ );
29
+ inferred_state.ticket = inferred_ticket;
30
+ }
31
+
32
+ const inferred_type = infer_type_from_git(
33
+ config.commit_type.options,
34
+ flags.git_args,
35
+ );
36
+ inferred_state.type = inferred_type;
37
+
38
+ return inferred_state;
39
+ }
40
+
41
+ export function infer_type_from_git(
42
+ options: { value: string }[],
43
+ git_args: string,
44
+ ): string {
45
+ const branch = get_current_branch(git_args);
46
+ if (!branch) return "";
47
+
48
+ return infer_type_from_branch(
49
+ branch,
50
+ options.map((option) => option.value),
51
+ );
52
+ }
53
+
54
+ export function infer_ticket_from_git(
55
+ options: { append_hashtag: boolean; prepend_hashtag: PrependHashtag },
56
+ git_args: string,
57
+ ): string {
58
+ const branch = get_current_branch(git_args);
59
+ if (!branch) return "";
60
+
61
+ return infer_ticket_from_branch(branch, options);
62
+ }
63
+
64
+ function infer_ticket_from_branch(
65
+ branch: string,
66
+ options: { append_hashtag: boolean; prepend_hashtag: PrependHashtag },
67
+ ): string {
68
+ const found: string[] = [
69
+ branch.match(REGEX_START_UND),
70
+ branch.match(REGEX_SLASH_UND),
71
+ branch.match(REGEX_SLASH_TAG),
72
+ branch.match(REGEX_SLASH_NUM),
73
+ branch.match(REGEX_START_TAG),
74
+ branch.match(REGEX_START_NUM),
75
+ ]
76
+ .filter((value) => value != null)
77
+ .map((value) => (value && value.length >= 2 ? value[1] : ""));
78
+
79
+ if (!found.length || !found[0]) return "";
80
+
81
+ return options.append_hashtag || options.prepend_hashtag === "Always"
82
+ ? `#${found[0]}`
83
+ : found[0];
84
+ }
85
+
86
+ function infer_type_from_branch(branch: string, types: string[]): string {
87
+ const found = types.find((type) => {
88
+ const start_dash = new RegExp(`^${type}-`);
89
+ const between_dash = new RegExp(`-${type}-`);
90
+ const before_slash = new RegExp(`${type}/`);
91
+
92
+ const matches = [
93
+ branch.match(start_dash),
94
+ branch.match(between_dash),
95
+ branch.match(before_slash),
96
+ ].filter((value) => value != null);
97
+
98
+ return matches.length > 0;
99
+ });
100
+
101
+ return found ?? "";
102
+ }
103
+
104
+ function get_current_branch(git_args: string): string {
105
+ try {
106
+ return execSync(`git ${git_args} branch --show-current`, {
107
+ stdio: "pipe",
108
+ })
109
+ .toString()
110
+ .trim();
111
+ } catch {
112
+ return "";
113
+ }
114
+ }
@@ -0,0 +1,25 @@
1
+ import color from "picocolors";
2
+
3
+ export function cache_message(message: string): string {
4
+ return `${message} ${color.dim("· restored from cache")}`;
5
+ }
6
+
7
+ export function inferred_message(message: string): string {
8
+ return `${message} ${color.dim("· inferred from branch")}`;
9
+ }
10
+
11
+ export function optional_message(message: string): string {
12
+ return `${message} ${color.dim("· optional")}`;
13
+ }
14
+
15
+ export function space_to_select_message(message: string): string {
16
+ return `${message} ${color.dim("· <space> to select")}`;
17
+ }
18
+
19
+ export function a_for_all_message(message: string): string {
20
+ return `${message} ${color.dim("· <space> to select | <a> to select all")}`;
21
+ }
22
+
23
+ export function dry_run_message(message: string): string {
24
+ return `${message} ${color.dim("· dry run - changes will not be committed")}`;
25
+ }
@@ -0,0 +1,170 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { parse } from "valibot";
3
+ import { BranchState, Config } from "../valibot-state";
4
+ import { create_strict_branch_state } from "./no-interactive-validation";
5
+
6
+ function make_config(input: Record<string, unknown> = {}) {
7
+ return parse(Config, input);
8
+ }
9
+
10
+ function make_state(input: Record<string, unknown>) {
11
+ return parse(BranchState, input);
12
+ }
13
+
14
+ describe("create_strict_branch_state", () => {
15
+ it("accepts valid parsed branch state input", () => {
16
+ const config = make_config();
17
+ const schema = create_strict_branch_state(config);
18
+
19
+ const result = parse(
20
+ schema,
21
+ make_state({
22
+ type: "feat",
23
+ description: "add-parser",
24
+ }),
25
+ );
26
+
27
+ expect(result.type).toBe("feat");
28
+ expect(result.description).toBe("add-parser");
29
+ });
30
+
31
+ it('defaults checkout to "branch" when omitted', () => {
32
+ const config = make_config();
33
+ const schema = create_strict_branch_state(config);
34
+
35
+ const result = parse(
36
+ schema,
37
+ make_state({
38
+ type: "feat",
39
+ description: "add-parser",
40
+ }),
41
+ );
42
+
43
+ expect(result.checkout).toBe("branch");
44
+ });
45
+
46
+ it("rejects types that are not in config.commit_type.options", () => {
47
+ const config = make_config();
48
+ const schema = create_strict_branch_state(config);
49
+
50
+ expect(() =>
51
+ parse(
52
+ schema,
53
+ make_state({
54
+ type: "unknown",
55
+ description: "add-parser",
56
+ }),
57
+ ),
58
+ ).toThrow(/Invalid --type "unknown"/);
59
+ });
60
+
61
+ it("rejects missing descriptions", () => {
62
+ const config = make_config();
63
+ const schema = create_strict_branch_state(config);
64
+
65
+ expect(() =>
66
+ parse(
67
+ schema,
68
+ make_state({
69
+ type: "feat",
70
+ }),
71
+ ),
72
+ ).toThrow(/Missing --description/);
73
+ });
74
+
75
+ it("rejects descriptions that exceed branch_description.max_length", () => {
76
+ const config = make_config({
77
+ branch_description: {
78
+ max_length: 5,
79
+ },
80
+ });
81
+ const schema = create_strict_branch_state(config);
82
+
83
+ expect(() =>
84
+ parse(
85
+ schema,
86
+ make_state({
87
+ type: "feat",
88
+ description: "too-long",
89
+ }),
90
+ ),
91
+ ).toThrow(/Description exceeds max length/);
92
+ });
93
+
94
+ it("rejects missing ticket when branch_ticket.required is enabled", () => {
95
+ const config = make_config({
96
+ branch_ticket: {
97
+ required: true,
98
+ },
99
+ });
100
+ const schema = create_strict_branch_state(config);
101
+
102
+ expect(() =>
103
+ parse(
104
+ schema,
105
+ make_state({
106
+ type: "feat",
107
+ description: "add-parser",
108
+ }),
109
+ ),
110
+ ).toThrow(/Missing --ticket/);
111
+ });
112
+
113
+ it("rejects missing version when branch_version.required is enabled", () => {
114
+ const config = make_config({
115
+ branch_version: {
116
+ required: true,
117
+ },
118
+ });
119
+ const schema = create_strict_branch_state(config);
120
+
121
+ expect(() =>
122
+ parse(
123
+ schema,
124
+ make_state({
125
+ type: "feat",
126
+ description: "add-parser",
127
+ }),
128
+ ),
129
+ ).toThrow(/Missing --branch-version/);
130
+ });
131
+
132
+ it("rejects missing user when branch_user.required is enabled", () => {
133
+ const config = make_config({
134
+ branch_user: {
135
+ required: true,
136
+ },
137
+ });
138
+ const schema = create_strict_branch_state(config);
139
+
140
+ expect(() =>
141
+ parse(
142
+ schema,
143
+ make_state({
144
+ type: "feat",
145
+ description: "add-parser",
146
+ }),
147
+ ),
148
+ ).toThrow(/Missing --user/);
149
+ });
150
+
151
+ it("allows worktree checkout even when worktrees are disabled", () => {
152
+ const config = make_config({
153
+ worktrees: {
154
+ enable: false,
155
+ },
156
+ });
157
+ const schema = create_strict_branch_state(config);
158
+
159
+ const result = parse(
160
+ schema,
161
+ make_state({
162
+ type: "feat",
163
+ description: "add-parser",
164
+ checkout: "worktree",
165
+ }),
166
+ );
167
+
168
+ expect(result.checkout).toBe("worktree");
169
+ });
170
+ });
@@ -0,0 +1,174 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { parse } from "valibot";
3
+ import { CommitState, Config } from "../valibot-state";
4
+ import { create_strict_commit_state } from "./no-interactive-validation";
5
+
6
+ function make_config(input: Record<string, unknown> = {}) {
7
+ return parse(Config, input);
8
+ }
9
+
10
+ function make_state(input: Record<string, unknown>) {
11
+ return parse(CommitState, input);
12
+ }
13
+
14
+ describe("create_strict_commit_state", () => {
15
+ it("accepts valid parsed commit state input", () => {
16
+ const config = make_config();
17
+ const schema = create_strict_commit_state(config);
18
+
19
+ const result = parse(
20
+ schema,
21
+ make_state({
22
+ type: "feat",
23
+ title: "add parser",
24
+ }),
25
+ );
26
+
27
+ expect(result.type).toBe("feat");
28
+ expect(result.title).toBe("add parser");
29
+ });
30
+
31
+ it("rejects types that are not in config.commit_type.options", () => {
32
+ const config = make_config();
33
+ const schema = create_strict_commit_state(config);
34
+
35
+ expect(() =>
36
+ parse(
37
+ schema,
38
+ make_state({
39
+ type: "unknown",
40
+ title: "add parser",
41
+ }),
42
+ ),
43
+ ).toThrow(/Invalid --type "unknown"/);
44
+ });
45
+
46
+ it("allows custom scopes when custom_scope is enabled", () => {
47
+ const config = make_config({
48
+ commit_scope: {
49
+ custom_scope: true,
50
+ initial_value: "custom",
51
+ options: [{ value: "app", label: "app" }],
52
+ },
53
+ });
54
+ const schema = create_strict_commit_state(config);
55
+
56
+ const result = parse(
57
+ schema,
58
+ make_state({
59
+ type: "feat",
60
+ scope: "custom-auth",
61
+ title: "add parser",
62
+ }),
63
+ );
64
+
65
+ expect(result.scope).toBe("custom-auth");
66
+ });
67
+
68
+ it("rejects scopes outside configured options when custom_scope is disabled", () => {
69
+ const config = make_config({
70
+ commit_scope: {
71
+ custom_scope: false,
72
+ options: [{ value: "app", label: "app" }],
73
+ },
74
+ });
75
+ const schema = create_strict_commit_state(config);
76
+
77
+ expect(() =>
78
+ parse(
79
+ schema,
80
+ make_state({
81
+ type: "feat",
82
+ scope: "custom-auth",
83
+ title: "add parser",
84
+ }),
85
+ ),
86
+ ).toThrow(/Invalid --scope "custom-auth"/);
87
+ });
88
+
89
+ it("rejects missing body when commit_body.required is enabled", () => {
90
+ const config = make_config({
91
+ commit_body: {
92
+ required: true,
93
+ },
94
+ });
95
+ const schema = create_strict_commit_state(config);
96
+
97
+ expect(() =>
98
+ parse(
99
+ schema,
100
+ make_state({
101
+ type: "feat",
102
+ title: "add parser",
103
+ }),
104
+ ),
105
+ ).toThrow(/Missing --body/);
106
+ });
107
+
108
+ it("rejects titles that exceed commit_title.max_size", () => {
109
+ const config = make_config({
110
+ commit_title: {
111
+ max_size: 10,
112
+ },
113
+ });
114
+ const schema = create_strict_commit_state(config);
115
+
116
+ expect(() =>
117
+ parse(
118
+ schema,
119
+ make_state({
120
+ type: "feat",
121
+ title: "too long title",
122
+ }),
123
+ ),
124
+ ).toThrow(/Title exceeds max width/);
125
+ });
126
+
127
+ it("rejects closes footers without a ticket", () => {
128
+ const config = make_config();
129
+ const schema = create_strict_commit_state(config);
130
+
131
+ expect(() =>
132
+ parse(
133
+ schema,
134
+ make_state({
135
+ type: "feat",
136
+ title: "add parser",
137
+ closes: "Closes:",
138
+ }),
139
+ ),
140
+ ).toThrow(/--closes requires --ticket/);
141
+ });
142
+
143
+ it("rejects breaking bodies without breaking titles", () => {
144
+ const config = make_config();
145
+ const schema = create_strict_commit_state(config);
146
+
147
+ expect(() =>
148
+ parse(
149
+ schema,
150
+ make_state({
151
+ type: "feat",
152
+ title: "add parser",
153
+ breaking_body: "migration needed",
154
+ }),
155
+ ),
156
+ ).toThrow(/--breaking-body requires --breaking-title/);
157
+ });
158
+
159
+ it("rejects deprecates bodies without deprecates titles", () => {
160
+ const config = make_config();
161
+ const schema = create_strict_commit_state(config);
162
+
163
+ expect(() =>
164
+ parse(
165
+ schema,
166
+ make_state({
167
+ type: "feat",
168
+ title: "add parser",
169
+ deprecates_body: "use the new api",
170
+ }),
171
+ ),
172
+ ).toThrow(/--deprecates-body requires --deprecates-title/);
173
+ });
174
+ });
@@ -0,0 +1,190 @@
1
+ import * as v from "valibot";
2
+ import {
3
+ BRANCH_STATE_ENTRIES,
4
+ COMMIT_STATE_ENTRIES,
5
+ Config,
6
+ } from "../valibot-state";
7
+ import { get_commit_title_size } from "./commit-title-size";
8
+
9
+ function format_allowed_values(values: string[]): string {
10
+ const printable_values = values.map((value) =>
11
+ value === "" ? '"" (none)' : `"${value}"`,
12
+ );
13
+ return printable_values.join(", ");
14
+ }
15
+
16
+ export function create_strict_commit_state(
17
+ config: v.InferOutput<typeof Config>,
18
+ ) {
19
+ const type_values = config.commit_type.options.map((option) => option.value);
20
+ const scope_values = config.commit_scope.options.map(
21
+ (option) => option.value,
22
+ );
23
+
24
+ return v.pipe(
25
+ v.object(COMMIT_STATE_ENTRIES),
26
+ v.rawCheck(({ dataset, addIssue }) => {
27
+ if (!dataset.typed) return;
28
+
29
+ const received = dataset.value.type ? `"${dataset.value.type}"` : "(empty)";
30
+ if (dataset.value.type && !type_values.includes(dataset.value.type)) {
31
+ addIssue({
32
+ message: `Invalid --type ${received}. Valid types: ${format_allowed_values(type_values)}.`,
33
+ });
34
+ }
35
+ }),
36
+ v.rawCheck(({ dataset, addIssue }) => {
37
+ if (!dataset.typed) return;
38
+
39
+ const received = dataset.value.scope
40
+ ? `"${dataset.value.scope}"`
41
+ : "(empty)";
42
+
43
+ if (
44
+ dataset.value.scope &&
45
+ !config.commit_scope.custom_scope &&
46
+ !scope_values.includes(dataset.value.scope)
47
+ ) {
48
+ addIssue({
49
+ message: `Invalid --scope ${received}. Valid scopes: ${format_allowed_values(scope_values)}.`,
50
+ });
51
+ }
52
+ }),
53
+ v.rawCheck(({ dataset, addIssue }) => {
54
+ if (!dataset.typed || dataset.value.title.trim()) return;
55
+
56
+ addIssue({
57
+ message: "Missing --title. Provide a non-empty commit title.",
58
+ });
59
+ }),
60
+ v.rawCheck(({ dataset, addIssue }) => {
61
+ if (!dataset.typed) return;
62
+
63
+ const size = get_commit_title_size(dataset.value, {
64
+ include_ticket: config.check_ticket.add_to_title,
65
+ });
66
+
67
+ if (size > config.commit_title.max_size) {
68
+ addIssue({
69
+ message: `Title exceeds max width. Current size is ${size}, max is ${config.commit_title.max_size} (includes type, scope, and ticket when enabled).`,
70
+ });
71
+ }
72
+ }),
73
+ v.rawCheck(({ dataset, addIssue }) => {
74
+ if (
75
+ dataset.typed &&
76
+ config.commit_body.required &&
77
+ !dataset.value.body.trim()
78
+ ) {
79
+ addIssue({
80
+ message: "Missing --body. commit_body.required is enabled in config.",
81
+ });
82
+ }
83
+ }),
84
+ v.rawCheck(({ dataset, addIssue }) => {
85
+ if (dataset.typed && dataset.value.closes && !dataset.value.ticket) {
86
+ addIssue({
87
+ message:
88
+ 'Invalid footer values: --closes requires --ticket (for example: --ticket "ABC-123").',
89
+ });
90
+ }
91
+ }),
92
+ v.rawCheck(({ dataset, addIssue }) => {
93
+ if (
94
+ dataset.typed &&
95
+ dataset.value.breaking_body &&
96
+ !dataset.value.breaking_title
97
+ ) {
98
+ addIssue({
99
+ message:
100
+ "Invalid breaking change values: --breaking-body requires --breaking-title.",
101
+ });
102
+ }
103
+ }),
104
+ v.rawCheck(({ dataset, addIssue }) => {
105
+ if (
106
+ dataset.typed &&
107
+ dataset.value.deprecates_body &&
108
+ !dataset.value.deprecates_title
109
+ ) {
110
+ addIssue({
111
+ message:
112
+ "Invalid deprecation values: --deprecates-body requires --deprecates-title.",
113
+ });
114
+ }
115
+ }),
116
+ );
117
+ }
118
+
119
+ export function create_strict_branch_state(
120
+ config: v.InferOutput<typeof Config>,
121
+ ) {
122
+ const type_values = config.commit_type.options.map((option) => option.value);
123
+
124
+ return v.pipe(
125
+ v.object(BRANCH_STATE_ENTRIES),
126
+ v.rawCheck(({ dataset, addIssue }) => {
127
+ if (!dataset.typed) return;
128
+
129
+ const received = dataset.value.type ? `"${dataset.value.type}"` : "(empty)";
130
+ if (dataset.value.type && !type_values.includes(dataset.value.type)) {
131
+ addIssue({
132
+ message: `Invalid --type ${received}. Valid types: ${format_allowed_values(type_values)}.`,
133
+ });
134
+ }
135
+ }),
136
+ v.rawCheck(({ dataset, addIssue }) => {
137
+ if (!dataset.typed || dataset.value.description.trim()) return;
138
+
139
+ addIssue({
140
+ message:
141
+ "Missing --description. Provide a non-empty branch description.",
142
+ });
143
+ }),
144
+ v.rawCheck(({ dataset, addIssue }) => {
145
+ if (!dataset.typed) return;
146
+
147
+ const description = dataset.value.description.trim();
148
+ if (description.length > config.branch_description.max_length) {
149
+ addIssue({
150
+ message: `Description exceeds max length. Current length is ${description.length}, max is ${config.branch_description.max_length}.`,
151
+ });
152
+ }
153
+ }),
154
+ v.rawCheck(({ dataset, addIssue }) => {
155
+ if (
156
+ dataset.typed &&
157
+ config.branch_user.required &&
158
+ !dataset.value.user.trim()
159
+ ) {
160
+ addIssue({
161
+ message: "Missing --user. branch_user.required is enabled in config.",
162
+ });
163
+ }
164
+ }),
165
+ v.rawCheck(({ dataset, addIssue }) => {
166
+ if (
167
+ dataset.typed &&
168
+ config.branch_ticket.required &&
169
+ !dataset.value.ticket.trim()
170
+ ) {
171
+ addIssue({
172
+ message:
173
+ "Missing --ticket. branch_ticket.required is enabled in config.",
174
+ });
175
+ }
176
+ }),
177
+ v.rawCheck(({ dataset, addIssue }) => {
178
+ if (
179
+ dataset.typed &&
180
+ config.branch_version.required &&
181
+ !dataset.value.version.trim()
182
+ ) {
183
+ addIssue({
184
+ message:
185
+ "Missing --branch-version. branch_version.required is enabled in config.",
186
+ });
187
+ }
188
+ }),
189
+ );
190
+ }