fg-devkit 1.12.6 → 1.12.7
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/configs/dependency-policy.vue-workspace.json +40 -34
- package/package.json +23 -7
- package/scaffold/vue/package.json +15 -12
- package/scripts/bump-node-toolchain.mjs +260 -0
- package/scripts/bump-pnpm-toolchain.mjs +65 -28
- package/scripts/check-dependency-policy.mjs +8 -0
- package/scripts/dependency-policy-toolchain.mjs +187 -7
- package/scripts/fg-devkit.mjs +214 -3
- package/scripts/fleet-git-commit-push-scoped.mjs +97 -0
- package/scripts/fleet-git-commit-push.mjs +75 -0
- package/scripts/fleet-git-discard-scoped.mjs +93 -0
- package/scripts/fleet-git-discard.mjs +66 -0
- package/scripts/fleet-git-pull-scoped.mjs +92 -0
- package/scripts/fleet-git-pull.mjs +65 -0
- package/scripts/fleet-project-repos.mjs +173 -0
- package/scripts/fleet-repo-picker.mjs +190 -0
- package/scripts/fleet-vue-repos.mjs +3 -1
- package/scripts/fleet-vulns.mjs +2 -1
- package/scripts/git-commit-push-fleet-common.mjs +147 -0
- package/scripts/git-discard-fleet-common.mjs +100 -0
- package/scripts/git-fleet-common.mjs +120 -0
- package/scripts/git-pull-fleet-common.mjs +90 -0
- package/scripts/node-toolchain-sync.mjs +347 -0
- package/scripts/pnpm-toolchain-sync.mjs +231 -0
- package/scripts/scaffold-vue.mjs +2 -2
- package/scripts/sync-dependency-policy.mjs +47 -15
- package/scripts/sync-node-toolchain.mjs +64 -0
- package/scripts/sync-pnpm-toolchain.mjs +59 -0
- package/scripts/sync-scaffold-vue-deps.mjs +12 -5
- package/scaffold/vue/Dockerfile.local +0 -16
package/scripts/fleet-vulns.mjs
CHANGED
|
@@ -11,6 +11,7 @@ import fs from 'node:fs'
|
|
|
11
11
|
import path from 'node:path'
|
|
12
12
|
import { spawnSync } from 'node:child_process'
|
|
13
13
|
import { fileURLToPath } from 'node:url'
|
|
14
|
+
import { isFgDevkitRepoDir } from './fleet-project-repos.mjs'
|
|
14
15
|
|
|
15
16
|
const scriptDir = path.dirname(fileURLToPath(import.meta.url))
|
|
16
17
|
const cliArgs = process.argv.slice(2)
|
|
@@ -54,8 +55,8 @@ for (const packageJsonPath of packageJsonFiles) {
|
|
|
54
55
|
try {
|
|
55
56
|
const pkg = readJson(packageJsonPath)
|
|
56
57
|
const repoDir = path.dirname(packageJsonPath)
|
|
58
|
+
if (isFgDevkitRepoDir(repoDir)) continue
|
|
57
59
|
if (!isPnpmProject(pkg)) continue
|
|
58
|
-
if (pkg.name === 'fg-devkit') continue
|
|
59
60
|
repos.push(repoDir)
|
|
60
61
|
} catch {
|
|
61
62
|
// Ignore invalid package.json files.
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stage, commit, and push helpers for fleet maintainer scripts.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { spawnSync } from 'node:child_process'
|
|
6
|
+
|
|
7
|
+
import { formatRepoLabel } from './fleet-repo-picker.mjs'
|
|
8
|
+
import { getCurrentGitBranch, hasGitWorkingTreeChanges } from './git-fleet-common.mjs'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {{
|
|
12
|
+
* repos: string[]
|
|
13
|
+
* projectsRoot: string
|
|
14
|
+
* commitMessage: string
|
|
15
|
+
* dryRun?: boolean
|
|
16
|
+
* logPrefix?: string
|
|
17
|
+
* }} options
|
|
18
|
+
* @returns {number}
|
|
19
|
+
*/
|
|
20
|
+
export function runFleetGitCommitPush(options) {
|
|
21
|
+
const {
|
|
22
|
+
repos,
|
|
23
|
+
projectsRoot,
|
|
24
|
+
commitMessage,
|
|
25
|
+
dryRun = false,
|
|
26
|
+
logPrefix = '[fleet-git-commit-push]',
|
|
27
|
+
} = options
|
|
28
|
+
|
|
29
|
+
/** @type {{ label: string, branch: string }[]} */
|
|
30
|
+
const committed = []
|
|
31
|
+
/** @type {string[]} */
|
|
32
|
+
const skipped = []
|
|
33
|
+
/** @type {{ label: string, reason: string }[]} */
|
|
34
|
+
const failed = []
|
|
35
|
+
|
|
36
|
+
for (const repoDir of repos) {
|
|
37
|
+
const label = formatRepoLabel(repoDir, projectsRoot)
|
|
38
|
+
const branch = getCurrentGitBranch(repoDir)
|
|
39
|
+
|
|
40
|
+
if (branch === null) {
|
|
41
|
+
failed.push({ label, reason: 'could not determine current branch' })
|
|
42
|
+
continue
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (!hasGitWorkingTreeChanges(repoDir)) {
|
|
46
|
+
skipped.push(label)
|
|
47
|
+
continue
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (dryRun) {
|
|
51
|
+
console.log(
|
|
52
|
+
`${logPrefix} DRY RUN ${label}: git add -A && git commit && git push (on ${branch})`,
|
|
53
|
+
)
|
|
54
|
+
committed.push({ label, branch })
|
|
55
|
+
continue
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
console.log(`\n${logPrefix} ${label} (${branch})`)
|
|
59
|
+
|
|
60
|
+
const stage = spawnSync('git', ['add', '-A'], {
|
|
61
|
+
cwd: repoDir,
|
|
62
|
+
encoding: 'utf8',
|
|
63
|
+
env: process.env,
|
|
64
|
+
})
|
|
65
|
+
if (stage.error) {
|
|
66
|
+
failed.push({ label, reason: stage.error.message })
|
|
67
|
+
continue
|
|
68
|
+
}
|
|
69
|
+
if ((stage.status ?? 1) !== 0) {
|
|
70
|
+
failed.push({
|
|
71
|
+
label,
|
|
72
|
+
reason: stage.stderr?.trim() || `git add exited with code ${stage.status ?? 1}`,
|
|
73
|
+
})
|
|
74
|
+
continue
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const commit = spawnSync('git', ['commit', '-m', commitMessage], {
|
|
78
|
+
cwd: repoDir,
|
|
79
|
+
encoding: 'utf8',
|
|
80
|
+
env: process.env,
|
|
81
|
+
})
|
|
82
|
+
if (commit.error) {
|
|
83
|
+
failed.push({ label, reason: commit.error.message })
|
|
84
|
+
continue
|
|
85
|
+
}
|
|
86
|
+
if ((commit.status ?? 1) !== 0) {
|
|
87
|
+
failed.push({
|
|
88
|
+
label,
|
|
89
|
+
reason: commit.stderr?.trim() || `git commit exited with code ${commit.status ?? 1}`,
|
|
90
|
+
})
|
|
91
|
+
continue
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const push = spawnSync('git', ['push'], {
|
|
95
|
+
cwd: repoDir,
|
|
96
|
+
encoding: 'utf8',
|
|
97
|
+
env: process.env,
|
|
98
|
+
})
|
|
99
|
+
if (push.error) {
|
|
100
|
+
failed.push({ label, reason: push.error.message })
|
|
101
|
+
continue
|
|
102
|
+
}
|
|
103
|
+
if ((push.status ?? 1) !== 0) {
|
|
104
|
+
failed.push({
|
|
105
|
+
label,
|
|
106
|
+
reason: push.stderr?.trim() || `git push exited with code ${push.status ?? 1}`,
|
|
107
|
+
})
|
|
108
|
+
continue
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (commit.stdout?.trim()) {
|
|
112
|
+
console.log(commit.stdout.trim())
|
|
113
|
+
}
|
|
114
|
+
committed.push({ label, branch })
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
console.log(`\n${logPrefix} Summary`)
|
|
118
|
+
console.log(`${logPrefix} commit message: ${commitMessage}`)
|
|
119
|
+
console.log(`${logPrefix} repositories=${repos.length}`)
|
|
120
|
+
|
|
121
|
+
if (committed.length > 0) {
|
|
122
|
+
console.log(`${logPrefix} committed and pushed (${committed.length}):`)
|
|
123
|
+
for (const item of committed) {
|
|
124
|
+
console.log(` - ${item.label} (${item.branch})`)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (skipped.length > 0) {
|
|
129
|
+
console.log(`${logPrefix} skipped — no changes (${skipped.length}):`)
|
|
130
|
+
for (const label of skipped) {
|
|
131
|
+
console.log(` - ${label}`)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (failed.length > 0) {
|
|
136
|
+
console.log(`${logPrefix} failed (${failed.length}):`)
|
|
137
|
+
for (const item of failed) {
|
|
138
|
+
console.log(` - ${item.label}: ${item.reason}`)
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (repos.length === 0) {
|
|
143
|
+
console.log(`${logPrefix} No repositories to process.`)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return failed.length > 0 ? 1 : 0
|
|
147
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discard tracked git changes helpers for fleet maintainer scripts.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { spawnSync } from 'node:child_process'
|
|
6
|
+
|
|
7
|
+
import { formatRepoLabel } from './fleet-repo-picker.mjs'
|
|
8
|
+
import { getCurrentGitBranch, hasTrackedGitChanges } from './git-fleet-common.mjs'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {{
|
|
12
|
+
* repos: string[]
|
|
13
|
+
* projectsRoot: string
|
|
14
|
+
* dryRun?: boolean
|
|
15
|
+
* logPrefix?: string
|
|
16
|
+
* }} options
|
|
17
|
+
* @returns {number}
|
|
18
|
+
*/
|
|
19
|
+
export function runFleetGitDiscard(options) {
|
|
20
|
+
const { repos, projectsRoot, dryRun = false, logPrefix = '[fleet-git-discard]' } = options
|
|
21
|
+
|
|
22
|
+
/** @type {{ label: string, branch: string }[]} */
|
|
23
|
+
const discarded = []
|
|
24
|
+
/** @type {string[]} */
|
|
25
|
+
const skipped = []
|
|
26
|
+
/** @type {{ label: string, reason: string }[]} */
|
|
27
|
+
const failed = []
|
|
28
|
+
|
|
29
|
+
for (const repoDir of repos) {
|
|
30
|
+
const label = formatRepoLabel(repoDir, projectsRoot)
|
|
31
|
+
const branch = getCurrentGitBranch(repoDir)
|
|
32
|
+
|
|
33
|
+
if (branch === null) {
|
|
34
|
+
failed.push({ label, reason: 'could not determine current branch' })
|
|
35
|
+
continue
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (!hasTrackedGitChanges(repoDir)) {
|
|
39
|
+
skipped.push(label)
|
|
40
|
+
continue
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (dryRun) {
|
|
44
|
+
console.log(`${logPrefix} DRY RUN ${label}: git restore --source=HEAD --staged --worktree . (${branch})`)
|
|
45
|
+
discarded.push({ label, branch })
|
|
46
|
+
continue
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
console.log(`\n${logPrefix} ${label} (${branch})`)
|
|
50
|
+
const restore = spawnSync('git', ['restore', '--source=HEAD', '--staged', '--worktree', '.'], {
|
|
51
|
+
cwd: repoDir,
|
|
52
|
+
encoding: 'utf8',
|
|
53
|
+
env: process.env,
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
if (restore.error) {
|
|
57
|
+
failed.push({ label, reason: restore.error.message })
|
|
58
|
+
continue
|
|
59
|
+
}
|
|
60
|
+
if ((restore.status ?? 1) !== 0) {
|
|
61
|
+
failed.push({
|
|
62
|
+
label,
|
|
63
|
+
reason: restore.stderr?.trim() || `git restore exited with code ${restore.status ?? 1}`,
|
|
64
|
+
})
|
|
65
|
+
continue
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
discarded.push({ label, branch })
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
console.log(`\n${logPrefix} Summary`)
|
|
72
|
+
console.log(`${logPrefix} repositories=${repos.length}`)
|
|
73
|
+
|
|
74
|
+
if (discarded.length > 0) {
|
|
75
|
+
console.log(`${logPrefix} discarded tracked changes (${discarded.length}):`)
|
|
76
|
+
for (const item of discarded) {
|
|
77
|
+
console.log(` - ${item.label} (${item.branch})`)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (skipped.length > 0) {
|
|
82
|
+
console.log(`${logPrefix} skipped — no tracked changes (${skipped.length}):`)
|
|
83
|
+
for (const label of skipped) {
|
|
84
|
+
console.log(` - ${label}`)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (failed.length > 0) {
|
|
89
|
+
console.log(`${logPrefix} failed (${failed.length}):`)
|
|
90
|
+
for (const item of failed) {
|
|
91
|
+
console.log(` - ${item.label}: ${item.reason}`)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (repos.length === 0) {
|
|
96
|
+
console.log(`${logPrefix} No repositories to process.`)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return failed.length > 0 ? 1 : 0
|
|
100
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared git helpers for fleet maintainer scripts.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { spawnSync } from 'node:child_process'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @param {string} repoDir
|
|
9
|
+
* @returns {string | null}
|
|
10
|
+
*/
|
|
11
|
+
export function getCurrentGitBranch(repoDir) {
|
|
12
|
+
const result = spawnSync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], {
|
|
13
|
+
cwd: repoDir,
|
|
14
|
+
encoding: 'utf8',
|
|
15
|
+
env: process.env,
|
|
16
|
+
})
|
|
17
|
+
if ((result.status ?? 1) !== 0) {
|
|
18
|
+
return null
|
|
19
|
+
}
|
|
20
|
+
const branch = result.stdout.trim()
|
|
21
|
+
if (!branch || branch === 'HEAD') {
|
|
22
|
+
return null
|
|
23
|
+
}
|
|
24
|
+
return branch
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param {string} repoDir
|
|
29
|
+
* @returns {boolean}
|
|
30
|
+
*/
|
|
31
|
+
export function hasGitWorkingTreeChanges(repoDir) {
|
|
32
|
+
const result = spawnSync('git', ['status', '--porcelain'], {
|
|
33
|
+
cwd: repoDir,
|
|
34
|
+
encoding: 'utf8',
|
|
35
|
+
env: process.env,
|
|
36
|
+
})
|
|
37
|
+
if ((result.status ?? 1) !== 0) {
|
|
38
|
+
return false
|
|
39
|
+
}
|
|
40
|
+
return result.stdout.trim().length > 0
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @param {string} repoDir
|
|
45
|
+
* @returns {boolean}
|
|
46
|
+
*/
|
|
47
|
+
export function hasTrackedGitChanges(repoDir) {
|
|
48
|
+
const result = spawnSync('git', ['status', '--porcelain', '--untracked-files=no'], {
|
|
49
|
+
cwd: repoDir,
|
|
50
|
+
encoding: 'utf8',
|
|
51
|
+
env: process.env,
|
|
52
|
+
})
|
|
53
|
+
if ((result.status ?? 1) !== 0) {
|
|
54
|
+
return false
|
|
55
|
+
}
|
|
56
|
+
return result.stdout.trim().length > 0
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @param {string[]} cliArgs
|
|
61
|
+
* @returns {string | null}
|
|
62
|
+
*/
|
|
63
|
+
export function parseCommitMessageArg(cliArgs) {
|
|
64
|
+
const messageArg = cliArgs.find((arg) => arg.startsWith('--message='))
|
|
65
|
+
if (messageArg) {
|
|
66
|
+
return messageArg.slice('--message='.length)
|
|
67
|
+
}
|
|
68
|
+
const mIndex = cliArgs.indexOf('-m')
|
|
69
|
+
if (mIndex !== -1 && cliArgs[mIndex + 1] && !cliArgs[mIndex + 1].startsWith('-')) {
|
|
70
|
+
return cliArgs[mIndex + 1]
|
|
71
|
+
}
|
|
72
|
+
return null
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* @param {string[]} cliArgs
|
|
77
|
+
* @returns {string[]}
|
|
78
|
+
*/
|
|
79
|
+
export function filterCommitPushPositionalArgs(cliArgs) {
|
|
80
|
+
const filtered = []
|
|
81
|
+
for (let i = 0; i < cliArgs.length; i++) {
|
|
82
|
+
const arg = cliArgs[i]
|
|
83
|
+
if (arg === '-m') {
|
|
84
|
+
i += 1
|
|
85
|
+
continue
|
|
86
|
+
}
|
|
87
|
+
if (arg.startsWith('--message=')) {
|
|
88
|
+
continue
|
|
89
|
+
}
|
|
90
|
+
filtered.push(arg)
|
|
91
|
+
}
|
|
92
|
+
return filtered
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* @param {string[]} cliArgs
|
|
97
|
+
* @param {string} logPrefix
|
|
98
|
+
* @returns {Promise<string>}
|
|
99
|
+
*/
|
|
100
|
+
export async function resolveCommitMessage(cliArgs, logPrefix) {
|
|
101
|
+
const fromArg = parseCommitMessageArg(cliArgs)
|
|
102
|
+
if (fromArg?.trim()) {
|
|
103
|
+
return fromArg.trim()
|
|
104
|
+
}
|
|
105
|
+
if (process.stdin.isTTY) {
|
|
106
|
+
try {
|
|
107
|
+
const inquirerInput = await import('@inquirer/input')
|
|
108
|
+
const message = await inquirerInput.default({
|
|
109
|
+
message: 'Commit message',
|
|
110
|
+
validate: (value) => (value.trim().length > 0 ? true : 'Commit message is required'),
|
|
111
|
+
})
|
|
112
|
+
return message.trim()
|
|
113
|
+
} catch {
|
|
114
|
+
console.error(`${logPrefix} Could not load @inquirer/input for commit message prompt.`)
|
|
115
|
+
process.exit(1)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
console.error(`${logPrefix} Commit message required: --message="..." or -m "..."`)
|
|
119
|
+
process.exit(1)
|
|
120
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git pull helpers for fleet maintainer scripts.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { spawnSync } from 'node:child_process'
|
|
6
|
+
|
|
7
|
+
import { formatRepoLabel } from './fleet-repo-picker.mjs'
|
|
8
|
+
import { getCurrentGitBranch } from './git-fleet-common.mjs'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {{
|
|
12
|
+
* repos: string[]
|
|
13
|
+
* projectsRoot: string
|
|
14
|
+
* dryRun?: boolean
|
|
15
|
+
* logPrefix?: string
|
|
16
|
+
* }} options
|
|
17
|
+
* @returns {number} Exit code (0 = success, 1 = any failure)
|
|
18
|
+
*/
|
|
19
|
+
export function runFleetGitPull(options) {
|
|
20
|
+
const { repos, projectsRoot, dryRun = false, logPrefix = '[fleet-git-pull]' } = options
|
|
21
|
+
|
|
22
|
+
/** @type {{ label: string, branch: string }[]} */
|
|
23
|
+
const pulled = []
|
|
24
|
+
/** @type {{ label: string, reason: string }[]} */
|
|
25
|
+
const failed = []
|
|
26
|
+
|
|
27
|
+
for (const repoDir of repos) {
|
|
28
|
+
const label = formatRepoLabel(repoDir, projectsRoot)
|
|
29
|
+
const branch = getCurrentGitBranch(repoDir)
|
|
30
|
+
|
|
31
|
+
if (branch === null) {
|
|
32
|
+
failed.push({ label, reason: 'could not determine current branch' })
|
|
33
|
+
continue
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (dryRun) {
|
|
37
|
+
console.log(`${logPrefix} DRY RUN ${label}: git pull (on ${branch})`)
|
|
38
|
+
pulled.push({ label, branch })
|
|
39
|
+
continue
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
console.log(`\n${logPrefix} ${label} (${branch})`)
|
|
43
|
+
const pull = spawnSync('git', ['pull'], {
|
|
44
|
+
cwd: repoDir,
|
|
45
|
+
encoding: 'utf8',
|
|
46
|
+
env: process.env,
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
if (pull.error) {
|
|
50
|
+
failed.push({ label, reason: pull.error.message })
|
|
51
|
+
continue
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if ((pull.status ?? 1) !== 0) {
|
|
55
|
+
const stderr = pull.stderr?.trim()
|
|
56
|
+
const stdout = pull.stdout?.trim()
|
|
57
|
+
const detail = stderr || stdout || `git pull exited with code ${pull.status ?? 1}`
|
|
58
|
+
failed.push({ label, reason: detail })
|
|
59
|
+
continue
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (pull.stdout?.trim()) {
|
|
63
|
+
console.log(pull.stdout.trim())
|
|
64
|
+
}
|
|
65
|
+
pulled.push({ label, branch })
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
console.log(`\n${logPrefix} Summary`)
|
|
69
|
+
console.log(`${logPrefix} repositories=${repos.length}`)
|
|
70
|
+
|
|
71
|
+
if (pulled.length > 0) {
|
|
72
|
+
console.log(`${logPrefix} pulled (${pulled.length}):`)
|
|
73
|
+
for (const item of pulled) {
|
|
74
|
+
console.log(` - ${item.label} (${item.branch})`)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (failed.length > 0) {
|
|
79
|
+
console.log(`${logPrefix} failed (${failed.length}):`)
|
|
80
|
+
for (const item of failed) {
|
|
81
|
+
console.log(` - ${item.label}: ${item.reason}`)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (repos.length === 0) {
|
|
86
|
+
console.log(`${logPrefix} No repositories to process.`)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return failed.length > 0 ? 1 : 0
|
|
90
|
+
}
|