actions-up 1.11.0 → 1.12.1
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/index.d.ts +3 -1
- package/dist/cli/index.js +84 -93
- package/dist/cli/merge-scan-results.d.ts +8 -0
- package/dist/cli/merge-scan-results.js +18 -0
- package/dist/cli/normalize-update-mode.d.ts +8 -0
- package/dist/cli/normalize-update-mode.js +6 -0
- package/dist/cli/print-mode-warning.d.ts +16 -0
- package/dist/cli/print-mode-warning.js +11 -0
- package/dist/cli/print-skipped-warning.d.ts +14 -0
- package/dist/cli/print-skipped-warning.js +10 -0
- package/dist/cli/resolve-scan-directories.d.ts +31 -0
- package/dist/cli/resolve-scan-directories.js +24 -0
- package/dist/core/api/check-updates.d.ts +4 -1
- package/dist/core/api/check-updates.js +119 -116
- package/dist/core/api/get-all-releases.d.ts +2 -1
- package/dist/core/api/get-compatible-update.d.ts +37 -0
- package/dist/core/api/get-compatible-update.js +40 -0
- 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 -68
- package/dist/core/scan-recursive.js +12 -14
- package/dist/core/versions/find-compatible-tag.d.ts +16 -0
- package/dist/core/versions/find-compatible-tag.js +27 -0
- package/dist/core/versions/get-update-level.d.ts +3 -1
- package/dist/core/versions/is-semver-like.d.ts +9 -0
- package/dist/core/versions/is-semver-like.js +4 -0
- package/dist/core/versions/normalize-version.d.ts +14 -0
- package/dist/core/versions/normalize-version.js +9 -0
- 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 +53 -18
|
@@ -1,149 +1,161 @@
|
|
|
1
|
+
import { normalizeVersion } from "../versions/normalize-version.js";
|
|
2
|
+
import { isSemverLike } from "../versions/is-semver-like.js";
|
|
1
3
|
import { createGitHubClient } from "./create-github-client.js";
|
|
2
4
|
import semver from "semver";
|
|
3
|
-
async function checkUpdates(
|
|
4
|
-
let
|
|
5
|
-
if (
|
|
6
|
-
let
|
|
7
|
-
for (let e of
|
|
8
|
-
let t =
|
|
9
|
-
t.push(e),
|
|
5
|
+
async function checkUpdates(i, o, l) {
|
|
6
|
+
let u = l?.client ?? createGitHubClient(o), d = l?.includeBranches ?? !1, f = i.filter((e) => e.type === "external" || e.type === "reusable-workflow");
|
|
7
|
+
if (f.length === 0) return [];
|
|
8
|
+
let p = /* @__PURE__ */ new Map();
|
|
9
|
+
for (let e of f) {
|
|
10
|
+
let t = p.get(e.name) ?? [];
|
|
11
|
+
t.push(e), p.set(e.name, t);
|
|
10
12
|
}
|
|
11
|
-
let
|
|
13
|
+
let m = {
|
|
12
14
|
rateLimitError: null,
|
|
13
15
|
rateLimitHit: !1
|
|
14
|
-
},
|
|
15
|
-
if (
|
|
16
|
+
}, h = await [...p.keys()].reduce((n, i) => n.then(async (n) => {
|
|
17
|
+
if (m.rateLimitHit) return [...n, {
|
|
16
18
|
publishedAt: null,
|
|
17
19
|
version: null,
|
|
18
|
-
actionName:
|
|
20
|
+
actionName: i,
|
|
19
21
|
sha: null
|
|
20
22
|
}];
|
|
21
|
-
let
|
|
22
|
-
if (
|
|
23
|
+
let a = i.split("/");
|
|
24
|
+
if (a.length < 2) return [...n, {
|
|
23
25
|
publishedAt: null,
|
|
24
26
|
version: null,
|
|
25
|
-
actionName:
|
|
27
|
+
actionName: i,
|
|
26
28
|
sha: null
|
|
27
29
|
}];
|
|
28
|
-
let [
|
|
29
|
-
if (!
|
|
30
|
+
let [o, l] = a;
|
|
31
|
+
if (!o || !l) return [...n, {
|
|
30
32
|
publishedAt: null,
|
|
31
33
|
version: null,
|
|
32
|
-
actionName:
|
|
34
|
+
actionName: i,
|
|
33
35
|
sha: null
|
|
34
36
|
}];
|
|
35
37
|
try {
|
|
36
|
-
let
|
|
37
|
-
if (
|
|
38
|
+
let a = p.get(i)[0]?.version;
|
|
39
|
+
if (a && !isSha(a) && !isSemverLike(a) && await u.getRefType(o, l, a) === "branch" && !d) return [...n, {
|
|
38
40
|
skipReason: "branch",
|
|
39
41
|
status: "skipped",
|
|
40
42
|
publishedAt: null,
|
|
41
43
|
version: null,
|
|
42
|
-
actionName:
|
|
44
|
+
actionName: i,
|
|
43
45
|
sha: null
|
|
44
46
|
}];
|
|
45
|
-
let
|
|
46
|
-
if (!
|
|
47
|
-
let e = await
|
|
48
|
-
|
|
47
|
+
let f = await u.getLatestRelease(o, l);
|
|
48
|
+
if (!f) {
|
|
49
|
+
let e = await u.getAllReleases(o, l, 1);
|
|
50
|
+
f = e.find((e) => !e.isPrerelease) ?? e[0] ?? null;
|
|
49
51
|
}
|
|
50
|
-
if (
|
|
51
|
-
let { publishedAt:
|
|
52
|
+
if (f) {
|
|
53
|
+
let { publishedAt: a, version: s, sha: d } = f, p = !1;
|
|
52
54
|
{
|
|
53
|
-
let
|
|
54
|
-
|
|
55
|
+
let n = normalizeVersion(s), i = !!(s && s.trim() !== ""), a = i && /^v?\d+$/u.test(s.trim()), o = semver.valid(n);
|
|
56
|
+
p = !i || a || !o || !isSemverLike(s);
|
|
55
57
|
}
|
|
56
|
-
if (
|
|
57
|
-
let
|
|
58
|
-
if (
|
|
59
|
-
let
|
|
60
|
-
v: semver.valid(normalizeVersion(
|
|
61
|
-
raw:
|
|
58
|
+
if (p) {
|
|
59
|
+
let a = await u.getAllTags(o, l, 30);
|
|
60
|
+
if (a.length > 0) {
|
|
61
|
+
let d = a.filter((e) => isSemverLike(e.tag)).map((t) => ({
|
|
62
|
+
v: semver.valid(normalizeVersion(t.tag)),
|
|
63
|
+
raw: t
|
|
62
64
|
}));
|
|
63
|
-
if (
|
|
64
|
-
|
|
65
|
-
let
|
|
66
|
-
if (
|
|
65
|
+
if (d.length > 0) {
|
|
66
|
+
d.sort((e, t) => {
|
|
67
|
+
let n = semver.rcompare(e.v, t.v);
|
|
68
|
+
if (n !== 0) return n;
|
|
67
69
|
let i = /\d+\.\d+/u.test(e.raw.tag) ? 1 : 0;
|
|
68
|
-
return (/\d+\.\d+/u.test(
|
|
70
|
+
return (/\d+\.\d+/u.test(t.raw.tag) ? 1 : 0) - i;
|
|
69
71
|
});
|
|
70
|
-
let
|
|
71
|
-
if (!
|
|
72
|
-
let
|
|
73
|
-
if (!
|
|
74
|
-
|
|
75
|
-
} catch {
|
|
76
|
-
|
|
77
|
-
|
|
72
|
+
let t = d[0].raw, a = semver.valid(normalizeVersion(s) ?? void 0);
|
|
73
|
+
if (!a || semver.gt(d[0].v, a) || semver.eq(d[0].v, a) && /\d+\.\d+/u.test(t.tag)) {
|
|
74
|
+
let e = t.tag, r = t.sha?.length ? t.sha : null;
|
|
75
|
+
if (!r && e) try {
|
|
76
|
+
r = await u.getTagSha(o, l, e);
|
|
77
|
+
} catch (e) {
|
|
78
|
+
if (isRateLimitError(e)) throw e;
|
|
79
|
+
}
|
|
80
|
+
return [...n, {
|
|
81
|
+
version: e,
|
|
78
82
|
publishedAt: null,
|
|
79
|
-
sha:
|
|
80
|
-
actionName:
|
|
83
|
+
sha: r,
|
|
84
|
+
actionName: i
|
|
81
85
|
}];
|
|
82
86
|
}
|
|
83
87
|
}
|
|
84
88
|
}
|
|
85
89
|
}
|
|
86
|
-
if (
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
+
if (s) {
|
|
91
|
+
let e = d;
|
|
92
|
+
try {
|
|
93
|
+
d = await u.getTagSha(o, l, s) ?? e;
|
|
94
|
+
} catch (t) {
|
|
95
|
+
if (isRateLimitError(t)) throw t;
|
|
96
|
+
d = e;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return [...n, {
|
|
90
100
|
status: "ok",
|
|
91
|
-
publishedAt:
|
|
92
|
-
actionName:
|
|
93
|
-
version:
|
|
94
|
-
sha:
|
|
101
|
+
publishedAt: a,
|
|
102
|
+
actionName: i,
|
|
103
|
+
version: s,
|
|
104
|
+
sha: d
|
|
95
105
|
}];
|
|
96
106
|
}
|
|
97
|
-
let
|
|
98
|
-
if (
|
|
99
|
-
let
|
|
100
|
-
v: semver.valid(normalizeVersion(
|
|
101
|
-
raw:
|
|
102
|
-
})),
|
|
103
|
-
|
|
104
|
-
let
|
|
105
|
-
if (
|
|
107
|
+
let m = await u.getAllTags(o, l, 30);
|
|
108
|
+
if (m.length > 0) {
|
|
109
|
+
let a = m.filter((e) => isSemverLike(e.tag)).map((t) => ({
|
|
110
|
+
v: semver.valid(normalizeVersion(t.tag)),
|
|
111
|
+
raw: t
|
|
112
|
+
})), s;
|
|
113
|
+
a.length > 0 ? (a.sort((e, t) => {
|
|
114
|
+
let n = semver.rcompare(e.v, t.v);
|
|
115
|
+
if (n !== 0) return n;
|
|
106
116
|
let i = /\d+\.\d+/u.test(e.raw.tag) ? 1 : 0;
|
|
107
|
-
return (/\d+\.\d+/u.test(
|
|
108
|
-
}),
|
|
109
|
-
let
|
|
110
|
-
if (!
|
|
111
|
-
|
|
112
|
-
} catch {
|
|
113
|
-
|
|
117
|
+
return (/\d+\.\d+/u.test(t.raw.tag) ? 1 : 0) - i;
|
|
118
|
+
}), s = a[0].raw) : s = m[0];
|
|
119
|
+
let d = s.tag, f = s.sha?.length ? s.sha : null;
|
|
120
|
+
if (!f && d) try {
|
|
121
|
+
f = await u.getTagSha(o, l, d);
|
|
122
|
+
} catch (e) {
|
|
123
|
+
if (isRateLimitError(e)) throw e;
|
|
124
|
+
}
|
|
125
|
+
return [...n, {
|
|
114
126
|
status: "ok",
|
|
115
127
|
publishedAt: null,
|
|
116
|
-
actionName:
|
|
117
|
-
version:
|
|
118
|
-
sha:
|
|
128
|
+
actionName: i,
|
|
129
|
+
version: d,
|
|
130
|
+
sha: f
|
|
119
131
|
}];
|
|
120
132
|
}
|
|
121
|
-
return [...
|
|
133
|
+
return [...n, {
|
|
122
134
|
publishedAt: null,
|
|
123
135
|
version: null,
|
|
124
|
-
actionName:
|
|
136
|
+
actionName: i,
|
|
125
137
|
sha: null
|
|
126
138
|
}];
|
|
127
|
-
} catch (
|
|
128
|
-
return
|
|
139
|
+
} catch (e) {
|
|
140
|
+
return e instanceof Error && e.name === "GitHubRateLimitError" ? (m.rateLimitHit = !0, m.rateLimitError = e, [...n, {
|
|
129
141
|
publishedAt: null,
|
|
130
142
|
version: null,
|
|
131
|
-
actionName:
|
|
143
|
+
actionName: i,
|
|
132
144
|
sha: null
|
|
133
|
-
}]) : (console.warn(`Failed to check ${
|
|
145
|
+
}]) : (console.warn(`Failed to check ${i}:`, e), [...n, {
|
|
134
146
|
publishedAt: null,
|
|
135
147
|
version: null,
|
|
136
|
-
actionName:
|
|
148
|
+
actionName: i,
|
|
137
149
|
sha: null
|
|
138
150
|
}]);
|
|
139
151
|
}
|
|
140
152
|
}), Promise.resolve([]));
|
|
141
|
-
if (
|
|
142
|
-
let e = !!(
|
|
153
|
+
if (m.rateLimitError) {
|
|
154
|
+
let e = !!(o ?? process.env.GITHUB_TOKEN), t = `${m.rateLimitError.message || "GitHub API rate limit exceeded."}\n${e ? "Wait for reset or reduce request rate." : "Please set GITHUB_TOKEN environment variable to increase the limit.\nSee: https://github.com/azat-io/actions-up?tab=readme-ov-file#github-token"}`, n = Error(t);
|
|
143
155
|
throw n.name = "GitHubRateLimitError", n;
|
|
144
156
|
}
|
|
145
|
-
let
|
|
146
|
-
for (let e of
|
|
157
|
+
let g = /* @__PURE__ */ new Map();
|
|
158
|
+
for (let e of h) g.set(e.actionName, {
|
|
147
159
|
publishedAt: e.publishedAt,
|
|
148
160
|
actionName: e.actionName,
|
|
149
161
|
skipReason: e.skipReason,
|
|
@@ -151,57 +163,57 @@ async function checkUpdates(n, i, c) {
|
|
|
151
163
|
status: e.status,
|
|
152
164
|
sha: e.sha
|
|
153
165
|
});
|
|
154
|
-
let
|
|
155
|
-
for (let e of
|
|
156
|
-
let t =
|
|
157
|
-
t ?
|
|
166
|
+
let _ = [];
|
|
167
|
+
for (let e of f) {
|
|
168
|
+
let t = g.get(e.name);
|
|
169
|
+
t ? _.push(createUpdate(e, {
|
|
158
170
|
publishedAt: t.publishedAt,
|
|
159
171
|
version: t.version,
|
|
160
172
|
sha: t.sha
|
|
161
173
|
}, {
|
|
162
174
|
skipReason: t.skipReason,
|
|
163
175
|
status: t.status
|
|
164
|
-
})) :
|
|
176
|
+
})) : _.push(createUpdate(e, {
|
|
165
177
|
publishedAt: null,
|
|
166
178
|
version: null,
|
|
167
179
|
sha: null
|
|
168
180
|
}));
|
|
169
181
|
}
|
|
170
|
-
return
|
|
182
|
+
return _;
|
|
171
183
|
}
|
|
172
|
-
function createUpdate(
|
|
173
|
-
let { version:
|
|
184
|
+
function createUpdate(t, n, i = {}) {
|
|
185
|
+
let { version: a, sha: c, publishedAt: l } = n, u = t.version ?? "unknown", d = normalizeVersion(u), f = a ? normalizeVersion(a) : null, p = i.status ?? "ok", m = i.skipReason, h = !1, g = !1;
|
|
174
186
|
if (p === "skipped") return {
|
|
175
187
|
currentVersion: u,
|
|
176
188
|
isBreaking: !1,
|
|
177
189
|
hasUpdate: !1,
|
|
178
|
-
latestVersion:
|
|
190
|
+
latestVersion: a,
|
|
179
191
|
publishedAt: l,
|
|
180
192
|
skipReason: m,
|
|
181
193
|
latestSha: c,
|
|
182
|
-
action:
|
|
194
|
+
action: t,
|
|
183
195
|
status: p
|
|
184
196
|
};
|
|
185
197
|
if (d && isSha(d)) c ? h = !compareSha(d, c) : f && (h = !0);
|
|
186
198
|
else if (d && f) {
|
|
187
|
-
let
|
|
188
|
-
if (
|
|
189
|
-
if (h = semver.lt(
|
|
190
|
-
let
|
|
191
|
-
g = semver.major(
|
|
199
|
+
let e = semver.valid(d), n = semver.valid(f);
|
|
200
|
+
if (e && n) {
|
|
201
|
+
if (h = semver.lt(e, n), h) {
|
|
202
|
+
let t = semver.major(e);
|
|
203
|
+
g = semver.major(n) > t;
|
|
192
204
|
}
|
|
193
|
-
!h && semver.eq(
|
|
205
|
+
!h && semver.eq(e, n) && !isSha(t.version) && c && (h = !0, g = !1);
|
|
194
206
|
} else d !== f && (h = !0);
|
|
195
207
|
}
|
|
196
208
|
return {
|
|
197
209
|
currentVersion: u,
|
|
198
|
-
latestVersion:
|
|
210
|
+
latestVersion: a,
|
|
199
211
|
publishedAt: l,
|
|
200
212
|
isBreaking: g,
|
|
201
213
|
skipReason: m,
|
|
202
214
|
latestSha: c,
|
|
203
215
|
hasUpdate: h,
|
|
204
|
-
action:
|
|
216
|
+
action: t,
|
|
205
217
|
status: p
|
|
206
218
|
};
|
|
207
219
|
}
|
|
@@ -209,21 +221,12 @@ function compareSha(e, t) {
|
|
|
209
221
|
let n = e.replace(/^v/u, ""), r = t.replace(/^v/u, ""), i = Math.min(n.length, r.length);
|
|
210
222
|
return i < 7 ? !1 : n.slice(0, Math.max(0, i)).toLowerCase() === r.slice(0, Math.max(0, i)).toLowerCase();
|
|
211
223
|
}
|
|
212
|
-
function normalizeVersion(e) {
|
|
213
|
-
if (!e) return null;
|
|
214
|
-
let n = e.replace(/^v/u, "");
|
|
215
|
-
if (/^[0-9a-f]{7,40}$/iu.test(n)) return e;
|
|
216
|
-
let r = semver.coerce(n);
|
|
217
|
-
return r ? r.version : e;
|
|
218
|
-
}
|
|
219
224
|
function isSha(e) {
|
|
220
225
|
if (!e) return !1;
|
|
221
226
|
let t = e.replace(/^v/u, "");
|
|
222
227
|
return /^[0-9a-f]{7,40}$/iu.test(t);
|
|
223
228
|
}
|
|
224
|
-
function
|
|
225
|
-
|
|
226
|
-
let t = e.trim();
|
|
227
|
-
return /^v?\d+(?:\.\d+){0,2}$/u.test(t);
|
|
229
|
+
function isRateLimitError(e) {
|
|
230
|
+
return e instanceof Error && e.name === "GitHubRateLimitError";
|
|
228
231
|
}
|
|
229
232
|
export { checkUpdates };
|
|
@@ -4,7 +4,8 @@ import { ReleaseInfo } from '../../types/release-info';
|
|
|
4
4
|
* Fetch releases for a repository.
|
|
5
5
|
*
|
|
6
6
|
* Resolves SHA only for the first returned release via target_commitish when it
|
|
7
|
-
* looks like a SHA;
|
|
7
|
+
* looks like a SHA; callers can resolve the tag via git refs later when
|
|
8
|
+
* pinning.
|
|
8
9
|
*
|
|
9
10
|
* @param context - Client context.
|
|
10
11
|
* @param parameters - Request parameters.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { GitHubClient } from '../../types/github-client';
|
|
2
|
+
import { UpdateMode } from '../../types/update-mode';
|
|
3
|
+
import { TagInfo } from '../../types/tag-info';
|
|
4
|
+
interface GetCompatibleUpdateParameters {
|
|
5
|
+
/**
|
|
6
|
+
* Optional in-memory cache for resolved tag SHAs.
|
|
7
|
+
*/
|
|
8
|
+
shaCache?: Map<string, string | null>;
|
|
9
|
+
/**
|
|
10
|
+
* Update mode that limits which tag can be selected.
|
|
11
|
+
*/
|
|
12
|
+
mode: Exclude<UpdateMode, 'major'>;
|
|
13
|
+
/**
|
|
14
|
+
* Optional in-memory cache for action tags.
|
|
15
|
+
*/
|
|
16
|
+
tagsCache?: Map<string, TagInfo[]>;
|
|
17
|
+
/**
|
|
18
|
+
* Current action version used as compatibility baseline.
|
|
19
|
+
*/
|
|
20
|
+
currentVersion: string | null;
|
|
21
|
+
/**
|
|
22
|
+
* Action name in `owner/repo` format (path suffix is allowed).
|
|
23
|
+
*/
|
|
24
|
+
actionName: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Resolve the newest compatible update for an action.
|
|
28
|
+
*
|
|
29
|
+
* @param client - GitHub client instance.
|
|
30
|
+
* @param parameters - Lookup parameters.
|
|
31
|
+
* @returns Compatible target version and SHA, or null when none found.
|
|
32
|
+
*/
|
|
33
|
+
export declare function getCompatibleUpdate(client: GitHubClient, parameters: GetCompatibleUpdateParameters): Promise<{
|
|
34
|
+
sha: string | null;
|
|
35
|
+
version: string;
|
|
36
|
+
} | null>;
|
|
37
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { isSemverLike } from "../versions/is-semver-like.js";
|
|
2
|
+
import { findCompatibleTag } from "../versions/find-compatible-tag.js";
|
|
3
|
+
async function getCompatibleUpdate(n, r) {
|
|
4
|
+
let { currentVersion: i, actionName: a, mode: o } = r;
|
|
5
|
+
if (!i || !isSemverLike(i)) return null;
|
|
6
|
+
let s = a.split("/");
|
|
7
|
+
if (s.length < 2) return null;
|
|
8
|
+
let [c, l] = s;
|
|
9
|
+
if (!c || !l) return null;
|
|
10
|
+
let u = r.tagsCache ?? /* @__PURE__ */ new Map(), d = r.shaCache ?? /* @__PURE__ */ new Map(), f = u.get(a);
|
|
11
|
+
if (!f) {
|
|
12
|
+
try {
|
|
13
|
+
f = await n.getAllTags(c, l, 100);
|
|
14
|
+
} catch {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
u.set(a, f);
|
|
18
|
+
}
|
|
19
|
+
let p = findCompatibleTag(f, i, o);
|
|
20
|
+
if (!p) return null;
|
|
21
|
+
let m = p.tag, h = p.sha?.length ? p.sha : null;
|
|
22
|
+
if (!h) {
|
|
23
|
+
let e = `${a}@${m}`;
|
|
24
|
+
if (d.has(e)) return {
|
|
25
|
+
sha: d.get(e) ?? null,
|
|
26
|
+
version: m
|
|
27
|
+
};
|
|
28
|
+
try {
|
|
29
|
+
h = await n.getTagSha(c, l, m);
|
|
30
|
+
} catch {
|
|
31
|
+
h = null;
|
|
32
|
+
}
|
|
33
|
+
d.set(e, h);
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
version: m,
|
|
37
|
+
sha: h
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export { getCompatibleUpdate };
|
|
@@ -3,9 +3,9 @@ import { ReleaseInfo } from '../../types/release-info';
|
|
|
3
3
|
/**
|
|
4
4
|
* Fetch the latest release for a repository.
|
|
5
5
|
*
|
|
6
|
-
* If the latest release does not exist (404), returns null. The commit SHA
|
|
7
|
-
* taken from target_commitish
|
|
8
|
-
*
|
|
6
|
+
* If the latest release does not exist (404), returns null. The commit SHA may
|
|
7
|
+
* be taken from target_commitish when it looks like a SHA; callers can resolve
|
|
8
|
+
* the tag via git refs later when pinning.
|
|
9
9
|
*
|
|
10
10
|
* @param context - Client context.
|
|
11
11
|
* @param owner - Repository owner.
|
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
import { GitHubAction } from '../../../types/github-action';
|
|
2
2
|
interface ExtractUsesOptions {
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* YAML sequence node containing workflow/action steps.
|
|
5
|
+
*/
|
|
4
6
|
stepsNode: unknown;
|
|
5
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* Path of the file being scanned (for metadata).
|
|
9
|
+
*/
|
|
6
10
|
filePath: string;
|
|
7
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* Name of the job containing these steps (for workflows).
|
|
13
|
+
*/
|
|
8
14
|
jobName?: string;
|
|
9
|
-
/**
|
|
15
|
+
/**
|
|
16
|
+
* Original YAML file content (for line number calculation).
|
|
17
|
+
*/
|
|
10
18
|
content: string;
|
|
11
19
|
}
|
|
12
20
|
/**
|
package/dist/core/constants.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* Constants for directory names used in the project.
|
|
3
|
+
*/
|
|
2
4
|
export declare const GITHUB_DIRECTORY: ".github";
|
|
3
5
|
export declare const WORKFLOWS_DIRECTORY: "workflows";
|
|
4
6
|
export declare const ACTIONS_DIRECTORY: "actions";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isYamlFile } from "./is-yaml-file.js";
|
|
2
|
-
import { join } from "node:path";
|
|
3
2
|
import { lstat, readdir } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
4
|
async function findYamlFilesRecursive(i) {
|
|
5
5
|
let a = [], o = /* @__PURE__ */ new Set();
|
|
6
6
|
async function s(i) {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { ActionUpdate } from '../../types/action-update';
|
|
2
2
|
interface PromptUpdateSelectionOptions {
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* Whether to show the Age column.
|
|
5
|
+
*/
|
|
4
6
|
showAge?: boolean;
|
|
5
7
|
}
|
|
6
8
|
export declare function promptUpdateSelection(updates: ActionUpdate[], options?: PromptUpdateSelectionOptions): Promise<ActionUpdate[] | null>;
|
|
@@ -4,10 +4,10 @@ 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";
|
|
8
7
|
import "node:worker_threads";
|
|
9
8
|
import pc from "picocolors";
|
|
10
9
|
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
12
|
async function promptUpdateSelection(g, v = {}) {
|
|
13
13
|
let { showAge: y = !1 } = v;
|
|
@@ -41,8 +41,8 @@ async function promptUpdateSelection(g, v = {}) {
|
|
|
41
41
|
};
|
|
42
42
|
})), C = [], w = stripAnsi("Action").length, T = stripAnsi("Current").length, E = stripAnsi("Job").length, D = 0, O = !1;
|
|
43
43
|
for (let [t, a] of b.entries()) {
|
|
44
|
-
let o = a.action.name,
|
|
45
|
-
if (w = Math.max(w, o.length), T = Math.max(T, stripAnsi(d).length,
|
|
44
|
+
let o = a.action.name, u = S[t], d = u.display, f = a.action.job ?? "–";
|
|
45
|
+
if (w = Math.max(w, o.length), T = Math.max(T, stripAnsi(d).length, u.versionForPadding && u.shortSha ? stripAnsi(`${padString(u.versionForPadding, D + 1)}${pc.gray(`(${u.shortSha})`)}`).length : 0), E = Math.max(E, f.length), a.latestVersion) {
|
|
46
46
|
let o = formatVersion(a.latestVersion, S[t]?.effectiveForDiff ?? a.currentVersion);
|
|
47
47
|
D = Math.max(D, stripAnsi(o).length);
|
|
48
48
|
}
|
|
@@ -56,7 +56,7 @@ async function promptUpdateSelection(g, v = {}) {
|
|
|
56
56
|
console.warn(`Unexpected missing group for file: ${a}`);
|
|
57
57
|
continue;
|
|
58
58
|
}
|
|
59
|
-
let s = [],
|
|
59
|
+
let s = [], u = o;
|
|
60
60
|
s.push({
|
|
61
61
|
current: "Current",
|
|
62
62
|
action: "Action",
|
|
@@ -65,10 +65,10 @@ async function promptUpdateSelection(g, v = {}) {
|
|
|
65
65
|
job: "Job",
|
|
66
66
|
age: "Age"
|
|
67
67
|
});
|
|
68
|
-
for (let { update: t, index: a } of
|
|
69
|
-
let o = !!t.latestSha,
|
|
70
|
-
|
|
71
|
-
let f =
|
|
68
|
+
for (let { update: t, index: a } of u) {
|
|
69
|
+
let o = !!t.latestSha, u = S[a], d = u.display;
|
|
70
|
+
u.versionForPadding && u.shortSha && (d = `${padString(u.versionForPadding, M + 1)}${pc.gray(`(${u.shortSha})`)}`);
|
|
71
|
+
let f = u.effectiveForDiff ?? t.currentVersion, p = formatVersion(t.latestVersion, f), m = t.action.name;
|
|
72
72
|
if (t.latestSha) {
|
|
73
73
|
let i = t.latestSha.slice(0, 7);
|
|
74
74
|
p = `${padString(p, M + 1)}${pc.gray(`(${i})`)}`;
|
|
@@ -101,7 +101,7 @@ async function promptUpdateSelection(g, v = {}) {
|
|
|
101
101
|
name: ""
|
|
102
102
|
});
|
|
103
103
|
else {
|
|
104
|
-
let { update: i, index: a } =
|
|
104
|
+
let { update: i, index: a } = u[t - 1], s = !!i.latestSha, c = s && !i.isBreaking;
|
|
105
105
|
_.push({
|
|
106
106
|
message: o,
|
|
107
107
|
value: String(a),
|
|
@@ -4,18 +4,22 @@ import { GitHubAction } from '../../types/github-action';
|
|
|
4
4
|
* object.
|
|
5
5
|
*
|
|
6
6
|
* @example
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* const action = parseActionReference(
|
|
10
|
+
* 'actions/checkout@v3',
|
|
11
|
+
* 'workflow.yml',
|
|
12
|
+
* 10,
|
|
13
|
+
* )
|
|
14
|
+
* // Returns:
|
|
15
|
+
* // {
|
|
16
|
+
* // type: 'external',
|
|
17
|
+
* // name: 'actions/checkout',
|
|
18
|
+
* // version: 'v3',
|
|
19
|
+
* // file: 'workflow.yml',
|
|
20
|
+
* // line: 10,
|
|
21
|
+
* // }
|
|
22
|
+
* ```
|
|
19
23
|
*
|
|
20
24
|
* @param reference - The action reference string to parse. Can be:
|
|
21
25
|
*
|
|
@@ -4,7 +4,10 @@ import { ScanResult } from '../types/scan-result';
|
|
|
4
4
|
* actions.
|
|
5
5
|
*
|
|
6
6
|
* @example
|
|
7
|
-
*
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* const result = await scanGitHubActions('/path/to/repo')
|
|
10
|
+
* ```
|
|
8
11
|
*
|
|
9
12
|
* @param rootPath - The root path of the repository to scan. Defaults to
|
|
10
13
|
* current working directory.
|