actionspack 0.0.0 → 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright © 2026-PRESENT Kevin Deng (https://github.com/sxzz)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,166 @@
1
+ # actionspack
2
+
3
+ [![Open on npmx][npmx-version-src]][npmx-href]
4
+ [![npm downloads][npmx-downloads-src]][npmx-href]
5
+ [![Unit Test][unit-test-src]][unit-test-href]
6
+
7
+ `actionspack` is a lockfile-first GitHub Actions workflow packer. It lets you
8
+ author workflows in `.github/workflows/src/`, lock every remote workflow/action
9
+ dependency in `.github/workflow.lock.yml`, and generate pinned workflows in
10
+ `.github/workflows/`.
11
+
12
+ It currently supports inlining composite actions and safely transformable
13
+ reusable workflows. JavaScript and Docker actions are pinned as external
14
+ dependencies instead of being bundled.
15
+
16
+ ## Install
17
+
18
+ ```bash
19
+ npm i actionspack
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ Put authored workflows under `.github/workflows/src/`:
25
+
26
+ ```yaml
27
+ # .github/workflows/src/ci.yml
28
+ name: CI
29
+
30
+ on:
31
+ push:
32
+
33
+ jobs:
34
+ test:
35
+ uses: owner/repo/.github/workflows/test.yml@main
36
+ ```
37
+
38
+ Then run:
39
+
40
+ ```bash
41
+ npx actionspack
42
+ ```
43
+
44
+ `actionspack` defaults to `actionspack pack`. It writes:
45
+
46
+ - `.github/workflow.lock.yml`
47
+ - `.github/workflows/ci.yml`
48
+
49
+ Generated workflows are safe to commit. Existing lockfile SHAs are reused until
50
+ you explicitly run `actionspack update`.
51
+
52
+ ## Commands
53
+
54
+ ```bash
55
+ actionspack pack
56
+ ```
57
+
58
+ Scan source workflows, resolve missing dependencies, update the lockfile, and
59
+ write generated workflows.
60
+
61
+ ```bash
62
+ actionspack scan
63
+ ```
64
+
65
+ Update the lockfile graph shape only. This adds newly discovered dependencies
66
+ and removes unreachable ones without refreshing existing SHAs.
67
+
68
+ ```bash
69
+ actionspack update [package]
70
+ ```
71
+
72
+ Refresh all locked dependencies, or only the selected package. By default this
73
+ also packs workflows. Use `--lockfile-only` to update only
74
+ `.github/workflow.lock.yml`.
75
+
76
+ ```bash
77
+ actionspack verify
78
+ ```
79
+
80
+ Check that generated workflows are current and contain no unsupported unpinned
81
+ remote references.
82
+
83
+ ```bash
84
+ actionspack tree
85
+ actionspack why <package>
86
+ actionspack diff
87
+ actionspack diff --json
88
+ ```
89
+
90
+ Inspect the lockfile dependency tree, explain why a package is present, or
91
+ compare the current lockfile with `HEAD`.
92
+
93
+ ## Configuration
94
+
95
+ `actionspack.yml` is optional. Without it, `actionspack` discovers
96
+ `.github/workflows/src/*.yml` and `.github/workflows/src/*.yaml`, then writes
97
+ matching generated workflows to `.github/workflows/*.yml`.
98
+
99
+ Use explicit entries when you need custom paths:
100
+
101
+ ```yaml
102
+ $schema: ./actionspack.schema.json
103
+
104
+ entries:
105
+ - source: .github/workflows/src/ci.yml
106
+ output: .github/workflows/ci.yml
107
+ ```
108
+
109
+ Use `external` to pin a workflow or action without bundling it:
110
+
111
+ ```yaml
112
+ external:
113
+ - actions/checkout
114
+ - owner/repo/path
115
+ ```
116
+
117
+ The same configuration can be supplied through CLI flags:
118
+
119
+ ```bash
120
+ actionspack pack \
121
+ --entry .github/workflows/src/ci.yml:.github/workflows/ci.yml \
122
+ --external actions/checkout
123
+ ```
124
+
125
+ ## Packing Rules
126
+
127
+ Composite actions are recursively inlined when `runs.using` is `composite`.
128
+ Inputs are substituted from caller `with` values or action defaults. Missing
129
+ required inputs fail closed.
130
+
131
+ Reusable workflows are inlined only when they use `workflow_call` and can be
132
+ transformed into local jobs deterministically. Unsupported cases, unresolved
133
+ refs, unsafe reusable workflows, and leftover remote `uses` fail closed.
134
+
135
+ JavaScript actions, Docker actions, and `docker://` references are not bundled
136
+ yet. They are pinned to locked SHAs as external dependencies.
137
+
138
+ ## API
139
+
140
+ ```ts
141
+ import { diff, pack, scan, tree, update, verify, why } from 'actionspack'
142
+
143
+ await pack()
144
+ await update({ packageName: 'owner/repo', lockfileOnly: true })
145
+ await verify()
146
+ ```
147
+
148
+ ## Sponsors
149
+
150
+ <p align="center">
151
+ <a href="https://cdn.jsdelivr.net/gh/sxzz/sponsors/sponsors.svg">
152
+ <img src='https://cdn.jsdelivr.net/gh/sxzz/sponsors/sponsors.svg'/>
153
+ </a>
154
+ </p>
155
+
156
+ ## License
157
+
158
+ [MIT](./LICENSE) License © 2026-PRESENT [Kevin Deng](https://github.com/sxzz)
159
+
160
+ <!-- Badges -->
161
+
162
+ [npmx-version-src]: https://npmx.dev/api/registry/badge/version/actionspack
163
+ [npmx-downloads-src]: https://npmx.dev/api/registry/badge/downloads-month/actionspack
164
+ [npmx-href]: https://npmx.dev/actionspack
165
+ [unit-test-src]: https://github.com/sxzz/actionspack/actions/workflows/unit-test.yml/badge.svg
166
+ [unit-test-href]: https://github.com/sxzz/actionspack/actions/workflows/unit-test.yml
package/dist/cli.d.mts ADDED
@@ -0,0 +1 @@
1
+ export { };
package/dist/cli.mjs ADDED
@@ -0,0 +1,86 @@
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-CPJczWTq.mjs";
3
+ import { styleText } from "node:util";
4
+ import process from "node:process";
5
+ import { cac } from "cac";
6
+ //#endregion
7
+ //#region src/cli.ts
8
+ const cli = cac("actionspack");
9
+ async function main() {
10
+ cli.command("", "Pack workflows").option("--entry <source:output>", "Use an explicit source/output workflow mapping").option("--external <selector>", "Pin a workflow or action without bundling it").action(async (flags) => {
11
+ await pack({
12
+ ...normalizeConfigFlags(flags),
13
+ stderr: process.stderr,
14
+ stdout: process.stdout
15
+ });
16
+ });
17
+ cli.command("pack", "Pack workflows").option("--entry <source:output>", "Use an explicit source/output workflow mapping").option("--external <selector>", "Pin a workflow or action without bundling it").action(async (flags) => {
18
+ await pack({
19
+ ...normalizeConfigFlags(flags),
20
+ stderr: process.stderr,
21
+ stdout: process.stdout
22
+ });
23
+ });
24
+ cli.command("scan", "Update the lockfile graph without generating workflows").option("--entry <source:output>", "Use an explicit source/output workflow mapping").option("--external <selector>", "Pin a workflow or action without bundling it").action(async (flags) => {
25
+ await scan({
26
+ ...normalizeConfigFlags(flags),
27
+ stderr: process.stderr,
28
+ stdout: process.stdout
29
+ });
30
+ });
31
+ cli.command("update [packageName]", "Refresh locked dependency versions").option("--entry <source:output>", "Use an explicit source/output workflow mapping").option("--external <selector>", "Pin a workflow or action without bundling it").option("--lockfile-only", "Write only .github/workflow.lock.yml").action(async (packageName, flags) => {
32
+ const { lockfileOnly, ...rest } = flags;
33
+ await update({
34
+ ...normalizeConfigFlags(rest),
35
+ packageName,
36
+ lockfileOnly,
37
+ stderr: process.stderr,
38
+ stdout: process.stdout
39
+ });
40
+ });
41
+ cli.command("tree", "Show the dependency tree from the lockfile").action(async () => {
42
+ await tree({ stdout: process.stdout });
43
+ });
44
+ cli.command("why <packageName>", "Explain why a dependency exists").action(async (packageName) => {
45
+ await why(packageName, { stdout: process.stdout });
46
+ });
47
+ cli.command("diff", "Show lockfile changes compared with HEAD").option("--json", "Print JSON output").action(async (flags) => {
48
+ await diff({
49
+ json: flags.json,
50
+ stdout: process.stdout
51
+ });
52
+ });
53
+ cli.command("verify", "Verify lockfile and packed workflows").action(async () => {
54
+ await verify();
55
+ });
56
+ cli.help();
57
+ cli.parse(process.argv, { run: false });
58
+ await cli.runMatchedCommand();
59
+ }
60
+ function normalizeConfigFlags(flags) {
61
+ return {
62
+ ...flags.entry ? { entries: normalizeEntries(flags.entry) } : {},
63
+ ...flags.external ? { external: normalizeStringList(flags.external) } : {}
64
+ };
65
+ }
66
+ function normalizeEntries(value) {
67
+ return normalizeStringList(value).map((item) => {
68
+ const [source, ...outputParts] = item.split(":");
69
+ const output = outputParts.join(":");
70
+ if (!source || !output) throw new Error(`Invalid --entry value: ${item}`);
71
+ return {
72
+ source,
73
+ output
74
+ };
75
+ });
76
+ }
77
+ function normalizeStringList(value) {
78
+ return Array.isArray(value) ? value : [value];
79
+ }
80
+ main().catch((error) => {
81
+ const message = error instanceof Error ? error.message : String(error);
82
+ process.stderr.write(`${styleText("red", `actionspack: ${message}`)}\n`);
83
+ process.exitCode = 1;
84
+ });
85
+ //#endregion
86
+ export {};