actionspack 0.1.3 → 0.1.5
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/README.md +13 -0
- package/dist/cli.mjs +2 -2
- package/dist/{commands-4KKgssQI.mjs → commands-BayB-wc-.mjs} +28 -66
- package/dist/index.mjs +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -76,6 +76,19 @@ git diff
|
|
|
76
76
|
Review the dependency SHA changes in `.github/workflow.lock.yml` and the
|
|
77
77
|
resulting generated workflow changes before committing.
|
|
78
78
|
|
|
79
|
+
### VS Code
|
|
80
|
+
|
|
81
|
+
Generated workflows should not be edited by hand. Consider marking them as
|
|
82
|
+
read-only in your workspace settings:
|
|
83
|
+
|
|
84
|
+
```json
|
|
85
|
+
{
|
|
86
|
+
"files.readonlyInclude": {
|
|
87
|
+
".github/workflows/*.yml": true
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
79
92
|
## Commands
|
|
80
93
|
|
|
81
94
|
```bash
|
package/dist/cli.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as why, f as scan, i as update, l as verify, r as tree, s as pack, t as diff } from "./commands-
|
|
2
|
+
import { a as why, f as scan, i as update, l as verify, r as tree, s as pack, t as diff } from "./commands-BayB-wc-.mjs";
|
|
3
3
|
import { styleText } from "node:util";
|
|
4
4
|
import process from "node:process";
|
|
5
5
|
import { cac } from "cac";
|
|
6
6
|
//#region package.json
|
|
7
7
|
var name = "actionspack";
|
|
8
|
-
var version = "0.1.
|
|
8
|
+
var version = "0.1.5";
|
|
9
9
|
//#endregion
|
|
10
10
|
//#region src/cli.ts
|
|
11
11
|
const cli = cac(name);
|
|
@@ -134,13 +134,11 @@ function evaluateStaticExpression(expr, values) {
|
|
|
134
134
|
const data = new Evaluator(expr, expressionContext(values)).evaluate();
|
|
135
135
|
return {
|
|
136
136
|
data,
|
|
137
|
-
text:
|
|
137
|
+
text: valueLiteral(dataValue(data)),
|
|
138
138
|
truthy: truthy(data),
|
|
139
139
|
value: dataValue(data)
|
|
140
140
|
};
|
|
141
|
-
} catch {
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
141
|
+
} catch {}
|
|
144
142
|
}
|
|
145
143
|
function hasValueForIndexAccess(expr, values) {
|
|
146
144
|
const key = indexAccessKey(expr);
|
|
@@ -213,9 +211,6 @@ function dataValue(value) {
|
|
|
213
211
|
if (value instanceof data.StringData) return value.value;
|
|
214
212
|
return null;
|
|
215
213
|
}
|
|
216
|
-
function dataLiteral(value) {
|
|
217
|
-
return valueLiteral(dataValue(value));
|
|
218
|
-
}
|
|
219
214
|
function replacementForIndexAccess(expr, values) {
|
|
220
215
|
if (!hasValueForIndexAccess(expr, values)) return;
|
|
221
216
|
const value = valueForIndexAccess(expr, values);
|
|
@@ -282,7 +277,7 @@ function simplifyFormatString(format, args) {
|
|
|
282
277
|
if (!rawIndex) return;
|
|
283
278
|
const arg = args[Number(rawIndex)];
|
|
284
279
|
if (!arg) return;
|
|
285
|
-
if (arg.static) nextFormat +=
|
|
280
|
+
if (arg.static) nextFormat += arg.static.data.coerceString().replaceAll("{", "{{").replaceAll("}", "}}");
|
|
286
281
|
else {
|
|
287
282
|
const nextIndex = nextArgs.push(arg.text) - 1;
|
|
288
283
|
nextFormat += `{${nextIndex}}`;
|
|
@@ -295,11 +290,9 @@ function simplifyFormatString(format, args) {
|
|
|
295
290
|
format: nextFormat
|
|
296
291
|
};
|
|
297
292
|
}
|
|
298
|
-
function escapeFormatLiteral(value) {
|
|
299
|
-
return value.replaceAll("{", "{{").replaceAll("}", "}}");
|
|
300
|
-
}
|
|
301
293
|
//#endregion
|
|
302
294
|
//#region src/utils/yaml.ts
|
|
295
|
+
const GENERATED_FILE_NOTICE = "# This file is generated by actionspack. Do not edit it manually.\n\n";
|
|
303
296
|
function parseYamlMap(source, file) {
|
|
304
297
|
const value = parse(source);
|
|
305
298
|
if (!isRecord(value)) throw new TypeError(`${file} must contain a YAML mapping`);
|
|
@@ -313,7 +306,7 @@ function stringifyYaml(value) {
|
|
|
313
306
|
});
|
|
314
307
|
}
|
|
315
308
|
function stringifyWorkflowYaml(value) {
|
|
316
|
-
return formatWorkflowYaml(stringifyYaml(normalizeWorkflowYamlValue(value)))
|
|
309
|
+
return `${GENERATED_FILE_NOTICE}${formatWorkflowYaml(stringifyYaml(normalizeWorkflowYamlValue(value)))}`;
|
|
317
310
|
}
|
|
318
311
|
function isRecord(value) {
|
|
319
312
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -330,7 +323,7 @@ function formatWorkflowYaml(source) {
|
|
|
330
323
|
let stepsIndent;
|
|
331
324
|
let stepItemIndent;
|
|
332
325
|
for (const line of lines) {
|
|
333
|
-
const indent =
|
|
326
|
+
const indent = line.length - line.trimStart().length;
|
|
334
327
|
const trimmed = line.trim();
|
|
335
328
|
const isTopLevelKey = indent === 0 && /^[\w-]+:/u.test(line);
|
|
336
329
|
if (stepsIndent !== void 0 && trimmed && indent <= stepsIndent) {
|
|
@@ -350,9 +343,6 @@ function formatWorkflowYaml(source) {
|
|
|
350
343
|
}
|
|
351
344
|
return `${output.join("\n")}\n`;
|
|
352
345
|
}
|
|
353
|
-
function leadingSpaces(value) {
|
|
354
|
-
return value.length - value.trimStart().length;
|
|
355
|
-
}
|
|
356
346
|
function pushBlankLine(lines) {
|
|
357
347
|
if (lines.length > 0 && lines.at(-1) !== "") lines.push("");
|
|
358
348
|
}
|
|
@@ -367,7 +357,7 @@ function normalizeWorkflowYamlValue(value) {
|
|
|
367
357
|
//#region src/optimizer.ts
|
|
368
358
|
function optimizeJob(job) {
|
|
369
359
|
const next = { ...job };
|
|
370
|
-
if (
|
|
360
|
+
if (Array.isArray(next.needs) && next.needs.length === 0) delete next.needs;
|
|
371
361
|
if (staticIfValue(next.if) === true) delete next.if;
|
|
372
362
|
return next;
|
|
373
363
|
}
|
|
@@ -395,9 +385,6 @@ function staticIfValue(value) {
|
|
|
395
385
|
const trimmed = value.trim();
|
|
396
386
|
return staticIfExpression(expressionBody(trimmed) ?? trimmed);
|
|
397
387
|
}
|
|
398
|
-
function isEmptyNeeds(value) {
|
|
399
|
-
return Array.isArray(value) && value.length === 0;
|
|
400
|
-
}
|
|
401
388
|
//#endregion
|
|
402
389
|
//#region src/utils/workflow-parser.ts
|
|
403
390
|
const workflowParserEntry = fileURLToPath(import.meta.resolve("@actions/workflow-parser"));
|
|
@@ -405,7 +392,8 @@ const workflowParserDist = path.dirname(workflowParserEntry);
|
|
|
405
392
|
let actionSchema;
|
|
406
393
|
let workflowSchema;
|
|
407
394
|
function parseWorkflowMap(source, file) {
|
|
408
|
-
|
|
395
|
+
workflowSchema ??= loadSchema("workflow-v1.0.min.json");
|
|
396
|
+
return parseTemplateMap(WORKFLOW_ROOT, workflowSchema, source, file);
|
|
409
397
|
}
|
|
410
398
|
function parseActionMap(source, file) {
|
|
411
399
|
return parseTemplateMap(ACTION_ROOT, actionSchemaForParser(), source, file);
|
|
@@ -448,10 +436,6 @@ function templateTokenToValue(token) {
|
|
|
448
436
|
if (isBasicExpression(token)) return token.toString();
|
|
449
437
|
return token.toJSON();
|
|
450
438
|
}
|
|
451
|
-
function workflowSchemaForParser() {
|
|
452
|
-
workflowSchema ??= loadSchema("workflow-v1.0.min.json");
|
|
453
|
-
return workflowSchema;
|
|
454
|
-
}
|
|
455
439
|
function actionSchemaForParser() {
|
|
456
440
|
actionSchema ??= loadSchema("action-v1.0.min.json");
|
|
457
441
|
return actionSchema;
|
|
@@ -479,13 +463,6 @@ async function fileExists(file) {
|
|
|
479
463
|
async function readYamlFile(file) {
|
|
480
464
|
return parseYamlMap(await readFile(file, "utf8"), file);
|
|
481
465
|
}
|
|
482
|
-
async function readWorkflowFile(file) {
|
|
483
|
-
return parseWorkflowMap(await readFile(file, "utf8"), file);
|
|
484
|
-
}
|
|
485
|
-
async function writeYamlFile(file, value) {
|
|
486
|
-
await mkdir(path.dirname(file), { recursive: true });
|
|
487
|
-
await writeFile(file, stringifyYaml(value), "utf8");
|
|
488
|
-
}
|
|
489
466
|
async function discoverConfig(cwd, overrides = {}) {
|
|
490
467
|
const root = resolveCwd(cwd);
|
|
491
468
|
const configPath = path.join(root, "actionspack.yml");
|
|
@@ -508,7 +485,8 @@ async function discoverConfig(cwd, overrides = {}) {
|
|
|
508
485
|
} else config = await discoverDefaultConfig(root);
|
|
509
486
|
return {
|
|
510
487
|
...config,
|
|
511
|
-
...
|
|
488
|
+
...overrides.entries ? { entries: overrides.entries } : {},
|
|
489
|
+
...overrides.external ? { external: overrides.external } : {}
|
|
512
490
|
};
|
|
513
491
|
}
|
|
514
492
|
async function discoverDefaultConfig(root) {
|
|
@@ -525,31 +503,23 @@ async function discoverDefaultConfig(root) {
|
|
|
525
503
|
}))
|
|
526
504
|
};
|
|
527
505
|
}
|
|
528
|
-
function normalizeConfigOverrides(overrides) {
|
|
529
|
-
return {
|
|
530
|
-
...overrides.entries ? { entries: overrides.entries } : {},
|
|
531
|
-
...overrides.external ? { external: overrides.external } : {}
|
|
532
|
-
};
|
|
533
|
-
}
|
|
534
506
|
function normalizeStringList(value) {
|
|
535
507
|
if (typeof value === "string") return [value];
|
|
536
508
|
if (!Array.isArray(value)) return [];
|
|
537
509
|
return value.filter((item) => typeof item === "string");
|
|
538
510
|
}
|
|
539
|
-
function readWorkflowEntry(root, entry) {
|
|
540
|
-
|
|
511
|
+
async function readWorkflowEntry(root, entry) {
|
|
512
|
+
const file = path.join(root, entry.source);
|
|
513
|
+
return parseWorkflowMap(await readFile(file, "utf8"), file);
|
|
541
514
|
}
|
|
542
|
-
function
|
|
543
|
-
|
|
515
|
+
async function readLockfile(cwd) {
|
|
516
|
+
const root = resolveCwd(cwd);
|
|
517
|
+
const file = path.join(root, LOCKFILE_PATH);
|
|
518
|
+
if (!await fileExists(file)) return {
|
|
544
519
|
lockfileVersion: 1,
|
|
545
520
|
entries: {},
|
|
546
521
|
packages: {}
|
|
547
522
|
};
|
|
548
|
-
}
|
|
549
|
-
async function readLockfile(cwd) {
|
|
550
|
-
const root = resolveCwd(cwd);
|
|
551
|
-
const file = path.join(root, LOCKFILE_PATH);
|
|
552
|
-
if (!await fileExists(file)) return emptyLockfile();
|
|
553
523
|
const value = await readYamlFile(file);
|
|
554
524
|
return {
|
|
555
525
|
lockfileVersion: 1,
|
|
@@ -558,7 +528,9 @@ async function readLockfile(cwd) {
|
|
|
558
528
|
};
|
|
559
529
|
}
|
|
560
530
|
async function writeLockfile(cwd, lockfile) {
|
|
561
|
-
|
|
531
|
+
const file = path.join(resolveCwd(cwd), LOCKFILE_PATH);
|
|
532
|
+
await mkdir(path.dirname(file), { recursive: true });
|
|
533
|
+
await writeFile(file, `${GENERATED_FILE_NOTICE}${stringifyYaml(lockfile)}`, "utf8");
|
|
562
534
|
}
|
|
563
535
|
async function writeWorkflow(cwd, output, workflow) {
|
|
564
536
|
const file = path.join(resolveCwd(cwd), output);
|
|
@@ -586,7 +558,7 @@ var HttpGitHubClient = class {
|
|
|
586
558
|
ref
|
|
587
559
|
];
|
|
588
560
|
for (const candidate of candidates) {
|
|
589
|
-
const sha = (await this.#request(`/repos/${owner}/${repo}/git/ref/${candidate}
|
|
561
|
+
const sha = (await this.#request(`/repos/${owner}/${repo}/git/ref/${candidate}`, true))?.object?.sha;
|
|
590
562
|
if (sha) return sha;
|
|
591
563
|
}
|
|
592
564
|
throw new Error(`Unable to resolve ${owner}/${repo}@${ref}`);
|
|
@@ -595,7 +567,8 @@ var HttpGitHubClient = class {
|
|
|
595
567
|
const cacheFile = this.#cacheFile(owner, repo, ref, filePath);
|
|
596
568
|
const cached = await readFile(cacheFile, "utf8").catch(() => void 0);
|
|
597
569
|
if (cached !== void 0) return cached;
|
|
598
|
-
const
|
|
570
|
+
const encodedPath = filePath.split("/").map(encodeURIComponent).join("/");
|
|
571
|
+
const response = await this.#request(`/repos/${owner}/${repo}/contents/${encodedPath}?ref=${ref}`, true);
|
|
599
572
|
if (!response) return;
|
|
600
573
|
if (response.encoding !== "base64" || typeof response.content !== "string") throw new Error(`Unexpected GitHub content response for ${owner}/${repo}/${filePath}@${ref}`);
|
|
601
574
|
const content = Buffer.from(response.content, "base64").toString("utf8");
|
|
@@ -619,15 +592,9 @@ var HttpGitHubClient = class {
|
|
|
619
592
|
return await response.json();
|
|
620
593
|
}
|
|
621
594
|
};
|
|
622
|
-
function encodeURIComponentPath(filePath) {
|
|
623
|
-
return filePath.split("/").map(encodeURIComponent).join("/");
|
|
624
|
-
}
|
|
625
595
|
//#endregion
|
|
626
596
|
//#region src/utils/ref.ts
|
|
627
597
|
const REMOTE_USES_RE = /^[\w.-]+\/[\w.-]+(?:\/[^@\s]+)?@[^@\s]+$/;
|
|
628
|
-
function packageKey(owner, repo, path) {
|
|
629
|
-
return path && path !== "." ? `github:${owner}/${repo}/${path}` : `github:${owner}/${repo}`;
|
|
630
|
-
}
|
|
631
598
|
function isRemoteUses(value) {
|
|
632
599
|
return typeof value === "string" && REMOTE_USES_RE.test(value);
|
|
633
600
|
}
|
|
@@ -649,7 +616,7 @@ function parseRemoteUses(value, kind = "action") {
|
|
|
649
616
|
repo,
|
|
650
617
|
path,
|
|
651
618
|
ref,
|
|
652
|
-
package:
|
|
619
|
+
package: path && path !== "." ? `github:${owner}/${repo}/${path}` : `github:${owner}/${repo}`,
|
|
653
620
|
kind: inferredKind
|
|
654
621
|
};
|
|
655
622
|
}
|
|
@@ -907,7 +874,7 @@ function substituteString(value, values) {
|
|
|
907
874
|
if (!expression) return value;
|
|
908
875
|
try {
|
|
909
876
|
const expr = parseExpression(expression);
|
|
910
|
-
const replacement =
|
|
877
|
+
const replacement = valueForIndexAccess(expr, values);
|
|
911
878
|
if (replacement !== void 0) return replacement;
|
|
912
879
|
const evaluated = staticExpression(expr, values);
|
|
913
880
|
if (evaluated) return evaluated.value;
|
|
@@ -951,9 +918,6 @@ function findToken(token, path) {
|
|
|
951
918
|
return Number.isInteger(index) ? findToken(token.get(index), rest) : void 0;
|
|
952
919
|
}
|
|
953
920
|
}
|
|
954
|
-
function directReplacement(expr, values) {
|
|
955
|
-
return valueForIndexAccess(expr, values);
|
|
956
|
-
}
|
|
957
921
|
//#endregion
|
|
958
922
|
//#region src/pack.ts
|
|
959
923
|
async function pack(options = {}) {
|
|
@@ -1236,7 +1200,8 @@ async function why(packageName, options = {}) {
|
|
|
1236
1200
|
if (matches.size === 0) throw new Error(`Package is not in the lockfile: ${packageName}`);
|
|
1237
1201
|
const paths = [];
|
|
1238
1202
|
for (const [source, entry] of Object.entries(lockfile.entries)) for (const dependency of entry.dependencies) collectWhyPaths(lockfile, dependency, matches, [source], paths);
|
|
1239
|
-
|
|
1203
|
+
let output = `${packageName} is not reachable\n`;
|
|
1204
|
+
if (paths.length > 0) output = `${packageName} is used by:\n\n${paths.map((path) => path.map((item, index) => `${" ".repeat(index)}${index === 0 ? item : `└─ ${item}`}`).join("\n")).join("\n\n")}\n`;
|
|
1240
1205
|
options.stdout?.write(output);
|
|
1241
1206
|
return output;
|
|
1242
1207
|
}
|
|
@@ -1279,9 +1244,6 @@ function collectWhyPaths(lockfile, dependency, matches, current, paths) {
|
|
|
1279
1244
|
if (matches.has(dependency.package)) paths.push(next);
|
|
1280
1245
|
item?.dependencies.forEach((child) => collectWhyPaths(lockfile, child, matches, next, paths));
|
|
1281
1246
|
}
|
|
1282
|
-
function formatPath(path) {
|
|
1283
|
-
return path.map((item, index) => `${" ".repeat(index)}${index === 0 ? item : `└─ ${item}`}`).join("\n");
|
|
1284
|
-
}
|
|
1285
1247
|
async function readHeadLockfile(cwd) {
|
|
1286
1248
|
try {
|
|
1287
1249
|
const { stdout } = await execFileAsync("git", ["show", `HEAD:${LOCKFILE_PATH}`], { cwd });
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as why, c as packWorkflow, d as collectWorkflowDependencies, f as scan, i as update, l as verify, n as diffLockfiles, o as assertNoRemoteUses, r as tree, s as pack, t as diff, u as collectStepDependencies } from "./commands-
|
|
1
|
+
import { a as why, c as packWorkflow, d as collectWorkflowDependencies, f as scan, i as update, l as verify, n as diffLockfiles, o as assertNoRemoteUses, r as tree, s as pack, t as diff, u as collectStepDependencies } from "./commands-BayB-wc-.mjs";
|
|
2
2
|
export { assertNoRemoteUses, collectStepDependencies, collectWorkflowDependencies, diff, diffLockfiles, pack, packWorkflow, scan, tree, update, verify, why };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "actionspack",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.5",
|
|
5
5
|
"description": "Lockfile-first GitHub Actions workflow packer",
|
|
6
6
|
"author": "Kevin Deng <sxzz@sxzz.moe>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@sxzz/eslint-config": "^8.1.0",
|
|
42
42
|
"@sxzz/prettier-config": "^2.3.1",
|
|
43
|
-
"@types/node": "^25.9.
|
|
43
|
+
"@types/node": "^25.9.1",
|
|
44
44
|
"@typescript/native-preview": "7.0.0-dev.20260519.1",
|
|
45
45
|
"bumpp": "^11.1.0",
|
|
46
46
|
"eslint": "^10.4.0",
|