project-auto-wizard 0.13.3 → 0.14.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/README.md +1 -1
- package/bin/project-auto-wizard.js +18 -4
- package/package.json +2 -2
- package/payload/config/breaking-changes.json +28 -14
- package/payload/config/wizard-prompts.yml +102 -46
- package/payload/flutter-app/android/fastlane/Fastfile.playstore +44 -32
- package/payload/flutter-app/ios/ExportOptions.plist +8 -8
- package/payload/flutter-app/ios/fastlane/Fastfile +57 -43
- package/payload/scripts/changelog_manager.py +296 -257
- package/payload/scripts/issue_helper.py +54 -50
- package/payload/scripts/messages.py +2279 -0
- package/payload/scripts/truncate_release_notes.py +7 -6
- package/payload/scripts/version_manager.py +64 -61
- package/payload/version.yml.template +2 -1
- package/payload/workflows/common/PROJECT-COMMON-AI-PR-SUMMARY.yaml +17 -12
- package/payload/workflows/common/PROJECT-COMMON-AUTO-CHANGELOG-CONTROL.yaml +59 -34
- package/payload/workflows/common/PROJECT-COMMON-ISSUE-HELPER.yaml +17 -15
- package/payload/workflows/common/PROJECT-COMMON-README-VERSION-UPDATE.yaml +17 -10
- package/payload/workflows/common/PROJECT-COMMON-RELEASE-PUBLISH.yaml +54 -44
- package/payload/workflows/common/PROJECT-COMMON-VERSION-CONTROL.yaml +24 -17
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-FIREBASE-CICD.yaml +194 -184
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-PLAYSTORE-CICD.yaml +226 -213
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-SELFHOSTED-CICD.yaml +46 -42
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-TEST-APK.yaml +334 -241
- package/payload/workflows/flutter/PROJECT-FLUTTER-APP-BUILD-TRIGGER.yaml +152 -128
- package/payload/workflows/flutter/PROJECT-FLUTTER-CI.yaml +246 -188
- package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TEST-TESTFLIGHT.yaml +353 -238
- package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TESTFLIGHT.yaml +96 -85
- package/payload/workflows/go/PROJECT-GO-CI.yaml +47 -36
- package/payload/workflows/go/PROJECT-GO-PR-PREVIEW.yaml +945 -508
- package/payload/workflows/go/PROJECT-GO-SIMPLE-CICD.yaml +155 -133
- package/payload/workflows/next/PROJECT-NEXT-CI.yaml +76 -60
- package/payload/workflows/next/PROJECT-NEXT-CICD.yaml +97 -77
- package/payload/workflows/python/PROJECT-PYTHON-CI.yaml +62 -47
- package/payload/workflows/python/PROJECT-PYTHON-PR-PREVIEW.yaml +942 -505
- package/payload/workflows/python/PROJECT-PYTHON-SIMPLE-CICD.yaml +148 -126
- package/payload/workflows/react/PROJECT-REACT-CI.yaml +86 -70
- package/payload/workflows/react/PROJECT-REACT-CICD.yaml +112 -92
- package/payload/workflows/spring/PROJECT-SPRING-CI.yml +112 -82
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-NONSTOP-NGINX-CICD.yaml +180 -150
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-NONSTOP-TRAEFIK-CICD.yaml +161 -131
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-PR-PREVIEW.yaml +970 -549
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-SIMPLE-CICD.yaml +193 -162
- package/src/cli/args.js +98 -52
- package/src/cli/help.js +8 -41
- package/src/commands/doctor.js +85 -89
- package/src/commands/dry-run.js +63 -43
- package/src/commands/full.js +79 -77
- package/src/commands/install-settings.js +16 -15
- package/src/commands/interactive-flutter.js +20 -19
- package/src/commands/interactive.js +135 -132
- package/src/commands/purge.js +47 -42
- package/src/commands/status.js +36 -36
- package/src/commands/uninstall.js +43 -41
- package/src/context.js +12 -11
- package/src/core/assets.js +12 -11
- package/src/core/baseline.js +27 -27
- package/src/core/branches.js +29 -27
- package/src/core/branding.js +7 -6
- package/src/core/breaking-check.js +22 -21
- package/src/core/breaking.js +15 -8
- package/src/core/copy/app-files.js +5 -4
- package/src/core/copy/flutter-app.js +8 -8
- package/src/core/copy/gitignore.js +58 -50
- package/src/core/copy/readme.js +45 -35
- package/src/core/copy/simple.js +16 -15
- package/src/core/copy/workflows.js +131 -124
- package/src/core/deploy-style.js +51 -48
- package/src/core/detect-fs.js +57 -57
- package/src/core/detect.js +67 -65
- package/src/core/errors.js +2 -2
- package/src/core/flutter-doctor.js +17 -16
- package/src/core/flutter-hooks.js +33 -32
- package/src/core/flutter-options.js +34 -33
- package/src/core/fsutil.js +12 -12
- package/src/core/installed-stores.js +4 -4
- package/src/core/logger.js +42 -40
- package/src/core/paths-resolve.js +88 -86
- package/src/core/paths.js +10 -10
- package/src/core/release-options.js +8 -8
- package/src/core/removal-exec.js +14 -13
- package/src/core/removal-plan.js +37 -37
- package/src/core/types.js +47 -47
- package/src/core/verify.js +44 -38
- package/src/core/version-yml.js +76 -68
- package/src/core/wizard-env.js +46 -46
- package/src/core/wizard-labels.js +63 -41
- package/src/i18n/catalog/en/cli.js +50 -0
- package/src/i18n/catalog/en/commands.js +187 -0
- package/src/i18n/catalog/en/copy.js +19 -0
- package/src/i18n/catalog/en/core.js +74 -0
- package/src/i18n/catalog/en/core2.js +15 -0
- package/src/i18n/catalog/en/ui.js +221 -0
- package/src/i18n/catalog/en.js +12 -0
- package/src/i18n/catalog/index.js +5 -0
- package/src/i18n/catalog/ko/cli.js +50 -0
- package/src/i18n/catalog/ko/commands.js +187 -0
- package/src/i18n/catalog/ko/copy.js +19 -0
- package/src/i18n/catalog/ko/core.js +74 -0
- package/src/i18n/catalog/ko/core2.js +15 -0
- package/src/i18n/catalog/ko/ui.js +221 -0
- package/src/i18n/catalog/ko.js +10 -0
- package/src/i18n/index.js +44 -0
- package/src/i18n/languages.js +9 -0
- package/src/index.js +128 -94
- package/src/ui/ansi.js +7 -7
- package/src/ui/banner.js +7 -6
- package/src/ui/env-plan.js +82 -81
- package/src/ui/prompts.js +97 -122
- package/src/ui/readline-engine.js +59 -58
- package/src/ui/status-cards.js +37 -31
- package/src/ui/summary.js +89 -88
package/src/ui/summary.js
CHANGED
|
@@ -1,89 +1,90 @@
|
|
|
1
|
-
//
|
|
1
|
+
// Completion summary output. Everything goes to stderr.
|
|
2
2
|
// ctx: { mode, types:[], version, copiedFiles:[], branches?, gitignoreUpdated?, readme?, scripts? }
|
|
3
3
|
import { WORKFLOW_PREFIX, WORKFLOW_COMMON_PREFIX } from "../core/paths.js";
|
|
4
4
|
import { paint, A, colorEnabled } from "./ansi.js";
|
|
5
5
|
import { EITHER_SEP } from "../core/verify.js";
|
|
6
6
|
import { BUILD_NUMBER_TYPES } from "../core/types.js";
|
|
7
7
|
import { SCRIPT_NAMES } from "../core/copy/simple.js";
|
|
8
|
+
import { t } from "../i18n/index.js";
|
|
8
9
|
|
|
9
10
|
const SEPARATOR = "────────────────────────────────────────";
|
|
10
11
|
|
|
11
12
|
export function printSummary(ctx) {
|
|
12
13
|
const { mode, types = [], version = "", versionCode = null, copiedFiles = [], autoUpdated = [], branches = null, gitignoreUpdated = false,
|
|
13
|
-
// pr-flow
|
|
14
|
+
// pr-flow but the develop branch could not be created on the remote - the layout line alone looks ready, so warn separately.
|
|
14
15
|
developMissing = false,
|
|
15
|
-
//
|
|
16
|
+
// Post-install verification and record
|
|
16
17
|
answers = [], unresolved = [], secrets = new Map(), optionalSecrets = new Map(), logPath = "", legacyMdLogs = false, cleanup = null,
|
|
17
|
-
// Flutter
|
|
18
|
+
// Flutter store deployment - app files created/kept and cleanup of deselected stores
|
|
18
19
|
flutterApp = null, storeCleanup = null,
|
|
19
|
-
//
|
|
20
|
-
//
|
|
20
|
+
// Actual outcome of this run - README version-section status (return value of addVersionSectionToReadme) and per-script results.
|
|
21
|
+
// Printing fixed text would report "added" even when README.md was missing and nothing was done.
|
|
21
22
|
readme = null, scripts = null } = ctx || {};
|
|
22
23
|
const err = (s = "") => process.stderr.write(`${s}\n`);
|
|
23
|
-
//
|
|
24
|
+
// Color is gated by the shared guard in ansi.js (NO_COLOR + stderr TTY)
|
|
24
25
|
const enabled = colorEnabled(process.stderr);
|
|
25
26
|
|
|
26
27
|
err("");
|
|
27
28
|
err(SEPARATOR);
|
|
28
29
|
err("");
|
|
29
|
-
err("
|
|
30
|
+
err(t("ui.summary.title"));
|
|
30
31
|
err("");
|
|
31
32
|
err(SEPARATOR);
|
|
32
33
|
err("");
|
|
33
|
-
err("
|
|
34
|
+
err(t("ui.summary.features.title"));
|
|
34
35
|
|
|
35
|
-
// README
|
|
36
|
+
// Mention the automatic update only when the README version section really exists (added now or already there).
|
|
36
37
|
const readmeTracked = readme === "added" || readme === "skip-marker" || readme === "skip-version-line";
|
|
37
38
|
if (mode === "full") {
|
|
38
|
-
err("
|
|
39
|
-
if (readmeTracked) err("
|
|
40
|
-
err(
|
|
41
|
-
if (gitignoreUpdated) err("
|
|
39
|
+
err(t("ui.summary.features.versionSystem"));
|
|
40
|
+
if (readmeTracked) err(t("ui.summary.features.readmeAuto"));
|
|
41
|
+
err(t("ui.summary.features.workflows"));
|
|
42
|
+
if (gitignoreUpdated) err(t("ui.summary.features.gitignore"));
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
//
|
|
45
|
+
// Branch mode + release-summary engine notes
|
|
45
46
|
if (branches) {
|
|
46
47
|
err("");
|
|
47
|
-
err("
|
|
48
|
+
err(t("ui.summary.branches.title"));
|
|
48
49
|
if (branches.mode === "trunk-based") {
|
|
49
|
-
err(
|
|
50
|
+
err(t("ui.summary.branches.trunk", { main: branches.main }));
|
|
50
51
|
} else {
|
|
51
|
-
err(
|
|
52
|
+
err(t("ui.summary.branches.prFlow", { develop: branches.develop, main: branches.main }));
|
|
52
53
|
if (developMissing) {
|
|
53
|
-
err(
|
|
54
|
-
err(
|
|
54
|
+
err(t("ui.summary.branches.developMissing", { develop: branches.develop }));
|
|
55
|
+
err(t("ui.summary.branches.developHint", { main: branches.main, develop: branches.develop }));
|
|
55
56
|
}
|
|
56
57
|
}
|
|
57
58
|
}
|
|
58
59
|
if (mode === "full" || mode === "workflows") {
|
|
59
60
|
err("");
|
|
60
|
-
err("
|
|
61
|
-
err("
|
|
61
|
+
err(t("ui.summary.engine.title"));
|
|
62
|
+
err(t("ui.summary.engine.chain"));
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
err("");
|
|
65
|
-
err("
|
|
66
|
-
err(
|
|
67
|
-
if (versionCode != null && types.some((
|
|
68
|
-
err(
|
|
66
|
+
err(t("ui.summary.files.title"));
|
|
67
|
+
err(t("ui.summary.files.versionYml", { version, types: types.join(",") }));
|
|
68
|
+
if (versionCode != null && types.some((ty) => BUILD_NUMBER_TYPES.has(ty))) {
|
|
69
|
+
err(t("ui.summary.files.buildNumber", { code: versionCode }));
|
|
69
70
|
}
|
|
70
|
-
if (readme === "added") err("
|
|
71
|
+
if (readme === "added") err(t("ui.summary.files.readmeAdded"));
|
|
71
72
|
if (readme === "skip-no-readme") {
|
|
72
|
-
err("
|
|
73
|
-
err("
|
|
73
|
+
err(t("ui.summary.files.readmeMissing"));
|
|
74
|
+
err(t("ui.summary.files.readmeMissingHint"));
|
|
74
75
|
}
|
|
75
76
|
err("");
|
|
76
|
-
err("
|
|
77
|
+
err(t("ui.summary.workflows.title"));
|
|
77
78
|
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
-
//
|
|
79
|
+
// Classify only files actually copied in this run (copiedFiles returned by copyWorkflows() -
|
|
80
|
+
// rescanning the directory would show files skipped on a re-run as "newly installed").
|
|
81
|
+
// Auto-updated files (unmodified files replaced with the latest) are also in copiedFiles - show them apart from new installs.
|
|
81
82
|
const updated = new Set(autoUpdated);
|
|
82
83
|
const commonWorkflows = [];
|
|
83
84
|
const typeWorkflows = [];
|
|
84
|
-
const typePrefixes = types.map((
|
|
85
|
+
const typePrefixes = types.map((ty) => `${WORKFLOW_PREFIX}-${ty.toUpperCase()}-`);
|
|
85
86
|
for (const filename of copiedFiles) {
|
|
86
|
-
if (!filename.startsWith(`${WORKFLOW_PREFIX}-`)) continue; // PROJECT
|
|
87
|
+
if (!filename.startsWith(`${WORKFLOW_PREFIX}-`)) continue; // PROJECT-* only
|
|
87
88
|
if (updated.has(filename)) continue;
|
|
88
89
|
if (filename.startsWith(`${WORKFLOW_COMMON_PREFIX}-`)) {
|
|
89
90
|
commonWorkflows.push(filename);
|
|
@@ -93,142 +94,142 @@ export function printSummary(ctx) {
|
|
|
93
94
|
}
|
|
94
95
|
|
|
95
96
|
if (commonWorkflows.length > 0 || typeWorkflows.length > 0) {
|
|
96
|
-
err(
|
|
97
|
+
err(t("ui.summary.workflows.installed", { count: commonWorkflows.length + typeWorkflows.length }));
|
|
97
98
|
for (const wf of commonWorkflows) err(` 📌 ${wf}`);
|
|
98
99
|
for (const wf of typeWorkflows) err(` 🎯 ${wf}`);
|
|
99
100
|
}
|
|
100
101
|
if (updated.size > 0) {
|
|
101
|
-
err(
|
|
102
|
+
err(t("ui.summary.workflows.updated", { count: updated.size }));
|
|
102
103
|
for (const wf of updated) err(` • ${wf}`);
|
|
103
104
|
}
|
|
104
105
|
|
|
105
106
|
err("");
|
|
106
107
|
err(" 🔧 .github/scripts/");
|
|
107
108
|
const scriptRows = scripts
|
|
108
|
-
? scripts.map(({ name, action }) => (action === "overwrite" ? `${name} ${paint("
|
|
109
|
+
? scripts.map(({ name, action }) => (action === "overwrite" ? `${name} ${paint(t("ui.summary.scripts.overwritten"), A.dim, enabled)}` : name))
|
|
109
110
|
: SCRIPT_NAMES;
|
|
110
111
|
scriptRows.forEach((row, i) => err(` ${i === scriptRows.length - 1 ? "└─" : "├─"} ${row}`));
|
|
111
112
|
err("");
|
|
112
113
|
|
|
113
|
-
//
|
|
114
|
-
// YAML
|
|
114
|
+
// Environment values the user entered - a last chance to eyeball them. Answers used to vanish
|
|
115
|
+
// into the workflow YAML, so a typo only surfaced after a deploy failed.
|
|
115
116
|
if (answers.length) {
|
|
116
|
-
err("
|
|
117
|
+
err(t("ui.summary.answers.title"));
|
|
117
118
|
for (const a of answers) {
|
|
118
|
-
const mark = a.isDefault ? paint("
|
|
119
|
+
const mark = a.isDefault ? paint(t("ui.summary.answers.default"), A.dim, enabled) : "";
|
|
119
120
|
err(` • ${a.label}: ${paint(a.value, A.green, enabled)}${mark}`);
|
|
120
121
|
}
|
|
121
122
|
err("");
|
|
122
123
|
}
|
|
123
|
-
//
|
|
124
|
-
printCleanup(err, enabled, "
|
|
125
|
-
//
|
|
126
|
-
printCleanup(err, enabled, "
|
|
127
|
-
// Fastfile
|
|
124
|
+
// When re-installed with a different deploy style, report how the previous CD was handled.
|
|
125
|
+
printCleanup(err, enabled, t("ui.summary.cleanup.previousDeploy"), cleanup);
|
|
126
|
+
// Same reporting when a store deploy target was deselected.
|
|
127
|
+
printCleanup(err, enabled, t("ui.summary.cleanup.deselectedStores"), storeCleanup);
|
|
128
|
+
// Fastfile and ExportOptions.plist are user-owned and only created when missing - show what was created vs. left alone.
|
|
128
129
|
const { created: appCreated = [], kept: appKept = [] } = flutterApp || {};
|
|
129
130
|
if (appCreated.length || appKept.length) {
|
|
130
|
-
err("
|
|
131
|
-
for (const f of appCreated) err(` • ${f} ${paint("
|
|
132
|
-
for (const f of appKept) err(` • ${f} ${paint("
|
|
131
|
+
err(t("ui.summary.flutterApp.title"));
|
|
132
|
+
for (const f of appCreated) err(` • ${f} ${paint(t("ui.summary.flutterApp.created"), A.dim, enabled)}`);
|
|
133
|
+
for (const f of appKept) err(` • ${f} ${paint(t("ui.summary.flutterApp.kept"), A.dim, enabled)}`);
|
|
133
134
|
if (appCreated.some((f) => f.endsWith("ExportOptions.plist"))) {
|
|
134
|
-
err("
|
|
135
|
+
err(t("ui.summary.flutterApp.plistHint"));
|
|
135
136
|
}
|
|
136
137
|
err("");
|
|
137
138
|
}
|
|
138
139
|
if (logPath) {
|
|
139
|
-
err(
|
|
140
|
-
err(
|
|
140
|
+
err(t("ui.summary.log.path", { path: logPath }));
|
|
141
|
+
err(t("ui.summary.log.hint"));
|
|
141
142
|
err("");
|
|
142
143
|
}
|
|
143
144
|
if (legacyMdLogs) {
|
|
144
|
-
err("
|
|
145
|
+
err(t("ui.summary.legacyLogs"));
|
|
145
146
|
err(" git rm -r --cached .github/.wizard/logs");
|
|
146
147
|
err("");
|
|
147
148
|
}
|
|
148
149
|
|
|
149
|
-
//
|
|
150
|
+
// Per-type notes
|
|
150
151
|
if (types.includes("spring")) {
|
|
151
|
-
err("
|
|
152
|
-
err("
|
|
152
|
+
err(t("ui.summary.spring.title"));
|
|
153
|
+
err(t("ui.summary.spring.sync"));
|
|
153
154
|
err("");
|
|
154
155
|
}
|
|
155
156
|
|
|
156
157
|
err(" 📖 REPO: https://github.com/Twin-Fang/project-auto-wizard");
|
|
157
158
|
err("");
|
|
158
159
|
|
|
159
|
-
//
|
|
160
|
+
// Required follow-up actions
|
|
160
161
|
err(SEPARATOR);
|
|
161
162
|
err("");
|
|
162
|
-
err(paint(paint("
|
|
163
|
+
err(paint(paint(t("ui.summary.todo.title"), A.yellow, enabled), A.bold, enabled));
|
|
163
164
|
err("");
|
|
164
165
|
|
|
165
166
|
let step = 0;
|
|
166
167
|
const num = () => ["1️⃣ ", "2️⃣ ", "3️⃣ ", "4️⃣ ", "5️⃣ "][step++] || " •";
|
|
167
168
|
|
|
168
|
-
//
|
|
169
|
+
// Unresolved placeholders - the affected workflow will not work as is, so report them first.
|
|
169
170
|
if (unresolved.length) {
|
|
170
|
-
err(` ${num()} ${paint("
|
|
171
|
+
err(` ${num()} ${paint(t("ui.summary.todo.unresolved"), A.red, enabled)}`);
|
|
171
172
|
for (const u of unresolved) {
|
|
172
173
|
err(` → ${u.filename}:${u.line} ${paint(u.token, A.bold, enabled)}`);
|
|
173
174
|
}
|
|
174
175
|
err("");
|
|
175
176
|
}
|
|
176
177
|
|
|
177
|
-
//
|
|
178
|
-
// "
|
|
179
|
-
// "A
|
|
178
|
+
// Secrets the installed workflows actually require - none used to be listed, so an install
|
|
179
|
+
// "succeeded" yet deploys never ran.
|
|
180
|
+
// "A or B" is a fallback pair where registering either one is enough, so it counts as one item.
|
|
180
181
|
if (secrets.size) {
|
|
181
|
-
err(` ${num()}
|
|
182
|
-
err("
|
|
182
|
+
err(` ${num()} ${t("ui.summary.todo.secrets", { count: secrets.size })}`);
|
|
183
|
+
err(t("ui.summary.todo.secretsPath"));
|
|
183
184
|
for (const [name, users] of secrets) {
|
|
184
|
-
const either = name.includes(EITHER_SEP) ? paint("
|
|
185
|
+
const either = name.includes(EITHER_SEP) ? paint(t("ui.summary.todo.either"), A.dim, enabled) : "";
|
|
185
186
|
err(` → ${paint(name, A.bold, enabled)}${either} ${paint(users.join(", "), A.dim, enabled)}`);
|
|
186
187
|
}
|
|
187
188
|
err("");
|
|
188
189
|
}
|
|
189
|
-
//
|
|
190
|
+
// Secrets that have a default or work without them - listed separately from the required count.
|
|
190
191
|
if (optionalSecrets.size) {
|
|
191
|
-
err(` ${paint("ℹ️", A.dim, enabled)}
|
|
192
|
+
err(` ${paint("ℹ️", A.dim, enabled)} ${t("ui.summary.todo.optionalSecrets", { count: optionalSecrets.size })}`);
|
|
192
193
|
for (const [name, users] of optionalSecrets) {
|
|
193
194
|
err(` · ${name} ${paint(users.join(", "), A.dim, enabled)}`);
|
|
194
195
|
}
|
|
195
196
|
err("");
|
|
196
197
|
}
|
|
197
198
|
|
|
198
|
-
//
|
|
199
|
-
//
|
|
199
|
+
// Installed files are not committed yet. If develop was created in this run it is based on the pre-install commit and has no workflows -
|
|
200
|
+
// committing to only one branch leaves the other without VERSION-CONTROL etc.
|
|
200
201
|
if (branches) {
|
|
201
|
-
err(` ${num()}
|
|
202
|
+
err(` ${num()} ${t("ui.summary.todo.commit", { main: branches.main })}`);
|
|
202
203
|
if (branches.mode !== "trunk-based") {
|
|
203
|
-
err(
|
|
204
|
-
err(
|
|
204
|
+
err(t("ui.summary.todo.commitDevelop", { develop: branches.develop }));
|
|
205
|
+
err(t("ui.summary.todo.commitExample", { develop: branches.develop, main: branches.main }));
|
|
205
206
|
}
|
|
206
|
-
err("
|
|
207
|
+
err(t("ui.summary.todo.changelogLink"));
|
|
207
208
|
err("");
|
|
208
209
|
}
|
|
209
210
|
|
|
210
|
-
err(` ${num()}
|
|
211
|
-
err("
|
|
212
|
-
err(
|
|
213
|
-
err("
|
|
214
|
-
err("
|
|
211
|
+
err(` ${num()} ${t("ui.summary.todo.pat")}`);
|
|
212
|
+
err(t("ui.summary.todo.patPath"));
|
|
213
|
+
err(t("ui.summary.todo.patName"));
|
|
214
|
+
err(t("ui.summary.todo.patAccount"));
|
|
215
|
+
err(t("ui.summary.todo.patOptional"));
|
|
215
216
|
err("");
|
|
216
|
-
//
|
|
217
|
-
err(` ${num()}
|
|
218
|
-
err("
|
|
219
|
-
err("
|
|
217
|
+
// Installed workflows declare the permissions they need themselves - report it by the same rule as the doctor guidance.
|
|
218
|
+
err(` ${num()} ${t("ui.summary.todo.permissions")}`);
|
|
219
|
+
err(t("ui.summary.todo.permissionsRead"));
|
|
220
|
+
err(t("ui.summary.todo.permissionsWrite"));
|
|
220
221
|
err("");
|
|
221
222
|
err(SEPARATOR);
|
|
222
223
|
err("");
|
|
223
|
-
err(paint("
|
|
224
|
+
err(paint(t("ui.summary.footer"), A.cyan, enabled));
|
|
224
225
|
err("");
|
|
225
226
|
}
|
|
226
227
|
|
|
227
|
-
//
|
|
228
|
+
// One block of removal/backup cleanup results - previous-deploy cleanup and deselected-store cleanup share the format.
|
|
228
229
|
function printCleanup(err, enabled, title, cleanup) {
|
|
229
230
|
if (!cleanup?.removed?.length && !cleanup?.backedUp?.length) return;
|
|
230
231
|
err(` 🧹 ${title}:`);
|
|
231
|
-
for (const f of cleanup.removed || []) err(` • ${f} ${paint("
|
|
232
|
-
for (const f of cleanup.backedUp || []) err(` • ${f} → ${f}.bak ${paint("
|
|
232
|
+
for (const f of cleanup.removed || []) err(` • ${f} ${paint(t("ui.summary.cleanup.removed"), A.dim, enabled)}`);
|
|
233
|
+
for (const f of cleanup.backedUp || []) err(` • ${f} → ${f}.bak ${paint(t("ui.summary.cleanup.backedUp"), A.dim, enabled)}`);
|
|
233
234
|
err("");
|
|
234
235
|
}
|