actions-up 1.12.0 → 1.13.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/dist/cli/build-json-report.d.ts +257 -0
- package/dist/cli/build-json-report.js +64 -0
- package/dist/cli/index.d.ts +3 -1
- package/dist/cli/index.js +132 -73
- package/dist/cli/resolve-scan-directories.d.ts +6 -2
- package/dist/cli/validate-cli-options.d.ts +20 -0
- package/dist/cli/validate-cli-options.js +4 -0
- package/dist/core/api/check-updates.js +68 -55
- package/dist/core/api/get-all-releases.d.ts +2 -1
- package/dist/core/api/get-compatible-update.d.ts +15 -5
- package/dist/core/api/get-latest-release.d.ts +3 -3
- package/dist/core/ast/utils/extract-uses-from-steps.d.ts +12 -4
- package/dist/core/constants.d.ts +3 -1
- package/dist/core/fs/find-yaml-files-recursive.js +1 -1
- package/dist/core/interactive/prompt-update-selection.d.ts +3 -1
- package/dist/core/interactive/prompt-update-selection.js +9 -9
- package/dist/core/parsing/parse-action-reference.d.ts +16 -12
- package/dist/core/scan-github-actions.d.ts +4 -1
- package/dist/core/scan-github-actions.js +67 -67
- package/dist/core/versions/get-update-level.d.ts +3 -1
- package/dist/package.js +1 -1
- package/dist/types/action-update.d.ts +30 -10
- package/dist/types/composite-action-runs.d.ts +12 -4
- package/dist/types/composite-action-step.d.ts +24 -8
- package/dist/types/composite-action-structure.d.ts +21 -7
- package/dist/types/github-action.d.ts +27 -9
- package/dist/types/github-client-context.d.ts +24 -8
- package/dist/types/github-client.d.ts +24 -8
- package/dist/types/release-info.d.ts +24 -8
- package/dist/types/scan-result.d.ts +12 -4
- package/dist/types/tag-info.d.ts +15 -5
- package/dist/types/update-mode.d.ts +3 -1
- package/dist/types/workflow-job.d.ts +27 -9
- package/dist/types/workflow-step.d.ts +21 -7
- package/dist/types/workflow-structure.d.ts +15 -5
- package/package.json +3 -8
- package/readme.md +94 -71
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { ActionUpdate } from '../types/action-update';
|
|
2
|
+
import { ScanResult } from '../types/scan-result';
|
|
3
|
+
import { UpdateMode } from '../types/update-mode';
|
|
4
|
+
/**
|
|
5
|
+
* High-level status of a JSON report.
|
|
6
|
+
*/
|
|
7
|
+
export type JsonReportStatus = 'updates-available' | 'no-actions-found' | 'nothing-to-check' | 'up-to-date';
|
|
8
|
+
/**
|
|
9
|
+
* Options used to build a JSON report from the current CLI state.
|
|
10
|
+
*/
|
|
11
|
+
interface BuildJsonReportOptions {
|
|
12
|
+
/**
|
|
13
|
+
* Updates excluded by the selected update mode.
|
|
14
|
+
*/
|
|
15
|
+
blockedByMode: ActionUpdate[];
|
|
16
|
+
/**
|
|
17
|
+
* Number of actions that were actually checked after excludes.
|
|
18
|
+
*/
|
|
19
|
+
actionsToCheckCount: number;
|
|
20
|
+
/**
|
|
21
|
+
* Regex patterns supplied through `--exclude`.
|
|
22
|
+
*/
|
|
23
|
+
excludePatterns: string[];
|
|
24
|
+
/**
|
|
25
|
+
* Whether branch references were included in update checks.
|
|
26
|
+
*/
|
|
27
|
+
includeBranches: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Updates that remain actionable after all filters.
|
|
30
|
+
*/
|
|
31
|
+
outdated: ActionUpdate[];
|
|
32
|
+
/**
|
|
33
|
+
* Final report status.
|
|
34
|
+
*/
|
|
35
|
+
status: JsonReportStatus;
|
|
36
|
+
/**
|
|
37
|
+
* Updates skipped during processing, such as branch references.
|
|
38
|
+
*/
|
|
39
|
+
skipped: ActionUpdate[];
|
|
40
|
+
/**
|
|
41
|
+
* Aggregate scan result for the current run.
|
|
42
|
+
*/
|
|
43
|
+
scanResult: ScanResult;
|
|
44
|
+
/**
|
|
45
|
+
* Directories resolved for scanning.
|
|
46
|
+
*/
|
|
47
|
+
directories: string[];
|
|
48
|
+
/**
|
|
49
|
+
* Whether recursive scanning mode is enabled.
|
|
50
|
+
*/
|
|
51
|
+
recursive: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Effective update mode for the run.
|
|
54
|
+
*/
|
|
55
|
+
mode: UpdateMode;
|
|
56
|
+
/**
|
|
57
|
+
* Minimum age filter in days.
|
|
58
|
+
*/
|
|
59
|
+
minAge: number;
|
|
60
|
+
/**
|
|
61
|
+
* Working directory used for relative path normalization.
|
|
62
|
+
*/
|
|
63
|
+
cwd?: string;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Serialized update entry in the JSON report.
|
|
67
|
+
*/
|
|
68
|
+
interface JsonReportUpdate {
|
|
69
|
+
/**
|
|
70
|
+
* Reason why this entry was skipped, if any.
|
|
71
|
+
*/
|
|
72
|
+
skipReason: ActionUpdate['skipReason'] | null;
|
|
73
|
+
/**
|
|
74
|
+
* Processing status for this entry.
|
|
75
|
+
*/
|
|
76
|
+
status: NonNullable<ActionUpdate['status']>;
|
|
77
|
+
/**
|
|
78
|
+
* Version currently used in the workflow or action file.
|
|
79
|
+
*/
|
|
80
|
+
currentVersion: string | null;
|
|
81
|
+
/**
|
|
82
|
+
* Latest version found for this dependency.
|
|
83
|
+
*/
|
|
84
|
+
latestVersion: string | null;
|
|
85
|
+
/**
|
|
86
|
+
* Release publication date in ISO format.
|
|
87
|
+
*/
|
|
88
|
+
publishedAt: string | null;
|
|
89
|
+
/**
|
|
90
|
+
* Original action reference metadata.
|
|
91
|
+
*/
|
|
92
|
+
action: JsonReportAction;
|
|
93
|
+
/**
|
|
94
|
+
* Resolved SHA for the target version.
|
|
95
|
+
*/
|
|
96
|
+
latestSha: string | null;
|
|
97
|
+
/**
|
|
98
|
+
* Whether this update crosses a major version boundary.
|
|
99
|
+
*/
|
|
100
|
+
isBreaking: boolean;
|
|
101
|
+
/**
|
|
102
|
+
* Whether an update is available for this entry.
|
|
103
|
+
*/
|
|
104
|
+
hasUpdate: boolean;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Aggregate counts included in the JSON report.
|
|
108
|
+
*/
|
|
109
|
+
interface JsonReportSummary {
|
|
110
|
+
/**
|
|
111
|
+
* Number of composite actions discovered during scanning.
|
|
112
|
+
*/
|
|
113
|
+
totalCompositeActions: number;
|
|
114
|
+
/**
|
|
115
|
+
* Number of breaking updates among actionable updates.
|
|
116
|
+
*/
|
|
117
|
+
totalBreakingUpdates: number;
|
|
118
|
+
/**
|
|
119
|
+
* Number of actions checked after excludes.
|
|
120
|
+
*/
|
|
121
|
+
totalActionsChecked: number;
|
|
122
|
+
/**
|
|
123
|
+
* Number of updates filtered out by `--mode`.
|
|
124
|
+
*/
|
|
125
|
+
totalBlockedByMode: number;
|
|
126
|
+
/**
|
|
127
|
+
* Number of workflows discovered during scanning.
|
|
128
|
+
*/
|
|
129
|
+
totalWorkflows: number;
|
|
130
|
+
/**
|
|
131
|
+
* Total number of action references found during scanning.
|
|
132
|
+
*/
|
|
133
|
+
totalActions: number;
|
|
134
|
+
/**
|
|
135
|
+
* Number of skipped entries in the report.
|
|
136
|
+
*/
|
|
137
|
+
totalSkipped: number;
|
|
138
|
+
/**
|
|
139
|
+
* Number of actionable updates in the report.
|
|
140
|
+
*/
|
|
141
|
+
totalUpdates: number;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Serialized action reference included in each update entry.
|
|
145
|
+
*/
|
|
146
|
+
interface JsonReportAction {
|
|
147
|
+
/**
|
|
148
|
+
* Action reference type detected during scanning.
|
|
149
|
+
*/
|
|
150
|
+
type: ActionUpdate['action']['type'];
|
|
151
|
+
/**
|
|
152
|
+
* Original version or ref from the file, if available.
|
|
153
|
+
*/
|
|
154
|
+
version: string | null;
|
|
155
|
+
/**
|
|
156
|
+
* Relative or absolute file path for the action reference.
|
|
157
|
+
*/
|
|
158
|
+
file: string | null;
|
|
159
|
+
/**
|
|
160
|
+
* Line number of the action reference.
|
|
161
|
+
*/
|
|
162
|
+
line: number | null;
|
|
163
|
+
/**
|
|
164
|
+
* Original `uses` value, if available.
|
|
165
|
+
*/
|
|
166
|
+
uses: string | null;
|
|
167
|
+
/**
|
|
168
|
+
* Workflow job name, when applicable.
|
|
169
|
+
*/
|
|
170
|
+
job: string | null;
|
|
171
|
+
/**
|
|
172
|
+
* Full `owner/repo@ref` string, when available.
|
|
173
|
+
*/
|
|
174
|
+
ref: string | null;
|
|
175
|
+
/**
|
|
176
|
+
* Normalized action name.
|
|
177
|
+
*/
|
|
178
|
+
name: string;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Effective CLI options serialized into the report.
|
|
182
|
+
*/
|
|
183
|
+
interface JsonReportOptions {
|
|
184
|
+
/**
|
|
185
|
+
* Regex patterns supplied through `--exclude`.
|
|
186
|
+
*/
|
|
187
|
+
excludePatterns: string[];
|
|
188
|
+
/**
|
|
189
|
+
* Whether branch references were checked.
|
|
190
|
+
*/
|
|
191
|
+
includeBranches: boolean;
|
|
192
|
+
/**
|
|
193
|
+
* Resolved scan directories.
|
|
194
|
+
*/
|
|
195
|
+
directories: string[];
|
|
196
|
+
/**
|
|
197
|
+
* Whether recursive scanning mode is enabled.
|
|
198
|
+
*/
|
|
199
|
+
recursive: boolean;
|
|
200
|
+
/**
|
|
201
|
+
* Effective update mode.
|
|
202
|
+
*/
|
|
203
|
+
mode: UpdateMode;
|
|
204
|
+
/**
|
|
205
|
+
* Indicates that JSON mode never applies changes.
|
|
206
|
+
*/
|
|
207
|
+
reportOnly: true;
|
|
208
|
+
/**
|
|
209
|
+
* Minimum age filter in days.
|
|
210
|
+
*/
|
|
211
|
+
minAge: number;
|
|
212
|
+
/**
|
|
213
|
+
* Indicates that this payload came from `--json`.
|
|
214
|
+
*/
|
|
215
|
+
json: true;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Top-level machine-readable report emitted by `--json`.
|
|
219
|
+
*/
|
|
220
|
+
interface JsonReport {
|
|
221
|
+
/**
|
|
222
|
+
* Entries filtered out by the selected update mode.
|
|
223
|
+
*/
|
|
224
|
+
blockedByMode: JsonReportUpdate[];
|
|
225
|
+
/**
|
|
226
|
+
* Entries skipped during update checks.
|
|
227
|
+
*/
|
|
228
|
+
skipped: JsonReportUpdate[];
|
|
229
|
+
/**
|
|
230
|
+
* Actionable updates after filtering.
|
|
231
|
+
*/
|
|
232
|
+
updates: JsonReportUpdate[];
|
|
233
|
+
/**
|
|
234
|
+
* Effective options that shaped the report.
|
|
235
|
+
*/
|
|
236
|
+
options: JsonReportOptions;
|
|
237
|
+
/**
|
|
238
|
+
* Aggregate counts for the current run.
|
|
239
|
+
*/
|
|
240
|
+
summary: JsonReportSummary;
|
|
241
|
+
/**
|
|
242
|
+
* Overall outcome for the current run.
|
|
243
|
+
*/
|
|
244
|
+
status: JsonReportStatus;
|
|
245
|
+
/**
|
|
246
|
+
* Version of the JSON payload schema.
|
|
247
|
+
*/
|
|
248
|
+
schemaVersion: 1;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Build the machine-readable JSON report returned by `--json`.
|
|
252
|
+
*
|
|
253
|
+
* @param options - Current CLI state and computed update data.
|
|
254
|
+
* @returns Serializable JSON payload for stdout.
|
|
255
|
+
*/
|
|
256
|
+
export declare function buildJsonReport(options: BuildJsonReportOptions): JsonReport;
|
|
257
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { isAbsolute, relative, resolve } from "node:path";
|
|
2
|
+
function buildJsonReport(e) {
|
|
3
|
+
let n = resolve(e.cwd ?? process.cwd());
|
|
4
|
+
return {
|
|
5
|
+
summary: {
|
|
6
|
+
totalBreakingUpdates: e.outdated.filter((e) => e.isBreaking).length,
|
|
7
|
+
totalCompositeActions: e.scanResult.compositeActions.size,
|
|
8
|
+
totalWorkflows: e.scanResult.workflows.size,
|
|
9
|
+
totalActionsChecked: e.actionsToCheckCount,
|
|
10
|
+
totalBlockedByMode: e.blockedByMode.length,
|
|
11
|
+
totalActions: e.scanResult.actions.length,
|
|
12
|
+
totalUpdates: e.outdated.length,
|
|
13
|
+
totalSkipped: e.skipped.length
|
|
14
|
+
},
|
|
15
|
+
options: {
|
|
16
|
+
directories: e.directories.map((e) => serializeDirectoryPath(e, n)),
|
|
17
|
+
excludePatterns: e.excludePatterns,
|
|
18
|
+
includeBranches: e.includeBranches,
|
|
19
|
+
recursive: e.recursive,
|
|
20
|
+
minAge: e.minAge,
|
|
21
|
+
mode: e.mode,
|
|
22
|
+
reportOnly: !0,
|
|
23
|
+
json: !0
|
|
24
|
+
},
|
|
25
|
+
blockedByMode: e.blockedByMode.map((e) => serializeUpdate(e, n)),
|
|
26
|
+
updates: e.outdated.map((e) => serializeUpdate(e, n)),
|
|
27
|
+
skipped: e.skipped.map((e) => serializeUpdate(e, n)),
|
|
28
|
+
status: e.status,
|
|
29
|
+
schemaVersion: 1
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function serializeUpdate(e, n) {
|
|
33
|
+
return {
|
|
34
|
+
action: {
|
|
35
|
+
file: serializePath(e.action.file, n),
|
|
36
|
+
version: e.action.version ?? null,
|
|
37
|
+
line: e.action.line ?? null,
|
|
38
|
+
uses: e.action.uses ?? null,
|
|
39
|
+
job: e.action.job ?? null,
|
|
40
|
+
ref: e.action.ref ?? null,
|
|
41
|
+
name: e.action.name,
|
|
42
|
+
type: e.action.type
|
|
43
|
+
},
|
|
44
|
+
publishedAt: e.publishedAt?.toISOString() ?? null,
|
|
45
|
+
currentVersion: e.currentVersion,
|
|
46
|
+
skipReason: e.skipReason ?? null,
|
|
47
|
+
latestVersion: e.latestVersion,
|
|
48
|
+
isBreaking: e.isBreaking,
|
|
49
|
+
status: e.status ?? "ok",
|
|
50
|
+
hasUpdate: e.hasUpdate,
|
|
51
|
+
latestSha: e.latestSha
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function serializePath(r, i, a = null) {
|
|
55
|
+
if (!r) return null;
|
|
56
|
+
if (!isAbsolute(r)) return r;
|
|
57
|
+
let o = relative(i, r);
|
|
58
|
+
return o === "" ? a ?? r : o.startsWith("..") || isAbsolute(o) ? r : o;
|
|
59
|
+
}
|
|
60
|
+
function serializeDirectoryPath(r, i) {
|
|
61
|
+
let a = relative(i, r);
|
|
62
|
+
return a === "" ? "." : a.startsWith("..") || isAbsolute(a) ? r : a;
|
|
63
|
+
}
|
|
64
|
+
export { buildJsonReport };
|
package/dist/cli/index.d.ts
CHANGED
package/dist/cli/index.js
CHANGED
|
@@ -8,127 +8,186 @@ import { getUpdateLevel } from "../core/versions/get-update-level.js";
|
|
|
8
8
|
import { applyUpdates } from "../core/ast/update/apply-updates.js";
|
|
9
9
|
import { printSkippedWarning } from "./print-skipped-warning.js";
|
|
10
10
|
import { normalizeUpdateMode } from "./normalize-update-mode.js";
|
|
11
|
+
import { validateCliOptions } from "./validate-cli-options.js";
|
|
11
12
|
import { shouldIgnore } from "../core/ignore/should-ignore.js";
|
|
12
13
|
import { checkUpdates } from "../core/api/check-updates.js";
|
|
13
14
|
import { mergeScanResults } from "./merge-scan-results.js";
|
|
14
15
|
import { printModeWarning } from "./print-mode-warning.js";
|
|
15
16
|
import { scanRecursive } from "../core/scan-recursive.js";
|
|
17
|
+
import { buildJsonReport } from "./build-json-report.js";
|
|
16
18
|
import { scanGitHubActions } from "../core/scan-github-actions.js";
|
|
17
19
|
import "../core/index.js";
|
|
18
20
|
import { version } from "../package.js";
|
|
19
21
|
import { createSpinner } from "nanospinner";
|
|
22
|
+
import { resolve } from "node:path";
|
|
20
23
|
import "node:worker_threads";
|
|
21
24
|
import pc from "picocolors";
|
|
22
25
|
import cac from "cac";
|
|
23
26
|
function run() {
|
|
24
|
-
let
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
recursive: v.recursive,
|
|
27
|
+
let C = cac("actions-up");
|
|
28
|
+
C.help().version(version).option("--dir <directory>", "Directory to scan (repeatable). Default: .github, or . with --recursive").option("--dry-run", "Preview changes without applying them").option("--exclude <regex>", "Exclude actions by regex (repeatable)").option("--include-branches", "Also check actions pinned to branches (default: false)").option("--json", "Output update information as machine-readable JSON").option("--min-age <days>", "Minimum age in days for updates (default: 0)", { default: 0 }).option("--mode <mode>", "Update mode: major, minor, or patch (default: major)", { default: "major" }).option("--recursive, -r", "Recursively scan directories for YAML files").option("--yes, -y", "Skip all confirmations").command("", "Update GitHub Actions").action(async (b) => {
|
|
29
|
+
let S = b.json ?? !1, C = null, w = resolveScanDirectories({
|
|
30
|
+
recursive: b.recursive,
|
|
29
31
|
cwd: process.cwd(),
|
|
30
|
-
dir:
|
|
31
|
-
});
|
|
32
|
+
dir: b.dir
|
|
33
|
+
}), T = w.map(({ root: e, dir: f }) => resolve(e, f)), E = b.includeBranches ?? !1, D = normalizeUpdateMode(b.mode), O = [];
|
|
34
|
+
Array.isArray(b.exclude) ? O.push(...b.exclude) : typeof b.exclude == "string" && O.push(b.exclude);
|
|
35
|
+
let k = O.flatMap((e) => e.split(",")).map((e) => e.trim()).filter(Boolean);
|
|
32
36
|
try {
|
|
33
|
-
|
|
34
|
-
|
|
37
|
+
validateCliOptions({
|
|
38
|
+
yes: b.yes,
|
|
39
|
+
json: S
|
|
40
|
+
}), S || (console.info(pc.cyan("\n🚀 Actions Up!\n")), C = createSpinner("Scanning GitHub Actions...").start());
|
|
41
|
+
function g({ actionsToCheckCount: e, blockedByMode: f = [], outdated: p = [], skipped: m = [], scanResult: h, status: g }) {
|
|
42
|
+
process.stdout.write(`${JSON.stringify(buildJsonReport({
|
|
43
|
+
recursive: b.recursive ?? !1,
|
|
44
|
+
excludePatterns: k,
|
|
45
|
+
directories: T,
|
|
46
|
+
minAge: b.minAge,
|
|
47
|
+
actionsToCheckCount: e,
|
|
48
|
+
includeBranches: E,
|
|
49
|
+
blockedByMode: f,
|
|
50
|
+
scanResult: h,
|
|
51
|
+
outdated: p,
|
|
52
|
+
skipped: m,
|
|
53
|
+
status: g,
|
|
54
|
+
mode: D
|
|
55
|
+
}), null, 2)}\n`);
|
|
56
|
+
}
|
|
57
|
+
let y = mergeScanResults(b.recursive ? await Promise.all(w.map(({ root: e, dir: f }) => scanRecursive(e, f))) : await Promise.all(w.map(({ root: e, dir: f }) => scanGitHubActions(e, f)))), x = y.actions.length, O = y.workflows.size, A = y.compositeActions.size;
|
|
58
|
+
if (C?.success(`Found ${pc.yellow(x)} actions in ${pc.yellow(O)} workflows and ${pc.yellow(A)} composite actions`), x === 0) {
|
|
59
|
+
if (S) {
|
|
60
|
+
g({
|
|
61
|
+
status: "no-actions-found",
|
|
62
|
+
actionsToCheckCount: 0,
|
|
63
|
+
scanResult: y
|
|
64
|
+
});
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
35
67
|
console.info(pc.green("\n✨ No GitHub Actions found in this repository"));
|
|
36
68
|
return;
|
|
37
69
|
}
|
|
38
|
-
let
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
let { name: d } = t;
|
|
45
|
-
for (let t of u) if (t.test(d)) return !1;
|
|
70
|
+
let j = y.actions;
|
|
71
|
+
if (k.length > 0) {
|
|
72
|
+
let { parseExcludePatterns: e } = await import("../core/filters/parse-exclude-patterns.js"), f = e(k);
|
|
73
|
+
f.length > 0 && (j = j.filter((e) => {
|
|
74
|
+
let { name: p } = e;
|
|
75
|
+
for (let e of f) if (e.test(p)) return !1;
|
|
46
76
|
return !0;
|
|
47
77
|
}));
|
|
48
78
|
}
|
|
49
|
-
if (
|
|
50
|
-
|
|
79
|
+
if (S || (C = createSpinner("Checking for updates...").start()), j.length === 0) {
|
|
80
|
+
if (C?.success("No actions to check after excludes"), S) {
|
|
81
|
+
g({
|
|
82
|
+
status: "nothing-to-check",
|
|
83
|
+
actionsToCheckCount: 0,
|
|
84
|
+
scanResult: y
|
|
85
|
+
});
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
console.info(pc.green("\n✨ Nothing to check after excludes\n"));
|
|
51
89
|
return;
|
|
52
90
|
}
|
|
53
|
-
let
|
|
54
|
-
client:
|
|
55
|
-
includeBranches:
|
|
56
|
-
}),
|
|
57
|
-
await Promise.all(
|
|
58
|
-
await shouldIgnore(
|
|
91
|
+
let M = process.env.GITHUB_TOKEN, N = createGitHubClient(M), P = await checkUpdates(j, M, {
|
|
92
|
+
client: N,
|
|
93
|
+
includeBranches: E
|
|
94
|
+
}), F = [];
|
|
95
|
+
await Promise.all(P.map(async (e) => {
|
|
96
|
+
await shouldIgnore(e.action.file, e.action.line) || F.push(e);
|
|
59
97
|
}));
|
|
60
|
-
let
|
|
61
|
-
|
|
62
|
-
let
|
|
63
|
-
if (
|
|
64
|
-
let
|
|
65
|
-
let
|
|
66
|
-
if (isSha(
|
|
67
|
-
let
|
|
68
|
-
|
|
98
|
+
let I = F.filter((e) => e.status === "skipped"), L = F.filter((e) => e.hasUpdate), R = b.minAge * 24 * 60 * 60 * 1e3, z = Date.now();
|
|
99
|
+
L = L.filter((e) => e.publishedAt ? z - e.publishedAt.getTime() >= R : !0);
|
|
100
|
+
let B = [];
|
|
101
|
+
if (D !== "major") {
|
|
102
|
+
let p = /* @__PURE__ */ new Map(), h = /* @__PURE__ */ new Map(), g = /* @__PURE__ */ new Map(), _ = await Promise.all(L.map(async (p) => {
|
|
103
|
+
let m = p.currentVersion;
|
|
104
|
+
if (isSha(p.currentVersion)) {
|
|
105
|
+
let f = await readInlineVersionComment(p.action.file, p.action.line, g);
|
|
106
|
+
f && (m = f);
|
|
69
107
|
}
|
|
70
|
-
let
|
|
108
|
+
let h = getUpdateLevel(m, p.latestVersion);
|
|
71
109
|
return {
|
|
72
|
-
effectiveCurrentVersion:
|
|
73
|
-
allowed:
|
|
74
|
-
update:
|
|
110
|
+
effectiveCurrentVersion: m,
|
|
111
|
+
allowed: D === "minor" ? h === "minor" || h === "patch" || h === "none" : h === "patch" || h === "none",
|
|
112
|
+
update: p
|
|
75
113
|
};
|
|
76
|
-
})),
|
|
77
|
-
if (
|
|
78
|
-
let
|
|
79
|
-
currentVersion:
|
|
80
|
-
actionName:
|
|
81
|
-
tagsCache:
|
|
82
|
-
shaCache:
|
|
83
|
-
mode:
|
|
114
|
+
})), v = [], y = await Promise.all(_.map(async (e) => {
|
|
115
|
+
if (e.allowed) return { update: e.update };
|
|
116
|
+
let f = await getCompatibleUpdate(N, {
|
|
117
|
+
currentVersion: e.effectiveCurrentVersion,
|
|
118
|
+
actionName: e.update.action.name,
|
|
119
|
+
tagsCache: p,
|
|
120
|
+
shaCache: h,
|
|
121
|
+
mode: D
|
|
84
122
|
});
|
|
85
|
-
return
|
|
86
|
-
...
|
|
87
|
-
latestVersion:
|
|
88
|
-
latestSha:
|
|
123
|
+
return f ? { update: {
|
|
124
|
+
...e.update,
|
|
125
|
+
latestVersion: f.version,
|
|
126
|
+
latestSha: f.sha,
|
|
89
127
|
isBreaking: !1,
|
|
90
128
|
hasUpdate: !0
|
|
91
|
-
} } : { blocked:
|
|
129
|
+
} } : { blocked: e.update };
|
|
92
130
|
}));
|
|
93
|
-
for (let
|
|
94
|
-
if (
|
|
95
|
-
|
|
131
|
+
for (let e of y) {
|
|
132
|
+
if (e.update) {
|
|
133
|
+
v.push(e.update);
|
|
96
134
|
continue;
|
|
97
135
|
}
|
|
98
|
-
|
|
136
|
+
B.push(e.blocked);
|
|
137
|
+
}
|
|
138
|
+
L = v;
|
|
139
|
+
}
|
|
140
|
+
let V = L.filter((e) => e.isBreaking);
|
|
141
|
+
if (L.length === 0) {
|
|
142
|
+
if (C?.success("All actions are up to date!"), S) {
|
|
143
|
+
g({
|
|
144
|
+
actionsToCheckCount: j.length,
|
|
145
|
+
status: "up-to-date",
|
|
146
|
+
blockedByMode: B,
|
|
147
|
+
scanResult: y,
|
|
148
|
+
skipped: I
|
|
149
|
+
});
|
|
150
|
+
return;
|
|
99
151
|
}
|
|
100
|
-
|
|
152
|
+
I.length > 0 && printSkippedWarning(I, E), B.length > 0 && printModeWarning(B, D), console.info(pc.green("\n✨ Everything is already at the latest version!\n"));
|
|
153
|
+
return;
|
|
101
154
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
155
|
+
if (C?.success(`Found ${pc.yellow(L.length)} updates available${V.length > 0 ? ` (${pc.redBright(V.length)} breaking)` : ""}`), S) {
|
|
156
|
+
g({
|
|
157
|
+
actionsToCheckCount: j.length,
|
|
158
|
+
status: "updates-available",
|
|
159
|
+
blockedByMode: B,
|
|
160
|
+
scanResult: y,
|
|
161
|
+
outdated: L,
|
|
162
|
+
skipped: I
|
|
163
|
+
});
|
|
105
164
|
return;
|
|
106
165
|
}
|
|
107
|
-
if (
|
|
166
|
+
if (I.length > 0 && printSkippedWarning(I, E), B.length > 0 && printModeWarning(B, D), b.dryRun) {
|
|
108
167
|
console.info(pc.yellow("\n📋 Dry Run - No changes will be made\n"));
|
|
109
|
-
for (let
|
|
110
|
-
console.info(pc.gray(`\n${
|
|
168
|
+
for (let e of L) console.info(`${pc.cyan(e.action.file ?? "unknown")}:\n${e.action.name}: ${pc.redBright(e.currentVersion)} → ${pc.green(e.latestVersion)} ${e.latestSha ? pc.gray(`(${e.latestSha.slice(0, 7)})`) : ""}\n`);
|
|
169
|
+
console.info(pc.gray(`\n${L.length} actions would be updated\n`));
|
|
111
170
|
return;
|
|
112
171
|
}
|
|
113
|
-
if (
|
|
114
|
-
let
|
|
115
|
-
if (
|
|
172
|
+
if (b.yes) {
|
|
173
|
+
let e = L.filter((e) => e.latestSha);
|
|
174
|
+
if (e.length === 0) {
|
|
116
175
|
console.info(pc.yellow("\n⚠️ No actions with SHA available for update\n"));
|
|
117
176
|
return;
|
|
118
177
|
}
|
|
119
|
-
console.info(pc.yellow(`\n🔄 Updating ${
|
|
178
|
+
console.info(pc.yellow(`\n🔄 Updating ${e.length} actions...\n`)), await applyUpdates(e), console.info(pc.green("\n✓ Updates applied successfully!"));
|
|
120
179
|
} else {
|
|
121
|
-
(
|
|
122
|
-
let
|
|
123
|
-
if (!
|
|
180
|
+
(I.length > 0 || B.length > 0) && console.info("");
|
|
181
|
+
let e = await promptUpdateSelection(L, { showAge: b.minAge > 0 });
|
|
182
|
+
if (!e || e.length === 0) {
|
|
124
183
|
console.info(pc.gray("\nNo updates applied"));
|
|
125
184
|
return;
|
|
126
185
|
}
|
|
127
|
-
console.info(pc.yellow(`\n🔄 Updating ${
|
|
186
|
+
console.info(pc.yellow(`\n🔄 Updating ${e.length} selected actions...\n`)), await applyUpdates(e), console.info(pc.green("\n✓ Updates applied successfully!"));
|
|
128
187
|
}
|
|
129
|
-
} catch (
|
|
130
|
-
|
|
188
|
+
} catch (e) {
|
|
189
|
+
C?.error("Failed"), e instanceof Error && e.name === "GitHubRateLimitError" ? (console.error(pc.yellow("\n⚠️ Rate Limit Exceeded\n")), console.error(e.message), console.error(pc.gray("\nExample: GITHUB_TOKEN=ghp_xxxx actions-up\n"))) : console.error(pc.redBright("\nError:"), e instanceof Error ? e.message : String(e)), process.exit(1);
|
|
131
190
|
}
|
|
132
|
-
}),
|
|
191
|
+
}), C.parse();
|
|
133
192
|
}
|
|
134
193
|
export { run };
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* Options for resolving scan directories from CLI flags.
|
|
3
|
+
*/
|
|
2
4
|
interface ResolveScanDirectoriesOptions {
|
|
3
5
|
dir?: string[] | string;
|
|
4
6
|
recursive?: boolean;
|
|
5
7
|
cwd: string;
|
|
6
8
|
}
|
|
7
|
-
/**
|
|
9
|
+
/**
|
|
10
|
+
* Resolved directory with root and relative directory.
|
|
11
|
+
*/
|
|
8
12
|
interface ResolvedDirectory {
|
|
9
13
|
root: string;
|
|
10
14
|
dir: string;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal subset of CLI flags that require cross-option validation.
|
|
3
|
+
*/
|
|
4
|
+
interface ValidateCliOptionsInput {
|
|
5
|
+
/**
|
|
6
|
+
* Whether JSON report mode is enabled.
|
|
7
|
+
*/
|
|
8
|
+
json?: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Whether auto-apply mode is enabled.
|
|
11
|
+
*/
|
|
12
|
+
yes?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Validate combinations of CLI flags before running the pipeline.
|
|
16
|
+
*
|
|
17
|
+
* @param options - Parsed CLI flags relevant to cross-option validation.
|
|
18
|
+
*/
|
|
19
|
+
export declare function validateCliOptions(options: ValidateCliOptionsInput): void;
|
|
20
|
+
export {};
|