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
|
@@ -4,60 +4,60 @@ import { GITHUB_DIRECTORY } from "../constants.js";
|
|
|
4
4
|
import { isSha } from "../versions/is-sha.js";
|
|
5
5
|
import { stripAnsi } from "./strip-ansi.js";
|
|
6
6
|
import { padString } from "./pad-string.js";
|
|
7
|
+
import path from "node:path";
|
|
7
8
|
import "node:worker_threads";
|
|
8
9
|
import pc from "picocolors";
|
|
9
10
|
import enquirer from "enquirer";
|
|
10
|
-
import path from "node:path";
|
|
11
11
|
var MIN_ACTION_WIDTH = 40, MIN_JOB_WIDTH = 4, MIN_CURRENT_WIDTH = 16, MAX_VERSION_WIDTH = 7;
|
|
12
|
-
async function promptUpdateSelection(
|
|
13
|
-
let { showAge:
|
|
14
|
-
if (
|
|
15
|
-
let
|
|
16
|
-
if (
|
|
17
|
-
let
|
|
18
|
-
for (let [
|
|
19
|
-
let
|
|
20
|
-
|
|
21
|
-
let
|
|
22
|
-
|
|
23
|
-
update:
|
|
24
|
-
index:
|
|
25
|
-
}),
|
|
12
|
+
async function promptUpdateSelection(b, S = {}) {
|
|
13
|
+
let { showAge: C = !1 } = S;
|
|
14
|
+
if (b.length === 0) return null;
|
|
15
|
+
let w = b.filter((e) => e.hasUpdate);
|
|
16
|
+
if (w.length === 0) return console.info(pc.green("✓ All actions are up to date!")), null;
|
|
17
|
+
let T = /* @__PURE__ */ new Map();
|
|
18
|
+
for (let [e, c] of w.entries()) {
|
|
19
|
+
let u = c.action.file ?? "unknown file", d = path.relative(path.join(process.cwd(), GITHUB_DIRECTORY), u);
|
|
20
|
+
d === "" && (d = u);
|
|
21
|
+
let f = T.get(d) ?? [];
|
|
22
|
+
f.push({
|
|
23
|
+
update: c,
|
|
24
|
+
index: e
|
|
25
|
+
}), T.set(d, f);
|
|
26
26
|
}
|
|
27
|
-
let
|
|
28
|
-
let
|
|
29
|
-
if (!
|
|
30
|
-
versionForPadding:
|
|
31
|
-
effectiveForDiff:
|
|
32
|
-
shortSha:
|
|
33
|
-
display:
|
|
27
|
+
let E = await Promise.all(w.map(async (c) => {
|
|
28
|
+
let l = formatVersionOrSha(c.currentVersion), d = c.currentVersion ?? void 0, f = null, p = null;
|
|
29
|
+
if (!c.currentVersion || !isSha(c.currentVersion)) return {
|
|
30
|
+
versionForPadding: f,
|
|
31
|
+
effectiveForDiff: d,
|
|
32
|
+
shortSha: p,
|
|
33
|
+
display: l
|
|
34
34
|
};
|
|
35
|
-
let
|
|
36
|
-
return
|
|
37
|
-
versionForPadding:
|
|
38
|
-
effectiveForDiff:
|
|
39
|
-
shortSha:
|
|
40
|
-
display:
|
|
35
|
+
let m = await readInlineVersionComment(c.action.file, c.action.line);
|
|
36
|
+
return m && (p = c.currentVersion.slice(0, 7), f = formatVersionOrSha(m), l = f, d = m), {
|
|
37
|
+
versionForPadding: f,
|
|
38
|
+
effectiveForDiff: d,
|
|
39
|
+
shortSha: p,
|
|
40
|
+
display: l
|
|
41
41
|
};
|
|
42
|
-
})),
|
|
43
|
-
for (let [
|
|
44
|
-
let
|
|
45
|
-
if (
|
|
46
|
-
let
|
|
47
|
-
|
|
42
|
+
})), D = [], O = stripAnsi("Action").length, k = stripAnsi("Current").length, A = stripAnsi("Job").length, j = 0, M = !1;
|
|
43
|
+
for (let [e, l] of w.entries()) {
|
|
44
|
+
let u = l.action.name, p = E[e], h = p.display, g = l.action.job ?? "–";
|
|
45
|
+
if (O = Math.max(O, u.length), k = Math.max(k, stripAnsi(h).length, p.versionForPadding && p.shortSha ? stripAnsi(`${padString(p.versionForPadding, j + 1)}${pc.gray(`(${p.shortSha})`)}`).length : 0), A = Math.max(A, g.length), l.latestVersion) {
|
|
46
|
+
let u = formatVersion(l.targetRefStyle === "tag" && l.targetRef ? l.targetRef : l.latestVersion, E[e]?.effectiveForDiff ?? l.currentVersion);
|
|
47
|
+
j = Math.max(j, stripAnsi(u).length);
|
|
48
48
|
}
|
|
49
|
-
let
|
|
50
|
-
|
|
49
|
+
let _ = E[e]?.versionForPadding;
|
|
50
|
+
_ && (j = Math.max(j, stripAnsi(_).length)), l.publishedAt && (M = !0);
|
|
51
51
|
}
|
|
52
|
-
let
|
|
53
|
-
for (let [
|
|
54
|
-
let
|
|
55
|
-
if (!
|
|
56
|
-
console.warn(`Unexpected missing group for file: ${
|
|
52
|
+
let N = Math.max(O, MIN_ACTION_WIDTH), P = Math.max(k, MIN_CURRENT_WIDTH), F = Math.max(A, MIN_JOB_WIDTH), I = Math.min(j, MAX_VERSION_WIDTH), L = I + 1 + 9, R = C && M ? 6 : 0, z = [...T.keys()].toSorted();
|
|
53
|
+
for (let [e, l] of z.entries()) {
|
|
54
|
+
let u = T.get(l);
|
|
55
|
+
if (!u) {
|
|
56
|
+
console.warn(`Unexpected missing group for file: ${l}`);
|
|
57
57
|
continue;
|
|
58
58
|
}
|
|
59
|
-
let
|
|
60
|
-
|
|
59
|
+
let d = [], p = u;
|
|
60
|
+
d.push({
|
|
61
61
|
current: "Current",
|
|
62
62
|
action: "Action",
|
|
63
63
|
target: "Target",
|
|
@@ -65,74 +65,74 @@ async function promptUpdateSelection(g, v = {}) {
|
|
|
65
65
|
job: "Job",
|
|
66
66
|
age: "Age"
|
|
67
67
|
});
|
|
68
|
-
for (let { update:
|
|
69
|
-
let
|
|
70
|
-
|
|
71
|
-
let
|
|
72
|
-
if (
|
|
73
|
-
let
|
|
74
|
-
|
|
68
|
+
for (let { update: e, index: l } of p) {
|
|
69
|
+
let u = hasResolvedTarget(e), p = E[l], h = p.display;
|
|
70
|
+
p.versionForPadding && p.shortSha && (h = `${padString(p.versionForPadding, I + 1)}${pc.gray(`(${p.shortSha})`)}`);
|
|
71
|
+
let g = p.effectiveForDiff ?? e.currentVersion, _ = formatVersion(getTargetVersion(e), g), v = e.action.name;
|
|
72
|
+
if (getResolvedTargetStyle(e) === "sha" && getResolvedTarget(e)) {
|
|
73
|
+
let c = getResolvedTarget(e).slice(0, 7);
|
|
74
|
+
_ = `${padString(_, I + 1)}${pc.gray(`(${c})`)}`;
|
|
75
75
|
}
|
|
76
|
-
|
|
77
|
-
let
|
|
78
|
-
|
|
79
|
-
job:
|
|
80
|
-
age:
|
|
81
|
-
action:
|
|
82
|
-
target:
|
|
76
|
+
u || (_ = pc.gray(_), h = pc.gray(h), v = pc.gray(v));
|
|
77
|
+
let y = e.action.job ?? "–", b = formatAge(e.publishedAt);
|
|
78
|
+
d.push({
|
|
79
|
+
job: u ? y : pc.gray(y),
|
|
80
|
+
age: u ? b : pc.gray(b),
|
|
81
|
+
action: v,
|
|
82
|
+
target: _,
|
|
83
83
|
arrow: "❯",
|
|
84
|
-
current:
|
|
84
|
+
current: h
|
|
85
85
|
});
|
|
86
86
|
}
|
|
87
|
-
let
|
|
88
|
-
for (let [
|
|
89
|
-
let
|
|
90
|
-
targetWidth:
|
|
91
|
-
currentWidth:
|
|
92
|
-
actionWidth:
|
|
93
|
-
ageWidth:
|
|
94
|
-
jobWidth:
|
|
95
|
-
row:
|
|
87
|
+
let h = Math.max(N, MIN_ACTION_WIDTH), y = Math.max(P, MIN_CURRENT_WIDTH), b = Math.max(F, MIN_JOB_WIDTH), x = [];
|
|
88
|
+
for (let [e, c] of d.entries()) {
|
|
89
|
+
let l = e === 0, u = formatTableRow({
|
|
90
|
+
targetWidth: L,
|
|
91
|
+
currentWidth: y,
|
|
92
|
+
actionWidth: h,
|
|
93
|
+
ageWidth: R,
|
|
94
|
+
jobWidth: b,
|
|
95
|
+
row: c
|
|
96
96
|
});
|
|
97
|
-
if (
|
|
98
|
-
message: pc.gray(` ○ ${
|
|
97
|
+
if (l) x.push({
|
|
98
|
+
message: pc.gray(` ○ ${u}`),
|
|
99
99
|
role: "separator",
|
|
100
100
|
indent: "",
|
|
101
101
|
name: ""
|
|
102
102
|
});
|
|
103
103
|
else {
|
|
104
|
-
let { update:
|
|
105
|
-
|
|
106
|
-
message:
|
|
107
|
-
value: String(
|
|
108
|
-
|
|
109
|
-
|
|
104
|
+
let { update: c, index: l } = p[e - 1], d = hasResolvedTarget(c), f = d && !c.isBreaking;
|
|
105
|
+
x.push({
|
|
106
|
+
message: u,
|
|
107
|
+
value: String(l),
|
|
108
|
+
disabled: !d,
|
|
109
|
+
name: String(l),
|
|
110
110
|
indent: "",
|
|
111
|
-
enabled:
|
|
111
|
+
enabled: f
|
|
112
112
|
});
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
|
-
|
|
116
|
-
message: pc.gray(
|
|
117
|
-
value: `label|${
|
|
118
|
-
choices:
|
|
119
|
-
name: `label|${
|
|
115
|
+
D.push({
|
|
116
|
+
message: pc.gray(l),
|
|
117
|
+
value: `label|${l}`,
|
|
118
|
+
choices: x,
|
|
119
|
+
name: `label|${l}`,
|
|
120
120
|
isGroupLabel: !0,
|
|
121
121
|
enabled: !1
|
|
122
|
-
}),
|
|
122
|
+
}), e < z.length - 1 && D.push({
|
|
123
123
|
role: "separator",
|
|
124
124
|
message: " ",
|
|
125
125
|
name: ""
|
|
126
126
|
});
|
|
127
127
|
}
|
|
128
128
|
try {
|
|
129
|
-
let
|
|
130
|
-
indicator(
|
|
131
|
-
if (
|
|
132
|
-
let
|
|
133
|
-
return ` ${pc.gray(
|
|
129
|
+
let e = {
|
|
130
|
+
indicator(e, c) {
|
|
131
|
+
if (c.isGroupLabel) {
|
|
132
|
+
let e = (c.choices ?? []).filter((e) => !("role" in e)), l = e.length, u = e.filter((e) => !!e.enabled).length === l ? "●" : "○";
|
|
133
|
+
return ` ${pc.gray(u)}`;
|
|
134
134
|
}
|
|
135
|
-
return ` ${
|
|
135
|
+
return ` ${c.enabled ? "●" : "○"}`;
|
|
136
136
|
},
|
|
137
137
|
message: `Choose which actions to update (Press ${pc.cyan("<space>")} to select, ${pc.cyan("<a>")} to toggle all, ${pc.cyan("<i>")} to invert selection)`,
|
|
138
138
|
styles: {
|
|
@@ -153,44 +153,56 @@ async function promptUpdateSelection(g, v = {}) {
|
|
|
153
153
|
type: "multiselect",
|
|
154
154
|
name: "selected",
|
|
155
155
|
pointer: "❯",
|
|
156
|
-
choices:
|
|
157
|
-
}, { selected:
|
|
158
|
-
for (let
|
|
159
|
-
if (
|
|
160
|
-
let
|
|
161
|
-
for (let { update:
|
|
156
|
+
choices: D
|
|
157
|
+
}, { selected: c } = await enquirer.prompt(e), l = /* @__PURE__ */ new Set();
|
|
158
|
+
for (let e of c) {
|
|
159
|
+
if (e.startsWith("label|")) {
|
|
160
|
+
let c = e.slice(6), u = T.get(c) ?? [];
|
|
161
|
+
for (let { update: e, index: c } of u) hasResolvedTarget(e) && l.add(c);
|
|
162
162
|
continue;
|
|
163
163
|
}
|
|
164
|
-
let
|
|
165
|
-
Number.isFinite(
|
|
164
|
+
let c = Number.parseInt(e, 10);
|
|
165
|
+
Number.isFinite(c) && l.add(c);
|
|
166
166
|
}
|
|
167
|
-
let
|
|
168
|
-
for (let [
|
|
169
|
-
return
|
|
170
|
-
} catch (
|
|
171
|
-
if (
|
|
172
|
-
throw console.error(pc.red("Unexpected error during selection:"),
|
|
167
|
+
let u = [];
|
|
168
|
+
for (let [e, c] of w.entries()) l.has(e) && hasResolvedTarget(c) && u.push(c);
|
|
169
|
+
return u.length === 0 ? (console.info(pc.yellow("\nNo actions selected")), null) : u;
|
|
170
|
+
} catch (e) {
|
|
171
|
+
if (e instanceof Error && (e.message.includes("cancelled") || e.message.includes("ESC") || e.name === "ExitPromptError")) return logSelectionCancelled(), null;
|
|
172
|
+
throw console.error(pc.red("Unexpected error during selection:"), e), e;
|
|
173
173
|
}
|
|
174
174
|
}
|
|
175
|
-
function formatAge(
|
|
176
|
-
if (!
|
|
177
|
-
let
|
|
178
|
-
return
|
|
175
|
+
function formatAge(e) {
|
|
176
|
+
if (!e) return "";
|
|
177
|
+
let c = Date.now() - e.getTime(), l = Math.floor(c / (1e3 * 60 * 60)), u = Math.floor(l / 24), d = Math.floor(u / 7), f = u % 7;
|
|
178
|
+
return d >= 1 ? f > 0 ? `${d}w ${f}d` : `${d}w` : u >= 1 ? `${u}d` : `${l}h`;
|
|
179
179
|
}
|
|
180
|
-
function formatTableRow(
|
|
181
|
-
let { currentWidth:
|
|
182
|
-
padString(
|
|
183
|
-
padString(
|
|
184
|
-
padString(
|
|
185
|
-
|
|
186
|
-
padString(
|
|
180
|
+
function formatTableRow(e) {
|
|
181
|
+
let { currentWidth: c, actionWidth: l, targetWidth: u, jobWidth: d, ageWidth: p, row: m } = e, h = [
|
|
182
|
+
padString(m.action, l),
|
|
183
|
+
padString(m.job, d),
|
|
184
|
+
padString(m.current, c),
|
|
185
|
+
m.arrow,
|
|
186
|
+
padString(m.target, u)
|
|
187
187
|
];
|
|
188
|
-
return
|
|
188
|
+
return p > 0 && h.push(m.age), h.join(" ").replace(/\s+$/u, "");
|
|
189
|
+
}
|
|
190
|
+
function formatVersionOrSha(e) {
|
|
191
|
+
return e ? isSha(e) ? e.slice(0, 7) : e.replace(/^v/u, "") : pc.gray("unknown");
|
|
189
192
|
}
|
|
190
|
-
function
|
|
191
|
-
return
|
|
193
|
+
function getTargetVersion(e) {
|
|
194
|
+
return getResolvedTargetStyle(e) === "tag" && getResolvedTarget(e) ? getResolvedTarget(e) : e.latestVersion;
|
|
195
|
+
}
|
|
196
|
+
function getResolvedTargetStyle(e) {
|
|
197
|
+
return e.targetRefStyle ? e.targetRefStyle : e.latestSha ? "sha" : null;
|
|
198
|
+
}
|
|
199
|
+
function getResolvedTarget(e) {
|
|
200
|
+
return e.targetRef ? e.targetRef : e.latestSha;
|
|
192
201
|
}
|
|
193
202
|
function logSelectionCancelled() {
|
|
194
203
|
console.info(`\r\u001B[K${pc.yellow("Selection cancelled")}`);
|
|
195
204
|
}
|
|
205
|
+
function hasResolvedTarget(e) {
|
|
206
|
+
return !!getResolvedTarget(e);
|
|
207
|
+
}
|
|
196
208
|
export { promptUpdateSelection };
|
|
@@ -2,17 +2,17 @@ import { ACTIONS_DIRECTORY, GITHUB_DIRECTORY, WORKFLOWS_DIRECTORY } from "./cons
|
|
|
2
2
|
import { isYamlFile } from "./fs/is-yaml-file.js";
|
|
3
3
|
import { scanWorkflowFile } from "./scan-workflow-file.js";
|
|
4
4
|
import { scanActionFile } from "./scan-action-file.js";
|
|
5
|
-
import { readFile, readdir, stat } from "node:fs/promises";
|
|
6
5
|
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
7
|
-
|
|
6
|
+
import { readFile, readdir, stat } from "node:fs/promises";
|
|
7
|
+
async function scanGitHubActions(p = process.cwd(), m = GITHUB_DIRECTORY) {
|
|
8
8
|
let h = {
|
|
9
9
|
compositeActions: /* @__PURE__ */ new Map(),
|
|
10
10
|
workflows: /* @__PURE__ */ new Map(),
|
|
11
11
|
actions: []
|
|
12
|
-
}, g = resolve(
|
|
13
|
-
function _(e,
|
|
14
|
-
let
|
|
15
|
-
return
|
|
12
|
+
}, g = resolve(p);
|
|
13
|
+
function _(e, a) {
|
|
14
|
+
let o = relative(e, a);
|
|
15
|
+
return o !== "" && !o.startsWith("..") && !isAbsolute(o);
|
|
16
16
|
}
|
|
17
17
|
let v = join(g, m);
|
|
18
18
|
function y(e) {
|
|
@@ -20,8 +20,8 @@ async function scanGitHubActions(d = process.cwd(), m = GITHUB_DIRECTORY) {
|
|
|
20
20
|
}
|
|
21
21
|
async function b(e) {
|
|
22
22
|
try {
|
|
23
|
-
let
|
|
24
|
-
return typeof
|
|
23
|
+
let a = await stat(e);
|
|
24
|
+
return typeof a.isFile == "function" ? a.isFile() : !1;
|
|
25
25
|
} catch {
|
|
26
26
|
return !1;
|
|
27
27
|
}
|
|
@@ -30,13 +30,13 @@ async function scanGitHubActions(d = process.cwd(), m = GITHUB_DIRECTORY) {
|
|
|
30
30
|
try {
|
|
31
31
|
if ((await stat(x)).isDirectory()) {
|
|
32
32
|
let e = (await readdir(x)).filter((e) => y(e) ? isYamlFile(e) : !1).map(async (e) => {
|
|
33
|
-
let
|
|
33
|
+
let a = join(x, e);
|
|
34
34
|
try {
|
|
35
|
-
let
|
|
35
|
+
let s = await scanWorkflowFile(a);
|
|
36
36
|
return {
|
|
37
37
|
path: `${m}/${WORKFLOWS_DIRECTORY}/${e}`,
|
|
38
38
|
success: !0,
|
|
39
|
-
actions:
|
|
39
|
+
actions: s
|
|
40
40
|
};
|
|
41
41
|
} catch {
|
|
42
42
|
return {
|
|
@@ -45,111 +45,111 @@ async function scanGitHubActions(d = process.cwd(), m = GITHUB_DIRECTORY) {
|
|
|
45
45
|
actions: []
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
|
-
}),
|
|
49
|
-
for (let e of
|
|
48
|
+
}), a = await Promise.all(e);
|
|
49
|
+
for (let e of a) e.success && e.path && (e.actions.length > 0 ? (h.workflows.set(e.path, e.actions), h.actions.push(...e.actions)) : h.workflows.set(e.path, []));
|
|
50
50
|
}
|
|
51
51
|
} catch {}
|
|
52
52
|
try {
|
|
53
|
-
let e = join(g, "action.yml"),
|
|
53
|
+
let e = join(g, "action.yml"), a = join(g, "action.yaml"), o = null, s = [];
|
|
54
54
|
if (await b(e)) try {
|
|
55
|
-
|
|
55
|
+
s = await scanActionFile(e), o = e;
|
|
56
56
|
} catch {
|
|
57
|
-
|
|
57
|
+
o = null;
|
|
58
58
|
}
|
|
59
|
-
if (!
|
|
60
|
-
|
|
59
|
+
if (!o && await b(a)) try {
|
|
60
|
+
s = await scanActionFile(a), o = a;
|
|
61
61
|
} catch {
|
|
62
|
-
|
|
62
|
+
o = null;
|
|
63
63
|
}
|
|
64
|
-
if (
|
|
65
|
-
let e = relative(g,
|
|
66
|
-
h.compositeActions.set(e, e),
|
|
64
|
+
if (o) {
|
|
65
|
+
let e = relative(g, o);
|
|
66
|
+
h.compositeActions.set(e, e), s.length > 0 && h.actions.push(...s);
|
|
67
67
|
}
|
|
68
68
|
} catch {}
|
|
69
69
|
let S = join(v, ACTIONS_DIRECTORY);
|
|
70
70
|
try {
|
|
71
71
|
if ((await stat(S)).isDirectory()) {
|
|
72
|
-
let
|
|
73
|
-
if (!y(
|
|
74
|
-
let
|
|
72
|
+
let a = (await readdir(S)).map(async (a) => {
|
|
73
|
+
if (!y(a)) return null;
|
|
74
|
+
let o = join(S, a);
|
|
75
75
|
try {
|
|
76
|
-
if (!(await stat(
|
|
77
|
-
let
|
|
76
|
+
if (!(await stat(o)).isDirectory()) return null;
|
|
77
|
+
let s = join(o, "action.yml"), c = [];
|
|
78
78
|
try {
|
|
79
|
-
|
|
79
|
+
c = await scanActionFile(s);
|
|
80
80
|
} catch {
|
|
81
81
|
try {
|
|
82
|
-
|
|
82
|
+
s = join(o, "action.yaml"), c = await scanActionFile(s);
|
|
83
83
|
} catch {
|
|
84
84
|
return null;
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
return {
|
|
88
|
-
path: `${m}/${ACTIONS_DIRECTORY}/${
|
|
89
|
-
name:
|
|
90
|
-
actions:
|
|
88
|
+
path: `${m}/${ACTIONS_DIRECTORY}/${a}`,
|
|
89
|
+
name: a,
|
|
90
|
+
actions: c
|
|
91
91
|
};
|
|
92
92
|
} catch {
|
|
93
93
|
return null;
|
|
94
94
|
}
|
|
95
|
-
}),
|
|
96
|
-
for (let e of
|
|
95
|
+
}), o = await Promise.all(a);
|
|
96
|
+
for (let e of o) e && (h.compositeActions.set(e.name, e.path), h.actions.push(...e.actions));
|
|
97
97
|
}
|
|
98
98
|
} catch {}
|
|
99
99
|
try {
|
|
100
100
|
let e = await getCurrentRepoSlug(g);
|
|
101
101
|
if (e) {
|
|
102
102
|
if (process.env.ACTIONS_UP_TEST_THROW === "1") throw Error("test");
|
|
103
|
-
let
|
|
104
|
-
for (let
|
|
105
|
-
if (
|
|
106
|
-
let
|
|
107
|
-
if (
|
|
108
|
-
let
|
|
109
|
-
_(g,
|
|
103
|
+
let a = /* @__PURE__ */ new Set(), o = [];
|
|
104
|
+
for (let s of h.actions) {
|
|
105
|
+
if (s.type !== "external") continue;
|
|
106
|
+
let c = s.name.split("/");
|
|
107
|
+
if (c.length < 3 || `${c[0]}/${c[1]}` !== e) continue;
|
|
108
|
+
let l = join(g, ...c.slice(2));
|
|
109
|
+
_(g, l) && (a.has(l) || (a.add(l), o.push(l)));
|
|
110
110
|
}
|
|
111
|
-
async function
|
|
112
|
-
if (
|
|
113
|
-
let
|
|
111
|
+
async function s() {
|
|
112
|
+
if (o.length === 0) return;
|
|
113
|
+
let c = o.splice(0), u = await Promise.all(c.map(async (o) => {
|
|
114
114
|
try {
|
|
115
|
-
let
|
|
115
|
+
let s = join(o, "action.yml"), c = join(o, "action.yaml"), u = s;
|
|
116
116
|
try {
|
|
117
|
-
if (!(await stat(
|
|
117
|
+
if (!(await stat(s)).isFile()) throw Error("not a file");
|
|
118
118
|
} catch {
|
|
119
|
-
if (!(await stat(
|
|
120
|
-
|
|
119
|
+
if (!(await stat(c)).isFile()) throw Error("not a file");
|
|
120
|
+
u = c;
|
|
121
121
|
}
|
|
122
|
-
let
|
|
123
|
-
|
|
124
|
-
let
|
|
125
|
-
for (let
|
|
126
|
-
if (
|
|
127
|
-
let
|
|
128
|
-
if (
|
|
129
|
-
let
|
|
130
|
-
_(g,
|
|
122
|
+
let d = await scanActionFile(u);
|
|
123
|
+
d.length > 0 && h.actions.push(...d);
|
|
124
|
+
let f = [];
|
|
125
|
+
for (let o of d) {
|
|
126
|
+
if (o.type !== "external") continue;
|
|
127
|
+
let s = o.name.split("/");
|
|
128
|
+
if (s.length < 3 || `${s[0]}/${s[1]}` !== e) continue;
|
|
129
|
+
let c = join(g, ...s.slice(2));
|
|
130
|
+
_(g, c) && (a.has(c) || (a.add(c), f.push(c)));
|
|
131
131
|
}
|
|
132
|
-
return
|
|
132
|
+
return f;
|
|
133
133
|
} catch {
|
|
134
134
|
return [];
|
|
135
135
|
}
|
|
136
136
|
}));
|
|
137
|
-
for (let e of
|
|
138
|
-
await
|
|
137
|
+
for (let e of u) for (let a of e) o.push(a);
|
|
138
|
+
await s();
|
|
139
139
|
}
|
|
140
|
-
await
|
|
140
|
+
await s();
|
|
141
141
|
}
|
|
142
142
|
} catch {}
|
|
143
143
|
return h;
|
|
144
144
|
}
|
|
145
145
|
async function getCurrentRepoSlug(e) {
|
|
146
|
-
let
|
|
147
|
-
if (
|
|
146
|
+
let a = process.env.GITHUB_REPOSITORY;
|
|
147
|
+
if (a && /^[^\s/]+\/[^\s/]+$/u.test(a)) return a;
|
|
148
148
|
try {
|
|
149
|
-
let
|
|
150
|
-
if (
|
|
151
|
-
let
|
|
152
|
-
if (
|
|
149
|
+
let a = await readFile(join(e, ".git", "config"), "utf8"), o = a.match(/\[remote "origin"\][\s\S]*?url\s*=\s*(?<url>.+)/u)?.groups?.url?.trim();
|
|
150
|
+
if (o ||= a.match(/url\s*=\s*(?<url>.+)/u)?.groups?.url?.trim(), !o) return null;
|
|
151
|
+
let s = o.match(/github\.com[/:](?<owner>[^/]+)\/(?<repo>[^./]+)(?:\.git)?$/u);
|
|
152
|
+
if (s?.groups) return `${s.groups.owner}/${s.groups.repo}`;
|
|
153
153
|
} catch {}
|
|
154
154
|
return null;
|
|
155
155
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ActionUpdate } from '../../types/action-update';
|
|
2
|
+
import { UpdateStyle } from '../../types/update-style';
|
|
3
|
+
/**
|
|
4
|
+
* Resolve the final reference that should be written back to the workflow.
|
|
5
|
+
*
|
|
6
|
+
* @param update - Update entry enriched with lookup data.
|
|
7
|
+
* @param style - Effective update style.
|
|
8
|
+
* @returns Update entry with resolved target reference fields.
|
|
9
|
+
*/
|
|
10
|
+
export declare function resolveTargetReference(update: ActionUpdate, style: UpdateStyle): ActionUpdate;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
function resolveTargetReference(e, t) {
|
|
2
|
+
return e.hasUpdate ? t === "sha" || e.currentRefType === "sha" ? e.latestSha ? {
|
|
3
|
+
...e,
|
|
4
|
+
targetRef: e.latestSha,
|
|
5
|
+
targetRefStyle: "sha"
|
|
6
|
+
} : {
|
|
7
|
+
...e,
|
|
8
|
+
targetRefStyle: null,
|
|
9
|
+
targetRef: null
|
|
10
|
+
} : e.currentRefType === "tag" && e.latestVersion ? {
|
|
11
|
+
...e,
|
|
12
|
+
targetRef: e.latestVersion,
|
|
13
|
+
targetRefStyle: "tag"
|
|
14
|
+
} : {
|
|
15
|
+
...e,
|
|
16
|
+
targetRefStyle: null,
|
|
17
|
+
targetRef: null
|
|
18
|
+
} : {
|
|
19
|
+
...e,
|
|
20
|
+
targetRefStyle: null,
|
|
21
|
+
targetRef: null
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export { resolveTargetReference };
|
package/dist/package.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const version = "1.
|
|
1
|
+
const version = "1.14.0";
|
|
2
2
|
export { version };
|
|
@@ -6,7 +6,17 @@ export interface ActionUpdate {
|
|
|
6
6
|
/**
|
|
7
7
|
* Reason for skipping the update check.
|
|
8
8
|
*/
|
|
9
|
-
skipReason?: 'unknown' | 'branch'
|
|
9
|
+
skipReason?: 'unsupported-style' | 'unknown' | 'branch'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Detected style of the current reference in the source file.
|
|
13
|
+
*/
|
|
14
|
+
currentRefType?: 'unknown' | 'branch' | 'sha' | 'tag'
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Style of the final reference that should be written back to the file.
|
|
18
|
+
*/
|
|
19
|
+
targetRefStyle?: 'sha' | 'tag' | null
|
|
10
20
|
|
|
11
21
|
/**
|
|
12
22
|
* Current version string.
|
|
@@ -23,6 +33,11 @@ export interface ActionUpdate {
|
|
|
23
33
|
*/
|
|
24
34
|
status?: 'skipped' | 'ok'
|
|
25
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Final reference that should be written back to the file.
|
|
38
|
+
*/
|
|
39
|
+
targetRef?: string | null
|
|
40
|
+
|
|
26
41
|
/**
|
|
27
42
|
* SHA hash of the latest version.
|
|
28
43
|
*/
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "actions-up",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Interactive CLI tool to update GitHub Actions
|
|
3
|
+
"version": "1.14.0",
|
|
4
|
+
"description": "Interactive CLI tool to update GitHub Actions with SHA pinning or preserved refs",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"github-actions",
|
|
7
7
|
"actions",
|