actions-up 1.6.0 → 1.7.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/index.js CHANGED
@@ -10,57 +10,57 @@ import "node:worker_threads";
10
10
  import pc from "picocolors";
11
11
  import cac from "cac";
12
12
  function run() {
13
- let l = cac("actions-up");
14
- l.help().version(version).option("--dir <directory>", "Custom directory name (default: .github)").option("--dry-run", "Preview changes without applying them").option("--exclude <regex>", "Exclude actions by regex (repeatable)").option("--min-age <days>", "Minimum age in days for updates (default: 0)", { default: 0 }).option("--yes, -y", "Skip all confirmations").command("", "Update GitHub Actions").action(async (s) => {
13
+ let u = cac("actions-up");
14
+ u.help().version(version).option("--dir <directory>", "Custom directory name (default: .github)").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("--min-age <days>", "Minimum age in days for updates (default: 0)", { default: 0 }).option("--yes, -y", "Skip all confirmations").command("", "Update GitHub Actions").action(async (c) => {
15
15
  console.info(pc.cyan("\n🚀 Actions Up!\n"));
16
- let c = createSpinner("Scanning GitHub Actions...").start();
16
+ let l = createSpinner("Scanning GitHub Actions...").start();
17
17
  try {
18
- let l = await scanGitHubActions(process.cwd(), s.dir), u = l.actions.length, d = l.workflows.size, f = l.compositeActions.size;
19
- if (c.success(`Found ${pc.yellow(u)} actions in ${pc.yellow(d)} workflows and ${pc.yellow(f)} composite actions`), u === 0) {
18
+ let u = await scanGitHubActions(process.cwd(), c.dir), d = u.actions.length, f = u.workflows.size, p = u.compositeActions.size;
19
+ if (l.success(`Found ${pc.yellow(d)} actions in ${pc.yellow(f)} workflows and ${pc.yellow(p)} composite actions`), d === 0) {
20
20
  console.info(pc.green("\n✨ No GitHub Actions found in this repository"));
21
21
  return;
22
22
  }
23
- let p = l.actions, m = [];
24
- Array.isArray(s.exclude) ? m.push(...s.exclude) : typeof s.exclude == "string" && m.push(s.exclude);
25
- let h = m.flatMap((e) => e.split(",")).map((e) => e.trim()).filter(Boolean);
26
- if (h.length > 0) {
27
- let { parseExcludePatterns: e } = await import("../core/filters/parse-exclude-patterns.js"), a = e(h);
28
- a.length > 0 && (p = p.filter((e) => {
23
+ let m = u.actions, h = [];
24
+ Array.isArray(c.exclude) ? h.push(...c.exclude) : typeof c.exclude == "string" && h.push(c.exclude);
25
+ let g = h.flatMap((e) => e.split(",")).map((e) => e.trim()).filter(Boolean);
26
+ if (g.length > 0) {
27
+ let { parseExcludePatterns: e } = await import("../core/filters/parse-exclude-patterns.js"), a = e(g);
28
+ a.length > 0 && (m = m.filter((e) => {
29
29
  let { name: o } = e;
30
30
  for (let e of a) if (e.test(o)) return !1;
31
31
  return !0;
32
32
  }));
33
33
  }
34
- if (c = createSpinner("Checking for updates...").start(), p.length === 0) {
35
- c.success("No actions to check after excludes"), console.info(pc.green("\n✨ Nothing to check after excludes\n"));
34
+ if (l = createSpinner("Checking for updates...").start(), m.length === 0) {
35
+ l.success("No actions to check after excludes"), console.info(pc.green("\n✨ Nothing to check after excludes\n"));
36
36
  return;
37
37
  }
38
- let g = await checkUpdates(p, process.env.GITHUB_TOKEN), _ = [];
39
- await Promise.all(g.map(async (e) => {
40
- await shouldIgnore(e.action.file, e.action.line) || _.push(e);
38
+ let _ = c.includeBranches ?? !1, v = await checkUpdates(m, process.env.GITHUB_TOKEN, { includeBranches: _ }), y = [];
39
+ await Promise.all(v.map(async (e) => {
40
+ await shouldIgnore(e.action.file, e.action.line) || y.push(e);
41
41
  }));
42
- let v = _.filter((e) => e.hasUpdate), y = s.minAge * 24 * 60 * 60 * 1e3, b = Date.now();
43
- v = v.filter((e) => e.publishedAt ? b - e.publishedAt.getTime() >= y : !0);
44
- let x = v.filter((e) => e.isBreaking);
45
- if (v.length === 0) {
46
- c.success("All actions are up to date!"), console.info(pc.green("\n✨ Everything is already at the latest version!\n"));
42
+ let b = y.filter((e) => e.status === "skipped"), x = y.filter((e) => e.hasUpdate), S = c.minAge * 24 * 60 * 60 * 1e3, C = Date.now();
43
+ x = x.filter((e) => e.publishedAt ? C - e.publishedAt.getTime() >= S : !0);
44
+ let w = x.filter((e) => e.isBreaking);
45
+ if (x.length === 0) {
46
+ l.success("All actions are up to date!"), b.length > 0 && printSkippedWarning(b, _), console.info(pc.green("\n✨ Everything is already at the latest version!\n"));
47
47
  return;
48
48
  }
49
- if (c.success(`Found ${pc.yellow(v.length)} updates available${x.length > 0 ? ` (${pc.redBright(x.length)} breaking)` : ""}`), s.dryRun) {
49
+ if (l.success(`Found ${pc.yellow(x.length)} updates available${w.length > 0 ? ` (${pc.redBright(w.length)} breaking)` : ""}`), b.length > 0 && printSkippedWarning(b, _), c.dryRun) {
50
50
  console.info(pc.yellow("\n📋 Dry Run - No changes will be made\n"));
51
- for (let e of v) console.info(`${pc.cyan(e.action.file ?? "unknown")}:\n${e.action.name}: ${pc.redBright(e.currentVersion)} → ${pc.green(e.latestVersion)} ${e.latestSha ? pc.gray(`(${e.latestSha.slice(0, 7)})`) : ""}\n`);
52
- console.info(pc.gray(`\n${v.length} actions would be updated\n`));
51
+ for (let e of x) console.info(`${pc.cyan(e.action.file ?? "unknown")}:\n${e.action.name}: ${pc.redBright(e.currentVersion)} → ${pc.green(e.latestVersion)} ${e.latestSha ? pc.gray(`(${e.latestSha.slice(0, 7)})`) : ""}\n`);
52
+ console.info(pc.gray(`\n${x.length} actions would be updated\n`));
53
53
  return;
54
54
  }
55
- if (s.yes) {
56
- let e = v.filter((e) => e.latestSha);
55
+ if (c.yes) {
56
+ let e = x.filter((e) => e.latestSha);
57
57
  if (e.length === 0) {
58
58
  console.info(pc.yellow("\n⚠️ No actions with SHA available for update\n"));
59
59
  return;
60
60
  }
61
61
  console.info(pc.yellow(`\n🔄 Updating ${e.length} actions...\n`)), await applyUpdates(e), console.info(pc.green("\n✓ Updates applied successfully!"));
62
62
  } else {
63
- let o = await promptUpdateSelection(_, { showAge: s.minAge > 0 });
63
+ let o = await promptUpdateSelection(y, { showAge: c.minAge > 0 });
64
64
  if (!o || o.length === 0) {
65
65
  console.info(pc.gray("\nNo updates applied"));
66
66
  return;
@@ -68,8 +68,17 @@ function run() {
68
68
  console.info(pc.yellow(`\n🔄 Updating ${o.length} selected actions...\n`)), await applyUpdates(o), console.info(pc.green("\n✓ Updates applied successfully!"));
69
69
  }
70
70
  } catch (e) {
71
- c.error("Failed"), e instanceof Error && e.name === "GitHubRateLimitError" ? (console.error(pc.yellow("\n⚠️ Rate Limit Exceeded\n")), console.error(e.message), console.error(pc.gray("\nExample: GITHUB_TOKEN=ghp_xxxx actions-up\n"))) : console.error(pc.redBright("\nError:"), e instanceof Error ? e.message : String(e)), process.exit(1);
71
+ l.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);
72
72
  }
73
- }), l.parse();
73
+ }), u.parse();
74
+ }
75
+ function printSkippedWarning(e, a) {
76
+ let o = new Intl.PluralRules("en-US", { type: "cardinal" }).select(e.length) === "one" ? "action" : "actions", s = a ? "" : " (use --include-branches to check them)";
77
+ console.info(pc.yellow(`\n⚠️ Skipped ${e.length} ${o} pinned to branches${s}`));
78
+ for (let a of e) {
79
+ let e = a.action.uses ?? `${a.action.name}@${a.currentVersion ?? "unknown"}`;
80
+ console.info(pc.gray(` • ${e}`));
81
+ }
82
+ console.info("");
74
83
  }
75
84
  export { run };
@@ -5,6 +5,9 @@ import { ActionUpdate } from '../../types/action-update';
5
5
  *
6
6
  * @param actions - Array of GitHub Actions to check.
7
7
  * @param token - Optional GitHub token for authentication.
8
+ * @param options - Additional options (e.g., include branch refs).
8
9
  * @returns Array of update information.
9
10
  */
10
- export declare function checkUpdates(actions: GitHubAction[], token?: string): Promise<ActionUpdate[]>;
11
+ export declare function checkUpdates(actions: GitHubAction[], token?: string, options?: {
12
+ includeBranches?: boolean;
13
+ }): Promise<ActionUpdate[]>;
@@ -1,18 +1,18 @@
1
1
  import { createGitHubClient } from "./create-github-client.js";
2
2
  import semver from "semver";
3
- async function checkUpdates(n, i) {
4
- let c = createGitHubClient(i), l = n.filter((e) => e.type === "external" || e.type === "reusable-workflow");
5
- if (l.length === 0) return [];
6
- let u = /* @__PURE__ */ new Map();
7
- for (let e of l) {
8
- let t = u.get(e.name) ?? [];
9
- t.push(e), u.set(e.name, t);
3
+ async function checkUpdates(n, i, c) {
4
+ let l = createGitHubClient(i), u = c?.includeBranches ?? !1, d = n.filter((e) => e.type === "external" || e.type === "reusable-workflow");
5
+ if (d.length === 0) return [];
6
+ let f = /* @__PURE__ */ new Map();
7
+ for (let e of d) {
8
+ let t = f.get(e.name) ?? [];
9
+ t.push(e), f.set(e.name, t);
10
10
  }
11
- let d = {
11
+ let p = {
12
12
  rateLimitError: null,
13
13
  rateLimitHit: !1
14
- }, f = await [...u.keys()].reduce((e, n) => e.then(async (e) => {
15
- if (d.rateLimitHit) return [...e, {
14
+ }, m = await [...f.keys()].reduce((e, n) => e.then(async (e) => {
15
+ if (p.rateLimitHit) return [...e, {
16
16
  publishedAt: null,
17
17
  version: null,
18
18
  actionName: n,
@@ -25,24 +25,26 @@ async function checkUpdates(n, i) {
25
25
  actionName: n,
26
26
  sha: null
27
27
  }];
28
- let [i, l] = r;
29
- if (!i || !l) return [...e, {
28
+ let [i, c] = r;
29
+ if (!i || !c) return [...e, {
30
30
  publishedAt: null,
31
31
  version: null,
32
32
  actionName: n,
33
33
  sha: null
34
34
  }];
35
35
  try {
36
- let r = u.get(n)[0]?.version;
37
- if (r && !isSha(r) && !isSemverLike(r) && await c.getRefType(i, l, r) === "branch") return [...e, {
36
+ let r = f.get(n)[0]?.version;
37
+ if (r && !isSha(r) && !isSemverLike(r) && await l.getRefType(i, c, r) === "branch" && !u) return [...e, {
38
+ skipReason: "branch",
39
+ status: "skipped",
38
40
  publishedAt: null,
39
41
  version: null,
40
42
  actionName: n,
41
43
  sha: null
42
44
  }];
43
- let d = await c.getLatestRelease(i, l);
45
+ let d = await l.getLatestRelease(i, c);
44
46
  if (!d) {
45
- let e = await c.getAllReleases(i, l, 1);
47
+ let e = await l.getAllReleases(i, c, 1);
46
48
  d = e.find((e) => !e.isPrerelease) ?? e[0] ?? null;
47
49
  }
48
50
  if (d) {
@@ -52,7 +54,7 @@ async function checkUpdates(n, i) {
52
54
  f = !n || r || !i;
53
55
  }
54
56
  if (f) {
55
- let r = await c.getAllTags(i, l, 30);
57
+ let r = await l.getAllTags(i, c, 30);
56
58
  if (r.length > 0) {
57
59
  let u = r.filter((e) => isSemverLike(e.tag)).map((e) => ({
58
60
  v: semver.valid(normalizeVersion(e.tag)),
@@ -69,7 +71,7 @@ async function checkUpdates(n, i) {
69
71
  if (!s || semver.gt(u[0].v, s) || semver.eq(u[0].v, s) && /\d+\.\d+/u.test(r.tag)) {
70
72
  let t = r.tag, a = r.sha?.length ? r.sha : null;
71
73
  if (!a && t) try {
72
- a = await c.getTagSha(i, l, t);
74
+ a = await l.getTagSha(i, c, t);
73
75
  } catch {}
74
76
  return [...e, {
75
77
  version: t,
@@ -82,18 +84,19 @@ async function checkUpdates(n, i) {
82
84
  }
83
85
  }
84
86
  if (!u && o) try {
85
- u = await c.getTagSha(i, l, o);
87
+ u = await l.getTagSha(i, c, o);
86
88
  } catch {}
87
89
  return [...e, {
90
+ status: "ok",
88
91
  publishedAt: r,
89
92
  actionName: n,
90
93
  version: o,
91
94
  sha: u
92
95
  }];
93
96
  }
94
- let f = await c.getAllTags(i, l, 30);
95
- if (f.length > 0) {
96
- let r = f.filter((e) => isSemverLike(e.tag)).map((e) => ({
97
+ let p = await l.getAllTags(i, c, 30);
98
+ if (p.length > 0) {
99
+ let r = p.filter((e) => isSemverLike(e.tag)).map((e) => ({
97
100
  v: semver.valid(normalizeVersion(e.tag)),
98
101
  raw: e
99
102
  })), o;
@@ -102,12 +105,13 @@ async function checkUpdates(n, i) {
102
105
  if (r !== 0) return r;
103
106
  let i = /\d+\.\d+/u.test(e.raw.tag) ? 1 : 0;
104
107
  return (/\d+\.\d+/u.test(n.raw.tag) ? 1 : 0) - i;
105
- }), o = r[0].raw) : o = f[0];
108
+ }), o = r[0].raw) : o = p[0];
106
109
  let u = o.tag, d = o.sha?.length ? o.sha : null;
107
110
  if (!d && u) try {
108
- d = await c.getTagSha(i, l, u);
111
+ d = await l.getTagSha(i, c, u);
109
112
  } catch {}
110
113
  return [...e, {
114
+ status: "ok",
111
115
  publishedAt: null,
112
116
  actionName: n,
113
117
  version: u,
@@ -121,7 +125,7 @@ async function checkUpdates(n, i) {
121
125
  sha: null
122
126
  }];
123
127
  } catch (t) {
124
- return t instanceof Error && t.name === "GitHubRateLimitError" ? (d.rateLimitHit = !0, d.rateLimitError = t, [...e, {
128
+ return t instanceof Error && t.name === "GitHubRateLimitError" ? (p.rateLimitHit = !0, p.rateLimitError = t, [...e, {
125
129
  publishedAt: null,
126
130
  version: null,
127
131
  actionName: n,
@@ -134,52 +138,71 @@ async function checkUpdates(n, i) {
134
138
  }]);
135
139
  }
136
140
  }), Promise.resolve([]));
137
- if (d.rateLimitError) {
138
- let e = !!(i ?? process.env.GITHUB_TOKEN), t = `${d.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#using-github-token-for-higher-rate-limits"}`, n = Error(t);
141
+ if (p.rateLimitError) {
142
+ let e = !!(i ?? process.env.GITHUB_TOKEN), t = `${p.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#using-github-token-for-higher-rate-limits"}`, n = Error(t);
139
143
  throw n.name = "GitHubRateLimitError", n;
140
144
  }
141
- let p = /* @__PURE__ */ new Map();
142
- for (let e of f) p.set(e.actionName, {
145
+ let h = /* @__PURE__ */ new Map();
146
+ for (let e of m) h.set(e.actionName, {
143
147
  publishedAt: e.publishedAt,
148
+ actionName: e.actionName,
149
+ skipReason: e.skipReason,
144
150
  version: e.version,
151
+ status: e.status,
145
152
  sha: e.sha
146
153
  });
147
- let m = [];
148
- for (let e of l) {
149
- let t = p.get(e.name);
150
- t ? m.push(createUpdate(e, {
154
+ let g = [];
155
+ for (let e of d) {
156
+ let t = h.get(e.name);
157
+ t ? g.push(createUpdate(e, {
151
158
  publishedAt: t.publishedAt,
152
159
  version: t.version,
153
160
  sha: t.sha
154
- })) : m.push(createUpdate(e, {
161
+ }, {
162
+ skipReason: t.skipReason,
163
+ status: t.status
164
+ })) : g.push(createUpdate(e, {
155
165
  publishedAt: null,
156
166
  version: null,
157
167
  sha: null
158
168
  }));
159
169
  }
160
- return m;
170
+ return g;
161
171
  }
162
- function createUpdate(e, n) {
163
- let { version: r, sha: s, publishedAt: c } = n, l = normalizeVersion(e.version ?? ""), u = r ? normalizeVersion(r) : null, d = !1, f = !1;
164
- if (l && isSha(l)) s ? d = !compareSha(l, s) : u && (d = !0);
165
- else if (l && u) {
166
- let n = semver.valid(l), r = semver.valid(u);
172
+ function createUpdate(e, n, r = {}) {
173
+ let { version: s, sha: c, publishedAt: l } = n, u = e.version ?? "unknown", d = normalizeVersion(u), f = s ? normalizeVersion(s) : null, p = r.status ?? "ok", m = r.skipReason, h = !1, g = !1;
174
+ if (p === "skipped") return {
175
+ currentVersion: u,
176
+ isBreaking: !1,
177
+ hasUpdate: !1,
178
+ latestVersion: s,
179
+ publishedAt: l,
180
+ skipReason: m,
181
+ latestSha: c,
182
+ action: e,
183
+ status: p
184
+ };
185
+ if (d && isSha(d)) c ? h = !compareSha(d, c) : f && (h = !0);
186
+ else if (d && f) {
187
+ let n = semver.valid(d), r = semver.valid(f);
167
188
  if (n && r) {
168
- if (d = semver.lt(n, r), d) {
189
+ if (h = semver.lt(n, r), h) {
169
190
  let e = semver.major(n);
170
- f = semver.major(r) > e;
191
+ g = semver.major(r) > e;
171
192
  }
172
- !d && semver.eq(n, r) && !isSha(e.version) && s && (d = !0, f = !1);
173
- } else l !== u && (d = !0);
193
+ !h && semver.eq(n, r) && !isSha(e.version) && c && (h = !0, g = !1);
194
+ } else d !== f && (h = !0);
174
195
  }
175
196
  return {
176
- currentVersion: e.version ?? "unknown",
177
- latestVersion: r,
178
- publishedAt: c,
179
- isBreaking: f,
180
- latestSha: s,
181
- hasUpdate: d,
182
- action: e
197
+ currentVersion: u,
198
+ latestVersion: s,
199
+ publishedAt: l,
200
+ isBreaking: g,
201
+ skipReason: m,
202
+ latestSha: c,
203
+ hasUpdate: h,
204
+ action: e,
205
+ status: p
183
206
  };
184
207
  }
185
208
  function compareSha(e, t) {
@@ -39,14 +39,14 @@ async function promptUpdateSelection(l, g = {}) {
39
39
  display: a
40
40
  };
41
41
  })), C = [], w = stripAnsi("Action").length, T = stripAnsi("Current").length, E = stripAnsi("Job").length, D = 0, O = !1;
42
- for (let [a, s] of b.entries()) {
43
- let c = s.action.name, l = S[a].display, u = s.action.job ?? "–";
44
- if (w = Math.max(w, c.length), T = Math.max(T, stripAnsi(l).length), E = Math.max(E, u.length), s.latestVersion) {
45
- let c = formatVersion(s.latestVersion, S[a]?.effectiveForDiff ?? s.currentVersion);
46
- D = Math.max(D, stripAnsi(c).length);
42
+ for (let [a, l] of b.entries()) {
43
+ let u = l.action.name, d = S[a], f = d.display, p = l.action.job ?? "–";
44
+ if (w = Math.max(w, u.length), T = Math.max(T, stripAnsi(f).length, d.versionForPadding && d.shortSha ? stripAnsi(`${padString(d.versionForPadding, D + 1)}${pc.gray(`(${d.shortSha})`)}`).length : 0), E = Math.max(E, p.length), l.latestVersion) {
45
+ let s = formatVersion(l.latestVersion, S[a]?.effectiveForDiff ?? l.currentVersion);
46
+ D = Math.max(D, stripAnsi(s).length);
47
47
  }
48
- let d = S[a]?.versionForPadding;
49
- d && (D = Math.max(D, stripAnsi(d).length)), s.publishedAt && (O = !0);
48
+ let m = S[a]?.versionForPadding;
49
+ m && (D = Math.max(D, stripAnsi(m).length)), l.publishedAt && (O = !0);
50
50
  }
51
51
  let k = Math.max(w, MIN_ACTION_WIDTH), A = Math.max(T, MIN_CURRENT_WIDTH), j = Math.max(E, MIN_JOB_WIDTH), M = Math.min(D, MAX_VERSION_WIDTH), N = M + 1 + 9, P = y && O ? 6 : 0, F = [...x.keys()].toSorted();
52
52
  for (let [a, o] of F.entries()) {
package/dist/package.js CHANGED
@@ -1,2 +1,2 @@
1
- const version = "1.6.0";
1
+ const version = "1.7.0";
2
2
  export { version };
@@ -1,12 +1,18 @@
1
1
  import { GitHubAction } from './github-action';
2
2
  /** Update information for a GitHub Action. */
3
3
  export interface ActionUpdate {
4
+ /** Reason for skipping the update check. */
5
+ skipReason?: 'unknown' | 'branch'
6
+
4
7
  /** Current version string. */
5
8
  currentVersion: string | null
6
9
 
7
10
  /** Latest available version. */
8
11
  latestVersion: string | null
9
12
 
13
+ /** Status of the check for this action. */
14
+ status?: 'skipped' | 'ok'
15
+
10
16
  /** SHA hash of the latest version. */
11
17
  latestSha: string | null
12
18
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "actions-up",
3
- "version": "1.6.0",
3
+ "version": "1.7.0",
4
4
  "description": "Interactive CLI tool to update GitHub Actions to latest versions with SHA pinning",
5
5
  "keywords": [
6
6
  "github-actions",
@@ -41,7 +41,7 @@
41
41
  "nanospinner": "^1.2.2",
42
42
  "picocolors": "^1.1.1",
43
43
  "semver": "^7.7.3",
44
- "yaml": "^2.8.1"
44
+ "yaml": "^2.8.2"
45
45
  },
46
46
  "engines": {
47
47
  "node": "^18.0.0 || >=20.0.0"
package/readme.md CHANGED
@@ -131,6 +131,10 @@ By default, Actions Up scans the `.github` directory. You can specify a differen
131
131
  npx actions-up --dir .gitea
132
132
  ```
133
133
 
134
+ ### Branch References
135
+
136
+ By default, actions pinned to branch refs (e.g., `@main`, `@release/v1`) are skipped to avoid changing intentionally floating references. Skipped entries are listed in the output. To include them in update checks, pass `--include-branches`.
137
+
134
138
  ## GitHub Actions Integration
135
139
 
136
140
  ### Automated PR Checks