actions-up 1.13.0 → 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 +57 -36
- package/dist/cli/build-json-report.js +4 -0
- package/dist/cli/index.js +109 -94
- 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/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/interactive/prompt-update-selection.js +127 -115
- 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 +24 -5
|
@@ -9,55 +9,55 @@ import "node:worker_threads";
|
|
|
9
9
|
import pc from "picocolors";
|
|
10
10
|
import enquirer from "enquirer";
|
|
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
189
|
}
|
|
190
|
-
function formatVersionOrSha(
|
|
191
|
-
return
|
|
190
|
+
function formatVersionOrSha(e) {
|
|
191
|
+
return e ? isSha(e) ? e.slice(0, 7) : e.replace(/^v/u, "") : pc.gray("unknown");
|
|
192
|
+
}
|
|
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 };
|
|
@@ -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",
|
package/readme.md
CHANGED
|
@@ -16,7 +16,7 @@ Actions Up scans your workflows and composite actions to discover every
|
|
|
16
16
|
referenced GitHub Action, then checks for newer releases.
|
|
17
17
|
|
|
18
18
|
Interactively upgrade and pin actions to exact commit SHAs for secure,
|
|
19
|
-
reproducible CI
|
|
19
|
+
reproducible CI, or preserve tag-style references when you need to stay on tags.
|
|
20
20
|
|
|
21
21
|
## Features
|
|
22
22
|
|
|
@@ -25,8 +25,8 @@ reproducible CI and low-friction maintenance.
|
|
|
25
25
|
`action.yml`/`action.yaml`)
|
|
26
26
|
- **Reusable Workflows**: Detects and updates reusable workflow calls at the job
|
|
27
27
|
level
|
|
28
|
-
- **
|
|
29
|
-
|
|
28
|
+
- **Flexible update styles**: Use SHA pinning by default, or preserve tag-style
|
|
29
|
+
references with `--style preserve`
|
|
30
30
|
- **Batch Updates**: Update multiple actions at once
|
|
31
31
|
- **Interactive Selection**: Choose which actions to update
|
|
32
32
|
- **Breaking Changes Detection**: Warns about major version updates
|
|
@@ -124,7 +124,7 @@ This will:
|
|
|
124
124
|
plus root `action.yml`/`action.yaml`
|
|
125
125
|
2. Check for available updates
|
|
126
126
|
3. Show an interactive list to select updates
|
|
127
|
-
4. Apply selected updates with SHA pinning
|
|
127
|
+
4. Apply selected updates with SHA pinning by default
|
|
128
128
|
|
|
129
129
|
### Auto-Update Mode
|
|
130
130
|
|
|
@@ -200,6 +200,24 @@ In `minor` and `patch` modes, Actions Up tries to find the newest compatible tag
|
|
|
200
200
|
first (for example, from `@v4` in `minor` mode it will choose the latest
|
|
201
201
|
`v4.x.y`). If no compatible version exists, that action is skipped.
|
|
202
202
|
|
|
203
|
+
### Update Style
|
|
204
|
+
|
|
205
|
+
By default, Actions Up writes updates as pinned SHAs:
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
npx actions-up --style sha
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Use `--style preserve` to keep the current reference style:
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
npx actions-up --style preserve
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
`preserve` keeps tag references on tags and SHA references on SHAs. For example,
|
|
218
|
+
`actions/checkout@v5` updates to `actions/checkout@v6.0.2`, while a SHA-pinned
|
|
219
|
+
action continues updating to the latest resolved SHA.
|
|
220
|
+
|
|
203
221
|
## GitHub Actions Integration
|
|
204
222
|
|
|
205
223
|
### Automated PR Checks
|
|
@@ -500,7 +518,8 @@ Ignore comments (file/block/next-line/inline):
|
|
|
500
518
|
Interactive CLI for developers who want control over GitHub Actions updates.
|
|
501
519
|
|
|
502
520
|
- **vs. Dependabot/Renovate:** Dependabot and Renovate update via pull requests;
|
|
503
|
-
Actions Up is an interactive CLI with explicit SHA pinning
|
|
521
|
+
Actions Up is an interactive CLI with explicit SHA pinning by default and an
|
|
522
|
+
opt-in preserve mode for tag users.
|
|
504
523
|
- **vs. pinact:** pinact is a CLI to pin and update Actions and reusable
|
|
505
524
|
workflows; Actions Up adds interactive selection and major update warnings.
|
|
506
525
|
- **Zero-config:** `npx actions-up` runs immediately.
|