actions-up 1.4.2 → 1.5.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
@@ -11,11 +11,11 @@ import pc from "picocolors";
11
11
  import cac from "cac";
12
12
  function run() {
13
13
  let l = cac("actions-up");
14
- l.help().version(version).option("--dry-run", "Preview changes without applying them").option("--exclude <regex>", "Exclude actions by regex (repeatable)").option("--yes, -y", "Skip all confirmations").command("", "Update GitHub Actions").action(async (s) => {
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("--yes, -y", "Skip all confirmations").command("", "Update GitHub Actions").action(async (s) => {
15
15
  console.info(pc.cyan("\nšŸš€ Actions Up!\n"));
16
16
  let c = createSpinner("Scanning GitHub Actions...").start();
17
17
  try {
18
- let l = await scanGitHubActions(process.cwd()), u = l.actions.length, d = l.workflows.size, f = l.compositeActions.size;
18
+ let l = await scanGitHubActions(process.cwd(), s.dir), u = l.actions.length, d = l.workflows.size, f = l.compositeActions.size;
19
19
  if (c.success(`Found ${pc.yellow(u)} actions in ${pc.yellow(d)} workflows and ${pc.yellow(f)} composite actions`), u === 0) {
20
20
  console.info(pc.green("\n✨ No GitHub Actions found in this repository"));
21
21
  return;
@@ -163,7 +163,6 @@ function createUpdate(e, r, i) {
163
163
  };
164
164
  }
165
165
  function compareSha(e, n) {
166
- if (!e || !n) return !1;
167
166
  let r = e.replace(/^v/u, ""), i = n.replace(/^v/u, ""), a = Math.min(r.length, i.length);
168
167
  return a < 7 ? !1 : r.slice(0, Math.max(0, a)).toLowerCase() === i.slice(0, Math.max(0, a)).toLowerCase();
169
168
  }
@@ -27,7 +27,7 @@ async function applyUpdates(n) {
27
27
  console.error(`Invalid SHA format: ${e.latestSha}`);
28
28
  continue;
29
29
  }
30
- let a = r ? String.raw`(?=[^\S\r\n]|$|#)` : "", o = RegExp(`(^\\s*-?\\s*uses:\\s*)(['"]?)(${n})@${r}\\2${a}([^\\S\\r\\n]*#[^\\r\\n]*)?`, "gm"), s = `$1$2$3@${e.latestSha}$2 # ${e.latestVersion}`;
30
+ let a = r ? String.raw`(?=[^\S\r\n]|$|#)` : "", o = new RegExp(String.raw`(^\s*-?\s*uses:\s*)(['"]?)(${n})@${r}\2${a}([^\S\r\n]*#[^\r\n]*)?`, "gm"), s = `$1$2$3@${e.latestSha}$2 # ${e.latestVersion}`;
31
31
  i = i.replace(o, s);
32
32
  }
33
33
  await writeFile(n, i, "utf8");
@@ -79,16 +79,14 @@ async function promptUpdateSelection(o) {
79
79
  name: ""
80
80
  });
81
81
  else {
82
- let i = l[e - 1];
83
- if (!i) continue;
84
- let { update: a, index: s } = i, c = !!a.latestSha, u = c && !a.isBreaking;
82
+ let { update: i, index: a } = l[e - 1], s = !!i.latestSha, c = s && !i.isBreaking;
85
83
  h.push({
86
84
  message: o,
87
- value: String(s),
88
- name: String(s),
89
- disabled: !c,
85
+ value: String(a),
86
+ name: String(a),
87
+ disabled: !s,
90
88
  indent: "",
91
- enabled: u
89
+ enabled: c
92
90
  });
93
91
  }
94
92
  }
@@ -171,7 +169,6 @@ function formatTableRow(e, i, a) {
171
169
  ].join(" ").replace(/\s+$/u, "");
172
170
  }
173
171
  function isSha(e) {
174
- if (!e) return !1;
175
172
  let i = e.replace(/^v/u, "");
176
173
  return /^[0-9a-f]{7,40}$/iu.test(i);
177
174
  }
@@ -8,10 +8,12 @@ import { ScanResult } from '../types/scan-result';
8
8
  *
9
9
  * @param rootPath - The root path of the repository to scan. Defaults to
10
10
  * current working directory.
11
+ * @param ciDirectory - The CI directory name (e.g., '.github' or '.gitea').
12
+ * Defaults to '.github'.
11
13
  * @returns A promise that resolves to a ScanResult containing:
12
14
  *
13
15
  * - Workflows: Map of workflow file paths to their referenced actions
14
16
  * - CompositeActions: Map of composite action names to their directory paths
15
17
  * - Actions: Flat array of all discovered GitHub Actions.
16
18
  */
17
- export declare function scanGitHubActions(rootPath?: string): Promise<ScanResult>;
19
+ export declare function scanGitHubActions(rootPath?: string, ciDirectory?: string): Promise<ScanResult>;
@@ -4,96 +4,85 @@ import { scanActionFile } from "./scan-action-file.js";
4
4
  import { isYamlFile } from "./fs/is-yaml-file.js";
5
5
  import { readFile, readdir, stat } from "node:fs/promises";
6
6
  import { isAbsolute, join, relative, resolve } from "node:path";
7
- async function scanGitHubActions(d = process.cwd()) {
8
- let m = {
7
+ async function scanGitHubActions(d = process.cwd(), m = GITHUB_DIRECTORY) {
8
+ let h = {
9
9
  compositeActions: /* @__PURE__ */ new Map(),
10
10
  workflows: /* @__PURE__ */ new Map(),
11
11
  actions: []
12
- }, h = resolve(d);
13
- function g(e, o) {
12
+ }, g = resolve(d);
13
+ function _(e, o) {
14
14
  let s = relative(e, o);
15
15
  return s !== "" && !s.startsWith("..") && !isAbsolute(s);
16
16
  }
17
- let _ = join(h, GITHUB_DIRECTORY);
18
- if (!g(h, _)) throw Error("Invalid path: detected path traversal attempt");
19
- function v(e) {
17
+ let v = join(g, m);
18
+ if (!_(g, v)) throw Error("Invalid path: detected path traversal attempt");
19
+ function y(e) {
20
20
  return e.includes("..") || e.includes("/") || e.includes("\\") ? (console.warn(`Skipping invalid name: ${e}`), !1) : !0;
21
21
  }
22
- let y = join(_, WORKFLOWS_DIRECTORY);
23
- if (!g(h, y)) return m;
22
+ let b = join(v, WORKFLOWS_DIRECTORY);
24
23
  try {
25
- if ((await stat(y)).isDirectory()) {
26
- let e = (await readdir(y)).filter((e) => v(e) ? isYamlFile(e) : !1).map(async (e) => {
27
- let l = join(y, e);
28
- if (!g(y, l)) return console.warn(`Skipping file outside workflows directory: ${e}`), {
29
- success: !1,
30
- actions: [],
31
- path: ""
32
- };
24
+ if ((await stat(b)).isDirectory()) {
25
+ let e = (await readdir(b)).filter((e) => y(e) ? isYamlFile(e) : !1).map(async (e) => {
26
+ let o = join(b, e);
33
27
  try {
34
- let u = await scanWorkflowFile(l);
28
+ let l = await scanWorkflowFile(o);
35
29
  return {
36
- path: `${GITHUB_DIRECTORY}/${WORKFLOWS_DIRECTORY}/${e}`,
30
+ path: `${m}/${WORKFLOWS_DIRECTORY}/${e}`,
37
31
  success: !0,
38
- actions: u
32
+ actions: l
39
33
  };
40
34
  } catch {
41
35
  return {
42
- path: `${GITHUB_DIRECTORY}/${WORKFLOWS_DIRECTORY}/${e}`,
36
+ path: `${m}/${WORKFLOWS_DIRECTORY}/${e}`,
43
37
  success: !1,
44
38
  actions: []
45
39
  };
46
40
  }
47
- }), l = await Promise.all(e);
48
- for (let e of l) e.success && e.path && (e.actions.length > 0 ? (m.workflows.set(e.path, e.actions), m.actions.push(...e.actions)) : m.workflows.set(e.path, []));
41
+ }), o = await Promise.all(e);
42
+ for (let e of o) 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, []));
49
43
  }
50
44
  } catch {}
51
- let b = join(_, ACTIONS_DIRECTORY);
52
- if (!g(h, b)) return m;
45
+ let x = join(v, ACTIONS_DIRECTORY);
53
46
  try {
54
- if ((await stat(b)).isDirectory()) {
55
- let s = (await readdir(b)).map(async (s) => {
56
- if (!v(s)) return null;
57
- let c = join(b, s);
58
- if (!g(b, c)) return console.warn(`Skipping subdirectory outside actions path: ${s}`), null;
47
+ if ((await stat(x)).isDirectory()) {
48
+ let o = (await readdir(x)).map(async (o) => {
49
+ if (!y(o)) return null;
50
+ let s = join(x, o);
59
51
  try {
60
- if (!(await stat(c)).isDirectory()) return null;
61
- let u = join(c, "action.yml");
62
- if (!g(c, u)) return null;
63
- let d = [];
52
+ if (!(await stat(s)).isDirectory()) return null;
53
+ let c = join(s, "action.yml"), u = [];
64
54
  try {
65
- d = await scanActionFile(u);
55
+ u = await scanActionFile(c);
66
56
  } catch {
67
57
  try {
68
- if (u = join(c, "action.yaml"), !g(c, u)) return null;
69
- d = await scanActionFile(u);
58
+ c = join(s, "action.yaml"), u = await scanActionFile(c);
70
59
  } catch {
71
60
  return null;
72
61
  }
73
62
  }
74
63
  return {
75
- path: `${GITHUB_DIRECTORY}/${ACTIONS_DIRECTORY}/${s}`,
76
- name: s,
77
- actions: d
64
+ path: `${m}/${ACTIONS_DIRECTORY}/${o}`,
65
+ name: o,
66
+ actions: u
78
67
  };
79
68
  } catch {
80
69
  return null;
81
70
  }
82
- }), c = await Promise.all(s);
83
- for (let e of c) e && (m.compositeActions.set(e.name, e.path), m.actions.push(...e.actions));
71
+ }), s = await Promise.all(o);
72
+ for (let e of s) e && (h.compositeActions.set(e.name, e.path), h.actions.push(...e.actions));
84
73
  }
85
74
  } catch {}
86
75
  try {
87
- let e = await getCurrentRepoSlug(h);
76
+ let e = await getCurrentRepoSlug(g);
88
77
  if (e) {
89
78
  if (process.env.ACTIONS_UP_TEST_THROW === "1") throw Error("test");
90
79
  let o = /* @__PURE__ */ new Set(), s = [];
91
- for (let c of m.actions) {
80
+ for (let c of h.actions) {
92
81
  if (c.type !== "external") continue;
93
82
  let l = c.name.split("/");
94
83
  if (l.length < 3 || `${l[0]}/${l[1]}` !== e) continue;
95
- let u = join(h, ...l.slice(2));
96
- g(h, u) && (o.has(u) || (o.add(u), s.push(u)));
84
+ let u = join(g, ...l.slice(2));
85
+ _(g, u) && (o.has(u) || (o.add(u), s.push(u)));
97
86
  }
98
87
  async function c() {
99
88
  if (s.length === 0) return;
@@ -107,14 +96,14 @@ async function scanGitHubActions(d = process.cwd()) {
107
96
  d = u;
108
97
  }
109
98
  let f = await scanActionFile(d);
110
- f.length > 0 && m.actions.push(...f);
99
+ f.length > 0 && h.actions.push(...f);
111
100
  let p = [];
112
101
  for (let s of f) {
113
102
  if (s.type !== "external") continue;
114
103
  let c = s.name.split("/");
115
104
  if (c.length < 3 || `${c[0]}/${c[1]}` !== e) continue;
116
- let l = join(h, ...c.slice(2));
117
- g(h, l) && (o.has(l) || (o.add(l), p.push(l)));
105
+ let l = join(g, ...c.slice(2));
106
+ _(g, l) && (o.has(l) || (o.add(l), p.push(l)));
118
107
  }
119
108
  return p;
120
109
  } catch {
@@ -127,7 +116,7 @@ async function scanGitHubActions(d = process.cwd()) {
127
116
  await c();
128
117
  }
129
118
  } catch {}
130
- return m;
119
+ return h;
131
120
  }
132
121
  async function getCurrentRepoSlug(e) {
133
122
  let o = process.env.GITHUB_REPOSITORY;
package/dist/package.js CHANGED
@@ -1,2 +1,2 @@
1
- const version = "1.4.2";
1
+ const version = "1.5.0";
2
2
  export { version };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "actions-up",
3
- "version": "1.4.2",
3
+ "version": "1.5.0",
4
4
  "description": "Interactive CLI tool to update GitHub Actions to latest versions with SHA pinning",
5
5
  "keywords": [
6
6
  "github-actions",
package/readme.md CHANGED
@@ -122,6 +122,14 @@ Check for updates without making any changes:
122
122
  npx actions-up --dry-run
123
123
  ```
124
124
 
125
+ ### Custom Directory
126
+
127
+ By default, Actions Up scans the `.github` directory. You can specify a different directory (e.g., for Gitea):
128
+
129
+ ```bash
130
+ npx actions-up --dir .gitea
131
+ ```
132
+
125
133
  ## GitHub Actions Integration
126
134
 
127
135
  ### Automated PR Checks