uva-cli 1.0.1 → 1.2.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/bin.mjs +6 -2
- package/commands/branch.mjs +25 -27
- package/commands/commit.mjs +33 -23
- package/commands/init.mjs +54 -37
- package/commands/push.mjs +7 -6
- package/commands/start.mjs +20 -15
- package/lib/banner.mjs +2 -2
- package/lib/config.mjs +31 -4
- package/lib/git.mjs +2 -2
- package/lib/i18n.mjs +9 -0
- package/lib/locales/en.mjs +97 -0
- package/lib/locales/pt-br.mjs +102 -0
- package/package.json +1 -1
package/bin.mjs
CHANGED
|
@@ -9,11 +9,15 @@ import { runStart } from './commands/start.mjs'
|
|
|
9
9
|
|
|
10
10
|
const program = new Command()
|
|
11
11
|
|
|
12
|
-
program.name('uva').description('UVA CLI — Git workflow automation').version('1.
|
|
12
|
+
program.name('uva').description('UVA CLI — Git workflow automation').version('1.1.0')
|
|
13
13
|
|
|
14
14
|
program.command('start').description('Show all available options interactively').action(runStart)
|
|
15
15
|
|
|
16
|
-
program
|
|
16
|
+
program
|
|
17
|
+
.command('init')
|
|
18
|
+
.description('Set up UVA CLI for this project')
|
|
19
|
+
.option('--global', 'save as global config (~/.config/uva/config.json)')
|
|
20
|
+
.action(runInit)
|
|
17
21
|
|
|
18
22
|
program
|
|
19
23
|
.command('commit')
|
package/commands/branch.mjs
CHANGED
|
@@ -4,20 +4,20 @@ import { hasUncommittedChanges, checkout, pull, createBranch } from '../lib/git.
|
|
|
4
4
|
import { COMMIT_TYPES } from '../lib/types.mjs'
|
|
5
5
|
import { requireConfig } from '../lib/config.mjs'
|
|
6
6
|
import { buildBranchName } from '../lib/format.mjs'
|
|
7
|
+
import { getLocale } from '../lib/i18n.mjs'
|
|
7
8
|
|
|
8
9
|
// Called by commander as runBranch(options, command)
|
|
9
10
|
export async function runBranch(opts = {}) {
|
|
10
11
|
bannerIntro('branch')
|
|
11
12
|
|
|
12
13
|
const config = requireConfig()
|
|
14
|
+
const t = getLocale(config)
|
|
13
15
|
|
|
14
16
|
if (hasUncommittedChanges()) {
|
|
15
|
-
const proceed = await confirm({
|
|
16
|
-
message: 'You have uncommitted changes. They will carry over to the new branch. Continue?',
|
|
17
|
-
})
|
|
17
|
+
const proceed = await confirm({ message: t.branch.uncommittedConfirm })
|
|
18
18
|
if (isCancel(proceed) || !proceed) {
|
|
19
|
-
log.info(
|
|
20
|
-
bannerCancelled()
|
|
19
|
+
log.info(t.branch.uncommittedTip)
|
|
20
|
+
bannerCancelled(t.common.cancelled)
|
|
21
21
|
process.exit(0)
|
|
22
22
|
}
|
|
23
23
|
}
|
|
@@ -26,16 +26,16 @@ export async function runBranch(opts = {}) {
|
|
|
26
26
|
let source
|
|
27
27
|
if (opts.source) {
|
|
28
28
|
if (!config.branch.sources.includes(opts.source)) {
|
|
29
|
-
log.warn(
|
|
29
|
+
log.warn(t.branch.sourceWarn(opts.source))
|
|
30
30
|
}
|
|
31
31
|
source = opts.source
|
|
32
32
|
} else {
|
|
33
33
|
source = await select({
|
|
34
|
-
message:
|
|
34
|
+
message: t.branch.source,
|
|
35
35
|
options: config.branch.sources.map((b) => ({ value: b, label: b })),
|
|
36
36
|
})
|
|
37
37
|
if (isCancel(source)) {
|
|
38
|
-
bannerCancelled()
|
|
38
|
+
bannerCancelled(t.common.cancelled)
|
|
39
39
|
process.exit(0)
|
|
40
40
|
}
|
|
41
41
|
}
|
|
@@ -47,12 +47,12 @@ export async function runBranch(opts = {}) {
|
|
|
47
47
|
ticket = opts.ticket
|
|
48
48
|
} else {
|
|
49
49
|
const input = await text({
|
|
50
|
-
message:
|
|
50
|
+
message: t.branch.ticket,
|
|
51
51
|
placeholder: config.commit.ticketPlaceholder,
|
|
52
|
-
validate: (v) => (v.trim() ? undefined :
|
|
52
|
+
validate: (v) => (v.trim() ? undefined : t.branch.ticketError),
|
|
53
53
|
})
|
|
54
54
|
if (isCancel(input)) {
|
|
55
|
-
bannerCancelled()
|
|
55
|
+
bannerCancelled(t.common.cancelled)
|
|
56
56
|
process.exit(0)
|
|
57
57
|
}
|
|
58
58
|
ticket = input.trim()
|
|
@@ -64,14 +64,14 @@ export async function runBranch(opts = {}) {
|
|
|
64
64
|
if (opts.type) {
|
|
65
65
|
const valid = COMMIT_TYPES.map((t) => t.value)
|
|
66
66
|
if (!valid.includes(opts.type)) {
|
|
67
|
-
log.error(
|
|
67
|
+
log.error(t.branch.invalidType(opts.type, valid.join(', ')))
|
|
68
68
|
process.exit(1)
|
|
69
69
|
}
|
|
70
70
|
type = opts.type
|
|
71
71
|
} else {
|
|
72
|
-
type = await select({ message:
|
|
72
|
+
type = await select({ message: t.branch.type, options: COMMIT_TYPES })
|
|
73
73
|
if (isCancel(type)) {
|
|
74
|
-
bannerCancelled()
|
|
74
|
+
bannerCancelled(t.common.cancelled)
|
|
75
75
|
process.exit(0)
|
|
76
76
|
}
|
|
77
77
|
}
|
|
@@ -82,12 +82,12 @@ export async function runBranch(opts = {}) {
|
|
|
82
82
|
taskName = opts.name
|
|
83
83
|
} else {
|
|
84
84
|
const input = await text({
|
|
85
|
-
message:
|
|
86
|
-
placeholder:
|
|
87
|
-
validate: (v) => (v.trim() ? undefined :
|
|
85
|
+
message: t.branch.name,
|
|
86
|
+
placeholder: t.branch.namePlaceholder,
|
|
87
|
+
validate: (v) => (v.trim() ? undefined : t.branch.nameError),
|
|
88
88
|
})
|
|
89
89
|
if (isCancel(input)) {
|
|
90
|
-
bannerCancelled()
|
|
90
|
+
bannerCancelled(t.common.cancelled)
|
|
91
91
|
process.exit(0)
|
|
92
92
|
}
|
|
93
93
|
taskName = input.trim()
|
|
@@ -100,9 +100,9 @@ export async function runBranch(opts = {}) {
|
|
|
100
100
|
const scripted = opts.source && opts.type && opts.name && ticketDone
|
|
101
101
|
|
|
102
102
|
if (!scripted) {
|
|
103
|
-
const confirmed = await confirm({ message:
|
|
103
|
+
const confirmed = await confirm({ message: t.branch.confirm(branchName) })
|
|
104
104
|
if (isCancel(confirmed) || !confirmed) {
|
|
105
|
-
bannerCancelled()
|
|
105
|
+
bannerCancelled(t.common.cancelled)
|
|
106
106
|
process.exit(0)
|
|
107
107
|
}
|
|
108
108
|
}
|
|
@@ -110,16 +110,14 @@ export async function runBranch(opts = {}) {
|
|
|
110
110
|
try {
|
|
111
111
|
checkout(source)
|
|
112
112
|
} catch {
|
|
113
|
-
log.error(
|
|
114
|
-
`Could not switch to ${source}. Make sure the branch exists and there are no conflicts.`,
|
|
115
|
-
)
|
|
113
|
+
log.error(t.branch.checkoutError(source))
|
|
116
114
|
process.exit(1)
|
|
117
115
|
}
|
|
118
116
|
|
|
119
117
|
try {
|
|
120
118
|
pull()
|
|
121
119
|
} catch {
|
|
122
|
-
log.error(
|
|
120
|
+
log.error(t.branch.pullError)
|
|
123
121
|
process.exit(1)
|
|
124
122
|
}
|
|
125
123
|
|
|
@@ -127,12 +125,12 @@ export async function runBranch(opts = {}) {
|
|
|
127
125
|
createBranch(branchName)
|
|
128
126
|
} catch (err) {
|
|
129
127
|
if (err.stderr?.includes('already exists') || err.message?.includes('already exists')) {
|
|
130
|
-
log.error(
|
|
128
|
+
log.error(t.branch.branchExists(branchName))
|
|
131
129
|
} else {
|
|
132
|
-
log.error(
|
|
130
|
+
log.error(t.branch.createError)
|
|
133
131
|
}
|
|
134
132
|
process.exit(1)
|
|
135
133
|
}
|
|
136
134
|
|
|
137
|
-
bannerOutro(
|
|
135
|
+
bannerOutro(t.branch.done(branchName))
|
|
138
136
|
}
|
package/commands/commit.mjs
CHANGED
|
@@ -4,16 +4,18 @@ import { getChangedFiles, addFiles, commit } from '../lib/git.mjs'
|
|
|
4
4
|
import { COMMIT_TYPES } from '../lib/types.mjs'
|
|
5
5
|
import { requireConfig } from '../lib/config.mjs'
|
|
6
6
|
import { buildCommitMessage } from '../lib/format.mjs'
|
|
7
|
+
import { getLocale } from '../lib/i18n.mjs'
|
|
7
8
|
|
|
8
9
|
// Called by commander as runCommit(options, command)
|
|
9
10
|
export async function runCommit(opts = {}) {
|
|
10
11
|
bannerIntro('commit')
|
|
11
12
|
|
|
12
13
|
const config = requireConfig()
|
|
14
|
+
const t = getLocale(config)
|
|
13
15
|
const files = getChangedFiles()
|
|
14
16
|
|
|
15
17
|
if (files.length === 0) {
|
|
16
|
-
log.info(
|
|
18
|
+
log.info(t.commit.nothingToCommit)
|
|
17
19
|
process.exit(0)
|
|
18
20
|
}
|
|
19
21
|
|
|
@@ -22,14 +24,14 @@ export async function runCommit(opts = {}) {
|
|
|
22
24
|
if (opts.type) {
|
|
23
25
|
const valid = COMMIT_TYPES.map((t) => t.value)
|
|
24
26
|
if (!valid.includes(opts.type)) {
|
|
25
|
-
log.error(
|
|
27
|
+
log.error(t.commit.invalidType(opts.type, valid.join(', ')))
|
|
26
28
|
process.exit(1)
|
|
27
29
|
}
|
|
28
30
|
type = opts.type
|
|
29
31
|
} else {
|
|
30
|
-
type = await select({ message:
|
|
32
|
+
type = await select({ message: t.commit.type, options: COMMIT_TYPES })
|
|
31
33
|
if (isCancel(type)) {
|
|
32
|
-
bannerCancelled()
|
|
34
|
+
bannerCancelled(t.common.cancelled)
|
|
33
35
|
process.exit(0)
|
|
34
36
|
}
|
|
35
37
|
}
|
|
@@ -41,12 +43,12 @@ export async function runCommit(opts = {}) {
|
|
|
41
43
|
ticket = opts.ticket
|
|
42
44
|
} else {
|
|
43
45
|
const input = await text({
|
|
44
|
-
message:
|
|
46
|
+
message: t.commit.ticket,
|
|
45
47
|
placeholder: config.commit.ticketPlaceholder,
|
|
46
|
-
validate: (v) => (v.trim() ? undefined :
|
|
48
|
+
validate: (v) => (v.trim() ? undefined : t.commit.ticketError),
|
|
47
49
|
})
|
|
48
50
|
if (isCancel(input)) {
|
|
49
|
-
bannerCancelled()
|
|
51
|
+
bannerCancelled(t.common.cancelled)
|
|
50
52
|
process.exit(0)
|
|
51
53
|
}
|
|
52
54
|
ticket = input.trim()
|
|
@@ -64,21 +66,19 @@ export async function runCommit(opts = {}) {
|
|
|
64
66
|
message = opts.message.trim().toLowerCase()
|
|
65
67
|
} else {
|
|
66
68
|
const input = await text({
|
|
67
|
-
message:
|
|
68
|
-
placeholder:
|
|
69
|
-
validate: (v) => (v.trim() ? undefined :
|
|
69
|
+
message: t.commit.message,
|
|
70
|
+
placeholder: t.commit.messagePlaceholder,
|
|
71
|
+
validate: (v) => (v.trim() ? undefined : t.commit.messageError),
|
|
70
72
|
})
|
|
71
73
|
if (isCancel(input)) {
|
|
72
|
-
bannerCancelled()
|
|
74
|
+
bannerCancelled(t.common.cancelled)
|
|
73
75
|
process.exit(0)
|
|
74
76
|
}
|
|
75
77
|
message = input.trim().toLowerCase()
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
if (message.length > 72) {
|
|
79
|
-
log.warn(
|
|
80
|
-
'Message is long (over 72 characters). Shorter messages are recommended, but you can continue.',
|
|
81
|
-
)
|
|
81
|
+
log.warn(t.commit.messageLong)
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
// Files
|
|
@@ -92,20 +92,30 @@ export async function runCommit(opts = {}) {
|
|
|
92
92
|
const availablePaths = files.map((f) => f.path)
|
|
93
93
|
const invalid = paths.filter((p) => !availablePaths.includes(p))
|
|
94
94
|
if (invalid.length) {
|
|
95
|
-
log.error(
|
|
95
|
+
log.error(t.commit.unknownFiles(invalid.join(', '), availablePaths.join(', ')))
|
|
96
96
|
process.exit(1)
|
|
97
97
|
}
|
|
98
98
|
selected = paths
|
|
99
99
|
} else {
|
|
100
|
+
const fileOptions = files.map((f) => ({
|
|
101
|
+
value: f.path,
|
|
102
|
+
label: `${f.status.padEnd(2)} ${f.path}`,
|
|
103
|
+
}))
|
|
104
|
+
if (files.length >= 5) {
|
|
105
|
+
fileOptions.unshift({ value: '__all__', label: t.commit.allFiles })
|
|
106
|
+
}
|
|
100
107
|
selected = await multiselect({
|
|
101
|
-
message:
|
|
102
|
-
options:
|
|
108
|
+
message: t.commit.files,
|
|
109
|
+
options: fileOptions,
|
|
103
110
|
required: true,
|
|
104
111
|
})
|
|
105
112
|
if (isCancel(selected)) {
|
|
106
|
-
bannerCancelled()
|
|
113
|
+
bannerCancelled(t.common.cancelled)
|
|
107
114
|
process.exit(0)
|
|
108
115
|
}
|
|
116
|
+
if (selected.includes('__all__')) {
|
|
117
|
+
selected = files.map((f) => f.path)
|
|
118
|
+
}
|
|
109
119
|
}
|
|
110
120
|
|
|
111
121
|
finalMessage = buildCommitMessage(config.commit.format, { type, ticket, message })
|
|
@@ -114,23 +124,23 @@ export async function runCommit(opts = {}) {
|
|
|
114
124
|
const scripted = opts.type && opts.message && (opts.all || opts.files)
|
|
115
125
|
if (scripted) break
|
|
116
126
|
|
|
117
|
-
const confirmed = await confirm({ message:
|
|
127
|
+
const confirmed = await confirm({ message: t.commit.confirm(finalMessage) })
|
|
118
128
|
if (isCancel(confirmed)) {
|
|
119
|
-
bannerCancelled()
|
|
129
|
+
bannerCancelled(t.common.cancelled)
|
|
120
130
|
process.exit(0)
|
|
121
131
|
}
|
|
122
132
|
if (confirmed) break
|
|
123
133
|
|
|
124
134
|
if (opts.message) break // message is fixed, can't retry
|
|
125
|
-
log.info(
|
|
135
|
+
log.info(t.commit.retry)
|
|
126
136
|
}
|
|
127
137
|
|
|
128
138
|
try {
|
|
129
139
|
addFiles(selected)
|
|
130
140
|
commit(finalMessage)
|
|
131
|
-
bannerOutro(
|
|
141
|
+
bannerOutro(t.commit.done(finalMessage))
|
|
132
142
|
} catch (e) {
|
|
133
|
-
log.error(
|
|
143
|
+
log.error(t.commit.failed(e.message))
|
|
134
144
|
process.exit(1)
|
|
135
145
|
}
|
|
136
146
|
}
|
package/commands/init.mjs
CHANGED
|
@@ -1,37 +1,54 @@
|
|
|
1
|
-
import { text, select, confirm, isCancel } from '@clack/prompts'
|
|
1
|
+
import { text, select, confirm, isCancel, log } from '@clack/prompts'
|
|
2
2
|
import { bannerIntro, bannerOutro, bannerCancelled } from '../lib/banner.mjs'
|
|
3
|
-
import { loadConfig, saveConfig } from '../lib/config.mjs'
|
|
3
|
+
import { loadConfig, loadGlobalConfig, saveConfig, saveGlobalConfig } from '../lib/config.mjs'
|
|
4
4
|
import { COMMIT_FORMATS, BRANCH_FORMATS } from '../lib/types.mjs'
|
|
5
|
+
import { getLocale } from '../lib/i18n.mjs'
|
|
5
6
|
|
|
6
|
-
export async function runInit() {
|
|
7
|
+
export async function runInit(opts = {}) {
|
|
8
|
+
const isGlobal = Boolean(opts.global)
|
|
7
9
|
bannerIntro('init')
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
// Language is always the first question — no config exists yet
|
|
12
|
+
const lang = await select({
|
|
13
|
+
message: 'Language / Idioma',
|
|
14
|
+
options: [
|
|
15
|
+
{ value: 'en', label: 'English' },
|
|
16
|
+
{ value: 'pt-br', label: 'Português (BR)' },
|
|
17
|
+
],
|
|
18
|
+
})
|
|
19
|
+
if (isCancel(lang)) {
|
|
20
|
+
bannerCancelled()
|
|
21
|
+
process.exit(0)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const t = getLocale({ project: { lang } })
|
|
25
|
+
|
|
26
|
+
if (isGlobal) {
|
|
27
|
+
log.info(t.init.globalMode)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const existing = isGlobal ? loadGlobalConfig() : loadConfig()
|
|
10
31
|
if (existing) {
|
|
11
|
-
const overwrite = await confirm({
|
|
12
|
-
message: 'A configuration already exists. Do you want to overwrite it?',
|
|
13
|
-
})
|
|
32
|
+
const overwrite = await confirm({ message: t.init.overwriteConfirm })
|
|
14
33
|
if (isCancel(overwrite) || !overwrite) {
|
|
15
|
-
bannerCancelled()
|
|
34
|
+
bannerCancelled(t.common.cancelled)
|
|
16
35
|
process.exit(0)
|
|
17
36
|
}
|
|
18
37
|
}
|
|
19
38
|
|
|
20
39
|
const projectName = await text({
|
|
21
|
-
message:
|
|
22
|
-
placeholder:
|
|
23
|
-
validate: (v) => (v.trim() ? undefined :
|
|
40
|
+
message: t.init.projectName,
|
|
41
|
+
placeholder: t.init.projectNamePlaceholder,
|
|
42
|
+
validate: (v) => (v.trim() ? undefined : t.init.projectNameError),
|
|
24
43
|
})
|
|
25
44
|
if (isCancel(projectName)) {
|
|
26
|
-
bannerCancelled()
|
|
45
|
+
bannerCancelled(t.common.cancelled)
|
|
27
46
|
process.exit(0)
|
|
28
47
|
}
|
|
29
48
|
|
|
30
|
-
const useTicket = await confirm({
|
|
31
|
-
message: 'Do you use a ticket/issue tracker? (e.g., Jira, Linear, GitHub Issues)',
|
|
32
|
-
})
|
|
49
|
+
const useTicket = await confirm({ message: t.init.ticketConfirm })
|
|
33
50
|
if (isCancel(useTicket)) {
|
|
34
|
-
bannerCancelled()
|
|
51
|
+
bannerCancelled(t.common.cancelled)
|
|
35
52
|
process.exit(0)
|
|
36
53
|
}
|
|
37
54
|
|
|
@@ -40,12 +57,12 @@ export async function runInit() {
|
|
|
40
57
|
|
|
41
58
|
if (useTicket) {
|
|
42
59
|
const prefix = await text({
|
|
43
|
-
message:
|
|
44
|
-
placeholder:
|
|
45
|
-
validate: (v) => (v.trim() ? undefined :
|
|
60
|
+
message: t.init.ticketPrefix,
|
|
61
|
+
placeholder: t.init.ticketPrefixPlaceholder,
|
|
62
|
+
validate: (v) => (v.trim() ? undefined : t.init.ticketPrefixError),
|
|
46
63
|
})
|
|
47
64
|
if (isCancel(prefix)) {
|
|
48
|
-
bannerCancelled()
|
|
65
|
+
bannerCancelled(t.common.cancelled)
|
|
49
66
|
process.exit(0)
|
|
50
67
|
}
|
|
51
68
|
ticketPrefix = prefix.trim().toUpperCase()
|
|
@@ -55,33 +72,33 @@ export async function runInit() {
|
|
|
55
72
|
let commitFormat = 'conventional'
|
|
56
73
|
if (useTicket) {
|
|
57
74
|
const selectedCommitFormat = await select({
|
|
58
|
-
message:
|
|
75
|
+
message: t.init.commitFormat,
|
|
59
76
|
options: COMMIT_FORMATS.map((f) => ({
|
|
60
77
|
...f,
|
|
61
78
|
label: f.label.replace(/PROJ/g, ticketPrefix || 'PROJ'),
|
|
62
79
|
})),
|
|
63
80
|
})
|
|
64
81
|
if (isCancel(selectedCommitFormat)) {
|
|
65
|
-
bannerCancelled()
|
|
82
|
+
bannerCancelled(t.common.cancelled)
|
|
66
83
|
process.exit(0)
|
|
67
84
|
}
|
|
68
85
|
commitFormat = selectedCommitFormat
|
|
69
86
|
}
|
|
70
87
|
|
|
71
88
|
const sourcesInput = await text({
|
|
72
|
-
message:
|
|
73
|
-
placeholder:
|
|
89
|
+
message: t.init.sources,
|
|
90
|
+
placeholder: t.init.sourcesPlaceholder,
|
|
74
91
|
initialValue: 'main,develop',
|
|
75
92
|
validate: (v) => {
|
|
76
93
|
const parts = v
|
|
77
94
|
.split(',')
|
|
78
95
|
.map((s) => s.trim())
|
|
79
96
|
.filter(Boolean)
|
|
80
|
-
return parts.length > 0 ? undefined :
|
|
97
|
+
return parts.length > 0 ? undefined : t.init.sourcesError
|
|
81
98
|
},
|
|
82
99
|
})
|
|
83
100
|
if (isCancel(sourcesInput)) {
|
|
84
|
-
bannerCancelled()
|
|
101
|
+
bannerCancelled(t.common.cancelled)
|
|
85
102
|
process.exit(0)
|
|
86
103
|
}
|
|
87
104
|
const sources = sourcesInput
|
|
@@ -92,44 +109,44 @@ export async function runInit() {
|
|
|
92
109
|
let branchFormat = 'type-name'
|
|
93
110
|
if (useTicket) {
|
|
94
111
|
const selectedBranchFormat = await select({
|
|
95
|
-
message:
|
|
112
|
+
message: t.init.branchFormat,
|
|
96
113
|
options: BRANCH_FORMATS.map((f) => ({
|
|
97
114
|
...f,
|
|
98
115
|
label: f.label.replace(/PROJ/g, ticketPrefix || 'PROJ'),
|
|
99
116
|
})),
|
|
100
117
|
})
|
|
101
118
|
if (isCancel(selectedBranchFormat)) {
|
|
102
|
-
bannerCancelled()
|
|
119
|
+
bannerCancelled(t.common.cancelled)
|
|
103
120
|
process.exit(0)
|
|
104
121
|
}
|
|
105
122
|
branchFormat = selectedBranchFormat
|
|
106
123
|
}
|
|
107
124
|
|
|
108
125
|
const useArea = await confirm({
|
|
109
|
-
message:
|
|
126
|
+
message: t.init.areaConfirm,
|
|
110
127
|
initialValue: false,
|
|
111
128
|
})
|
|
112
129
|
if (isCancel(useArea)) {
|
|
113
|
-
bannerCancelled()
|
|
130
|
+
bannerCancelled(t.common.cancelled)
|
|
114
131
|
process.exit(0)
|
|
115
132
|
}
|
|
116
133
|
|
|
117
134
|
let areas = []
|
|
118
135
|
if (useArea) {
|
|
119
136
|
const areasInput = await text({
|
|
120
|
-
message:
|
|
121
|
-
placeholder:
|
|
137
|
+
message: t.init.areaLabels,
|
|
138
|
+
placeholder: t.init.areaLabelsPlaceholder,
|
|
122
139
|
initialValue: 'FE,BE,DOC',
|
|
123
140
|
validate: (v) => {
|
|
124
141
|
const parts = v
|
|
125
142
|
.split(',')
|
|
126
143
|
.map((s) => s.trim())
|
|
127
144
|
.filter(Boolean)
|
|
128
|
-
return parts.length > 0 ? undefined :
|
|
145
|
+
return parts.length > 0 ? undefined : t.init.areaLabelsError
|
|
129
146
|
},
|
|
130
147
|
})
|
|
131
148
|
if (isCancel(areasInput)) {
|
|
132
|
-
bannerCancelled()
|
|
149
|
+
bannerCancelled(t.common.cancelled)
|
|
133
150
|
process.exit(0)
|
|
134
151
|
}
|
|
135
152
|
areas = areasInput
|
|
@@ -139,7 +156,7 @@ export async function runInit() {
|
|
|
139
156
|
}
|
|
140
157
|
|
|
141
158
|
const config = {
|
|
142
|
-
project: { name: projectName.trim() },
|
|
159
|
+
project: { name: projectName.trim(), lang },
|
|
143
160
|
commit: {
|
|
144
161
|
ticketEnabled: Boolean(useTicket),
|
|
145
162
|
ticketPrefix,
|
|
@@ -155,6 +172,6 @@ export async function runInit() {
|
|
|
155
172
|
},
|
|
156
173
|
}
|
|
157
174
|
|
|
158
|
-
const configPath = saveConfig(config)
|
|
159
|
-
bannerOutro(
|
|
175
|
+
const configPath = isGlobal ? saveGlobalConfig(config) : saveConfig(config)
|
|
176
|
+
bannerOutro(t.init.saved(configPath))
|
|
160
177
|
}
|
package/commands/push.mjs
CHANGED
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
import { confirm, isCancel, log } from '@clack/prompts'
|
|
2
2
|
import { bannerIntro, bannerOutro, bannerCancelled } from '../lib/banner.mjs'
|
|
3
3
|
import { getCurrentBranch } from '../lib/git.mjs'
|
|
4
|
+
import { loadConfig } from '../lib/config.mjs'
|
|
5
|
+
import { getLocale } from '../lib/i18n.mjs'
|
|
4
6
|
import { spawnSync } from 'child_process'
|
|
5
7
|
|
|
6
8
|
// Called by commander as runPush(options, command)
|
|
7
9
|
export async function runPush(opts = {}) {
|
|
8
10
|
bannerIntro('push')
|
|
9
11
|
|
|
12
|
+
const t = getLocale(loadConfig())
|
|
10
13
|
const branch = getCurrentBranch()
|
|
11
14
|
|
|
12
15
|
if (!opts.yes) {
|
|
13
|
-
const confirmed = await confirm({
|
|
14
|
-
message: `Push current branch: ${branch}?`,
|
|
15
|
-
})
|
|
16
|
+
const confirmed = await confirm({ message: t.push.confirm(branch) })
|
|
16
17
|
if (isCancel(confirmed) || !confirmed) {
|
|
17
|
-
bannerCancelled()
|
|
18
|
+
bannerCancelled(t.common.cancelled)
|
|
18
19
|
process.exit(0)
|
|
19
20
|
}
|
|
20
21
|
}
|
|
@@ -23,9 +24,9 @@ export async function runPush(opts = {}) {
|
|
|
23
24
|
stdio: ['pipe', 'inherit', 'inherit'],
|
|
24
25
|
})
|
|
25
26
|
if (result.status !== 0) {
|
|
26
|
-
log.error(
|
|
27
|
+
log.error(t.push.failed)
|
|
27
28
|
process.exit(1)
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
bannerOutro(
|
|
31
|
+
bannerOutro(t.push.done(branch))
|
|
31
32
|
}
|
package/commands/start.mjs
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { select, isCancel, intro, outro } from '@clack/prompts'
|
|
2
2
|
import pc from 'picocolors'
|
|
3
3
|
import { banner as brandBanner, uva, folha } from '../lib/colors.mjs'
|
|
4
|
+
import { loadConfig } from '../lib/config.mjs'
|
|
5
|
+
import { getLocale } from '../lib/i18n.mjs'
|
|
4
6
|
import { runInit } from './init.mjs'
|
|
5
7
|
import { runCommit } from './commit.mjs'
|
|
6
8
|
import { runBranch } from './branch.mjs'
|
|
@@ -8,48 +10,51 @@ import { runNewFile } from './new-file.mjs'
|
|
|
8
10
|
import { runPush } from './push.mjs'
|
|
9
11
|
|
|
10
12
|
export async function runStart() {
|
|
13
|
+
const t = getLocale(loadConfig())
|
|
14
|
+
|
|
11
15
|
intro(brandBanner('UVA CLI'))
|
|
12
16
|
|
|
13
17
|
console.log('')
|
|
14
|
-
console.log(uva(' uva-cli') + pc.dim(
|
|
18
|
+
console.log(uva(' uva-cli') + pc.dim(` ${t.start.tagline}`))
|
|
15
19
|
console.log('')
|
|
16
|
-
console.log(pc.dim(
|
|
17
|
-
console.log(pc.dim(
|
|
20
|
+
console.log(pc.dim(` ${t.start.desc1}`))
|
|
21
|
+
console.log(pc.dim(` ${t.start.desc2}`))
|
|
18
22
|
console.log('')
|
|
19
23
|
|
|
24
|
+
const o = t.start.options
|
|
20
25
|
const action = await select({
|
|
21
|
-
message:
|
|
26
|
+
message: t.start.prompt,
|
|
22
27
|
options: [
|
|
23
28
|
{
|
|
24
29
|
value: 'init',
|
|
25
|
-
label: folha('uva init') + '
|
|
26
|
-
hint:
|
|
30
|
+
label: folha('uva init') + ' ' + o.init.label,
|
|
31
|
+
hint: o.init.hint,
|
|
27
32
|
},
|
|
28
33
|
{
|
|
29
34
|
value: 'commit',
|
|
30
|
-
label: uva('uva commit') + '
|
|
31
|
-
hint:
|
|
35
|
+
label: uva('uva commit') + ' ' + o.commit.label,
|
|
36
|
+
hint: o.commit.hint,
|
|
32
37
|
},
|
|
33
38
|
{
|
|
34
39
|
value: 'branch',
|
|
35
|
-
label: uva('uva branch') + '
|
|
36
|
-
hint:
|
|
40
|
+
label: uva('uva branch') + ' ' + o.branch.label,
|
|
41
|
+
hint: o.branch.hint,
|
|
37
42
|
},
|
|
38
43
|
{
|
|
39
44
|
value: 'new-file',
|
|
40
|
-
label: uva('uva new-file') + '
|
|
41
|
-
hint:
|
|
45
|
+
label: uva('uva new-file') + ' ' + o.newFile.label,
|
|
46
|
+
hint: o.newFile.hint,
|
|
42
47
|
},
|
|
43
48
|
{
|
|
44
49
|
value: 'push',
|
|
45
|
-
label: uva('uva push') + '
|
|
46
|
-
hint:
|
|
50
|
+
label: uva('uva push') + ' ' + o.push.label,
|
|
51
|
+
hint: o.push.hint,
|
|
47
52
|
},
|
|
48
53
|
],
|
|
49
54
|
})
|
|
50
55
|
|
|
51
56
|
if (isCancel(action)) {
|
|
52
|
-
outro(pc.dim(
|
|
57
|
+
outro(pc.dim(t.common.cancelled))
|
|
53
58
|
process.exit(0)
|
|
54
59
|
}
|
|
55
60
|
|
package/lib/banner.mjs
CHANGED
package/lib/config.mjs
CHANGED
|
@@ -1,15 +1,34 @@
|
|
|
1
|
-
import { existsSync, readFileSync, writeFileSync } from 'fs'
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs'
|
|
2
2
|
import { join } from 'path'
|
|
3
|
+
import { homedir } from 'os'
|
|
3
4
|
import { log } from '@clack/prompts'
|
|
4
5
|
import { getGitRoot } from './git.mjs'
|
|
5
6
|
|
|
6
7
|
function getConfigPath() {
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
try {
|
|
9
|
+
const root = getGitRoot()
|
|
10
|
+
return join(root, 'uva.config.json')
|
|
11
|
+
} catch {
|
|
12
|
+
return null
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function getGlobalConfigPath() {
|
|
17
|
+
return join(homedir(), '.config', 'uva', 'config.json')
|
|
9
18
|
}
|
|
10
19
|
|
|
11
20
|
export function loadConfig() {
|
|
12
21
|
const path = getConfigPath()
|
|
22
|
+
if (!path || !existsSync(path)) return null
|
|
23
|
+
try {
|
|
24
|
+
return JSON.parse(readFileSync(path, { encoding: 'utf-8' }))
|
|
25
|
+
} catch {
|
|
26
|
+
return null
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function loadGlobalConfig() {
|
|
31
|
+
const path = getGlobalConfigPath()
|
|
13
32
|
if (!existsSync(path)) return null
|
|
14
33
|
try {
|
|
15
34
|
return JSON.parse(readFileSync(path, { encoding: 'utf-8' }))
|
|
@@ -24,8 +43,16 @@ export function saveConfig(config) {
|
|
|
24
43
|
return path
|
|
25
44
|
}
|
|
26
45
|
|
|
46
|
+
export function saveGlobalConfig(config) {
|
|
47
|
+
const dir = join(homedir(), '.config', 'uva')
|
|
48
|
+
const path = join(dir, 'config.json')
|
|
49
|
+
mkdirSync(dir, { recursive: true })
|
|
50
|
+
writeFileSync(path, JSON.stringify(config, null, 2) + '\n', { encoding: 'utf-8' })
|
|
51
|
+
return path
|
|
52
|
+
}
|
|
53
|
+
|
|
27
54
|
export function requireConfig() {
|
|
28
|
-
const config = loadConfig()
|
|
55
|
+
const config = loadConfig() ?? loadGlobalConfig()
|
|
29
56
|
if (!config) {
|
|
30
57
|
log.error('No configuration found. Run `uva init` to set up your project.')
|
|
31
58
|
process.exit(1)
|
package/lib/git.mjs
CHANGED
|
@@ -51,7 +51,7 @@ export function addFiles(paths) {
|
|
|
51
51
|
stdio: 'pipe',
|
|
52
52
|
})
|
|
53
53
|
if (result.status !== 0) {
|
|
54
|
-
throw new Error(result.stderr || 'git add
|
|
54
|
+
throw new Error(result.stderr || 'git add failed')
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
|
|
@@ -62,6 +62,6 @@ export function commit(message) {
|
|
|
62
62
|
stdio: ['pipe', 'inherit', 'inherit'],
|
|
63
63
|
})
|
|
64
64
|
if (result.status !== 0) {
|
|
65
|
-
throw new Error('git commit
|
|
65
|
+
throw new Error('git commit failed — see output above')
|
|
66
66
|
}
|
|
67
67
|
}
|
package/lib/i18n.mjs
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
init: {
|
|
3
|
+
langSelect: 'Language / Idioma',
|
|
4
|
+
globalMode: 'Global configuration — applies to all projects without a local config',
|
|
5
|
+
overwriteConfirm: 'A configuration already exists. Do you want to overwrite it?',
|
|
6
|
+
projectName: 'Project name',
|
|
7
|
+
projectNamePlaceholder: 'My Awesome Project',
|
|
8
|
+
projectNameError: 'Project name cannot be empty.',
|
|
9
|
+
ticketConfirm: 'Do you use a ticket/issue tracker? (e.g., Jira, Linear, GitHub Issues)',
|
|
10
|
+
ticketPrefix: 'Ticket prefix',
|
|
11
|
+
ticketPrefixPlaceholder: 'PROJ',
|
|
12
|
+
ticketPrefixError: 'Ticket prefix cannot be empty.',
|
|
13
|
+
commitFormat: 'Choose a commit message format',
|
|
14
|
+
sources: 'Branches to branch from (comma-separated)',
|
|
15
|
+
sourcesPlaceholder: 'main,develop',
|
|
16
|
+
sourcesError: 'At least one branch is required.',
|
|
17
|
+
branchFormat: 'Choose a branch naming format',
|
|
18
|
+
areaConfirm: 'Do you want to categorize branches by area? (e.g., FE, BE, DOC)',
|
|
19
|
+
areaLabels: 'Area labels (comma-separated)',
|
|
20
|
+
areaLabelsPlaceholder: 'FE,BE,DOC',
|
|
21
|
+
areaLabelsError: 'At least one area is required.',
|
|
22
|
+
saved: (path) => `Configuration saved to ${path}`,
|
|
23
|
+
},
|
|
24
|
+
commit: {
|
|
25
|
+
nothingToCommit: 'Nothing to commit here.',
|
|
26
|
+
invalidType: (type, valid) => `Invalid --type "${type}". Valid values: ${valid}`,
|
|
27
|
+
unknownFiles: (invalid, available) => `Unknown file(s): ${invalid}\nAvailable: ${available}`,
|
|
28
|
+
type: 'Commit type',
|
|
29
|
+
ticket: 'Ticket',
|
|
30
|
+
ticketError: 'Ticket cannot be empty.',
|
|
31
|
+
message: 'Commit message',
|
|
32
|
+
messagePlaceholder: 'add login screen',
|
|
33
|
+
messageError: 'Message cannot be empty.',
|
|
34
|
+
messageLong:
|
|
35
|
+
'Message is long (over 72 characters). Shorter messages are recommended, but you can continue.',
|
|
36
|
+
files: 'Which files to include in the commit?',
|
|
37
|
+
allFiles: 'All files',
|
|
38
|
+
confirm: (msg) => `Commit with message:\n ${msg}`,
|
|
39
|
+
retry: "OK! Let's rewrite the message.",
|
|
40
|
+
failed: (err) => `Commit failed: ${err}`,
|
|
41
|
+
done: (msg) => `Committed: ${msg}`,
|
|
42
|
+
},
|
|
43
|
+
branch: {
|
|
44
|
+
uncommittedConfirm:
|
|
45
|
+
'You have uncommitted changes. They will carry over to the new branch. Continue?',
|
|
46
|
+
uncommittedTip: 'Tip: run `uva commit` first to commit pending changes.',
|
|
47
|
+
source: 'Branch from',
|
|
48
|
+
sourceWarn: (src) => `"${src}" is not in the configured source branches. Proceeding anyway.`,
|
|
49
|
+
ticket: 'Ticket',
|
|
50
|
+
ticketError: 'Ticket cannot be empty.',
|
|
51
|
+
type: 'Branch type',
|
|
52
|
+
invalidType: (type, valid) => `Invalid --type "${type}". Valid values: ${valid}`,
|
|
53
|
+
name: 'Task name',
|
|
54
|
+
namePlaceholder: 'add login screen',
|
|
55
|
+
nameError: 'Task name cannot be empty.',
|
|
56
|
+
confirm: (name) => `Create branch:\n ${name}`,
|
|
57
|
+
checkoutError: (src) =>
|
|
58
|
+
`Could not switch to ${src}. Make sure the branch exists and there are no conflicts.`,
|
|
59
|
+
pullError: 'Could not pull. Check your connection or resolve any conflicts.',
|
|
60
|
+
branchExists: (name) => `Branch "${name}" already exists. Choose a different name or ticket.`,
|
|
61
|
+
createError: 'Could not create the branch. Check if the name is valid.',
|
|
62
|
+
done: (name) => `Branch created: ${name}`,
|
|
63
|
+
},
|
|
64
|
+
push: {
|
|
65
|
+
confirm: (branch) => `Push current branch: ${branch}?`,
|
|
66
|
+
failed: 'Push failed — see the output above.',
|
|
67
|
+
done: (branch) => `Pushed: origin/${branch}`,
|
|
68
|
+
},
|
|
69
|
+
start: {
|
|
70
|
+
tagline: '— Git workflow automation',
|
|
71
|
+
desc1: 'Guides your team through branch creation and commits',
|
|
72
|
+
desc2: 'following whatever conventions your project defines.',
|
|
73
|
+
prompt: 'What do you want to do?',
|
|
74
|
+
options: {
|
|
75
|
+
init: {
|
|
76
|
+
label: 'Set up UVA CLI for this project',
|
|
77
|
+
hint: 'configure commit and branch patterns',
|
|
78
|
+
},
|
|
79
|
+
commit: {
|
|
80
|
+
label: 'Create an interactive commit',
|
|
81
|
+
hint: 'select files, type, ticket and message',
|
|
82
|
+
},
|
|
83
|
+
branch: { label: 'Create a new branch', hint: 'checks out source and pulls automatically' },
|
|
84
|
+
newFile: {
|
|
85
|
+
label: 'Scaffold a file from a template',
|
|
86
|
+
hint: 'docs and git workflow templates',
|
|
87
|
+
},
|
|
88
|
+
push: {
|
|
89
|
+
label: 'Push the current branch to origin',
|
|
90
|
+
hint: 'confirms the branch and runs git push',
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
common: {
|
|
95
|
+
cancelled: 'Operation cancelled.',
|
|
96
|
+
},
|
|
97
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
init: {
|
|
3
|
+
langSelect: 'Language / Idioma',
|
|
4
|
+
globalMode: 'Configuração global — aplicada a todos os projetos sem config local',
|
|
5
|
+
overwriteConfirm: 'Já existe uma configuração. Deseja sobrescrever?',
|
|
6
|
+
projectName: 'Nome do projeto',
|
|
7
|
+
projectNamePlaceholder: 'Meu Projeto Incrível',
|
|
8
|
+
projectNameError: 'O nome do projeto não pode estar vazio.',
|
|
9
|
+
ticketConfirm: 'Você usa um rastreador de tickets? (ex.: Jira, Linear, GitHub Issues)',
|
|
10
|
+
ticketPrefix: 'Prefixo do ticket',
|
|
11
|
+
ticketPrefixPlaceholder: 'PROJ',
|
|
12
|
+
ticketPrefixError: 'O prefixo não pode estar vazio.',
|
|
13
|
+
commitFormat: 'Escolha o formato de mensagem de commit',
|
|
14
|
+
sources: 'Branches de origem (separados por vírgula)',
|
|
15
|
+
sourcesPlaceholder: 'main,develop',
|
|
16
|
+
sourcesError: 'Pelo menos um branch é obrigatório.',
|
|
17
|
+
branchFormat: 'Escolha o formato de nome de branch',
|
|
18
|
+
areaConfirm: 'Deseja categorizar os branches por área? (ex.: FE, BE, DOC)',
|
|
19
|
+
areaLabels: 'Áreas (separadas por vírgula)',
|
|
20
|
+
areaLabelsPlaceholder: 'FE,BE,DOC',
|
|
21
|
+
areaLabelsError: 'Pelo menos uma área é obrigatória.',
|
|
22
|
+
saved: (path) => `Configuração salva em ${path}`,
|
|
23
|
+
},
|
|
24
|
+
commit: {
|
|
25
|
+
nothingToCommit: 'Nada para commitar.',
|
|
26
|
+
invalidType: (type, valid) => `Tipo inválido "${type}". Valores válidos: ${valid}`,
|
|
27
|
+
unknownFiles: (invalid, available) =>
|
|
28
|
+
`Arquivo(s) desconhecido(s): ${invalid}\nDisponíveis: ${available}`,
|
|
29
|
+
type: 'Tipo do commit',
|
|
30
|
+
ticket: 'Ticket',
|
|
31
|
+
ticketError: 'O ticket não pode estar vazio.',
|
|
32
|
+
message: 'Mensagem do commit',
|
|
33
|
+
messagePlaceholder: 'adicionar tela de login',
|
|
34
|
+
messageError: 'A mensagem não pode estar vazia.',
|
|
35
|
+
messageLong:
|
|
36
|
+
'Mensagem longa (mais de 72 caracteres). Mensagens curtas são recomendadas, mas você pode continuar.',
|
|
37
|
+
files: 'Quais arquivos incluir no commit?',
|
|
38
|
+
allFiles: 'Todos os arquivos',
|
|
39
|
+
confirm: (msg) => `Commitar com a mensagem:\n ${msg}`,
|
|
40
|
+
retry: 'Ok! Vamos reescrever a mensagem.',
|
|
41
|
+
failed: (err) => `Commit falhou: ${err}`,
|
|
42
|
+
done: (msg) => `Commitado: ${msg}`,
|
|
43
|
+
},
|
|
44
|
+
branch: {
|
|
45
|
+
uncommittedConfirm:
|
|
46
|
+
'Você tem alterações não commitadas. Elas serão levadas para o novo branch. Continuar?',
|
|
47
|
+
uncommittedTip: 'Dica: rode `uva commit` primeiro para commitar as alterações pendentes.',
|
|
48
|
+
source: 'Branch de origem',
|
|
49
|
+
sourceWarn: (src) =>
|
|
50
|
+
`"${src}" não está nos branches de origem configurados. Continuando mesmo assim.`,
|
|
51
|
+
ticket: 'Ticket',
|
|
52
|
+
ticketError: 'O ticket não pode estar vazio.',
|
|
53
|
+
type: 'Tipo do branch',
|
|
54
|
+
invalidType: (type, valid) => `Tipo inválido "${type}". Valores válidos: ${valid}`,
|
|
55
|
+
name: 'Nome da tarefa',
|
|
56
|
+
namePlaceholder: 'adicionar tela de login',
|
|
57
|
+
nameError: 'O nome da tarefa não pode estar vazio.',
|
|
58
|
+
confirm: (name) => `Criar branch:\n ${name}`,
|
|
59
|
+
checkoutError: (src) =>
|
|
60
|
+
`Não foi possível mudar para ${src}. Verifique se o branch existe e não há conflitos.`,
|
|
61
|
+
pullError: 'Não foi possível fazer pull. Verifique sua conexão ou resolva conflitos.',
|
|
62
|
+
branchExists: (name) => `O branch "${name}" já existe. Escolha um nome ou ticket diferente.`,
|
|
63
|
+
createError: 'Não foi possível criar o branch. Verifique se o nome é válido.',
|
|
64
|
+
done: (name) => `Branch criado: ${name}`,
|
|
65
|
+
},
|
|
66
|
+
push: {
|
|
67
|
+
confirm: (branch) => `Fazer push do branch atual: ${branch}?`,
|
|
68
|
+
failed: 'Push falhou — veja a saída acima.',
|
|
69
|
+
done: (branch) => `Push realizado: origin/${branch}`,
|
|
70
|
+
},
|
|
71
|
+
start: {
|
|
72
|
+
tagline: '— Automação de workflow Git',
|
|
73
|
+
desc1: 'Guia seu time na criação de branches e commits',
|
|
74
|
+
desc2: 'seguindo as convenções definidas no seu projeto.',
|
|
75
|
+
prompt: 'O que você quer fazer?',
|
|
76
|
+
options: {
|
|
77
|
+
init: {
|
|
78
|
+
label: 'Configurar o UVA CLI para este projeto',
|
|
79
|
+
hint: 'configura padrões de commit e branch',
|
|
80
|
+
},
|
|
81
|
+
commit: {
|
|
82
|
+
label: 'Criar um commit interativo',
|
|
83
|
+
hint: 'selecione arquivos, tipo, ticket e mensagem',
|
|
84
|
+
},
|
|
85
|
+
branch: {
|
|
86
|
+
label: 'Criar um novo branch',
|
|
87
|
+
hint: 'faz checkout da origem e pull automaticamente',
|
|
88
|
+
},
|
|
89
|
+
newFile: {
|
|
90
|
+
label: 'Gerar um arquivo a partir de um template',
|
|
91
|
+
hint: 'templates de docs e workflow Git',
|
|
92
|
+
},
|
|
93
|
+
push: {
|
|
94
|
+
label: 'Fazer push do branch atual para a origin',
|
|
95
|
+
hint: 'confirma o branch e executa git push',
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
common: {
|
|
100
|
+
cancelled: 'Operação cancelada.',
|
|
101
|
+
},
|
|
102
|
+
}
|