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