willfire 0.1.10 → 0.1.12
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 +86 -5
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +1 -0
- package/dist/cli/parseArgs.d.ts +9 -0
- package/dist/cli/parseArgs.js +42 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +41 -0
- package/dist/entries/index.d.ts +3 -0
- package/dist/entries/index.js +3 -0
- package/dist/entries/isJobEntry.d.ts +3 -0
- package/dist/entries/isJobEntry.js +2 -0
- package/dist/entries/isWorkflowEntry.d.ts +3 -0
- package/dist/entries/isWorkflowEntry.js +2 -0
- package/dist/entries/jobName.d.ts +3 -0
- package/dist/entries/jobName.js +2 -0
- package/dist/execute.d.ts +123 -0
- package/dist/execute.js +490 -0
- package/dist/expr.d.ts +51 -3
- package/dist/expr.js +85 -18
- package/dist/filters/index.d.ts +2 -0
- package/dist/filters/index.js +2 -0
- package/dist/filters/matchFilters.d.ts +2 -0
- package/dist/filters/matchFilters.js +12 -0
- package/dist/filters/patternToRegex.d.ts +1 -0
- package/dist/filters/patternToRegex.js +35 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +6 -0
- package/dist/jobs/evalIf.d.ts +10 -0
- package/dist/jobs/evalIf.js +18 -0
- package/dist/jobs/expandJobs.d.ts +4 -0
- package/dist/jobs/expandJobs.js +247 -0
- package/dist/jobs/expandWorkflowJobs.d.ts +14 -0
- package/dist/jobs/expandWorkflowJobs.js +14 -0
- package/dist/jobs/index.d.ts +4 -0
- package/dist/jobs/index.js +4 -0
- package/dist/jobs/prScope.d.ts +10 -0
- package/dist/jobs/prScope.js +19 -0
- package/dist/matrix/expandMatrix.d.ts +4 -0
- package/dist/matrix/expandMatrix.js +6 -0
- package/dist/matrix/expandMatrixDetailed.d.ts +3 -0
- package/dist/matrix/expandMatrixDetailed.js +74 -0
- package/dist/matrix/formatMatrixValue.d.ts +8 -0
- package/dist/matrix/formatMatrixValue.js +16 -0
- package/dist/matrix/index.d.ts +4 -0
- package/dist/matrix/index.js +4 -0
- package/dist/matrix/matrixSuffix.d.ts +3 -0
- package/dist/matrix/matrixSuffix.js +8 -0
- package/dist/names/index.d.ts +4 -0
- package/dist/names/index.js +4 -0
- package/dist/names/jobDisplayName.d.ts +16 -0
- package/dist/names/jobDisplayName.js +25 -0
- package/dist/names/lookupPath.d.ts +1 -0
- package/dist/names/lookupPath.js +9 -0
- package/dist/names/renderName.d.ts +2 -0
- package/dist/names/renderName.js +26 -0
- package/dist/names/skippedDisplayName.d.ts +14 -0
- package/dist/names/skippedDisplayName.js +16 -0
- package/dist/predict/finalizePrediction.d.ts +2 -0
- package/dist/predict/finalizePrediction.js +19 -0
- package/dist/predict/index.d.ts +5 -0
- package/dist/predict/index.js +5 -0
- package/dist/predict/makeOctokit.d.ts +2 -0
- package/dist/predict/makeOctokit.js +7 -0
- package/dist/predict/predict.d.ts +3 -0
- package/dist/predict/predict.js +214 -0
- package/dist/predict/sourceKey.d.ts +3 -0
- package/dist/predict/sourceKey.js +2 -0
- package/dist/predict/stackTargetRef.d.ts +14 -0
- package/dist/predict/stackTargetRef.js +58 -0
- package/dist/triggers/getPrTrigger.d.ts +3 -0
- package/dist/triggers/getPrTrigger.js +18 -0
- package/dist/triggers/index.d.ts +2 -0
- package/dist/triggers/index.js +2 -0
- package/dist/triggers/workflowDispatches.d.ts +2 -0
- package/dist/triggers/workflowDispatches.js +45 -0
- package/dist/{predict.d.ts → types.d.ts} +75 -46
- package/dist/types.js +1 -0
- package/dist/uses/index.d.ts +1 -0
- package/dist/uses/index.js +1 -0
- package/dist/uses/parseUses.d.ts +15 -0
- package/dist/uses/parseUses.js +33 -0
- package/dist/verify.js +1 -1
- package/package.json +7 -7
- package/dist/predict.js +0 -785
package/README.md
CHANGED
|
@@ -54,8 +54,9 @@ workflows all applied. That is the unit required status checks key on, so it
|
|
|
54
54
|
is the one worth comparing against. On a `JobEntry` it is `null` only where no
|
|
55
55
|
single name is knowable ahead of the run:
|
|
56
56
|
|
|
57
|
-
- a matrix computed at runtime (`fromJSON` of another job's output)
|
|
58
|
-
as one `unknown` entry for that job and
|
|
57
|
+
- a matrix computed at runtime (`fromJSON` of another job's output) whose
|
|
58
|
+
outputs were not supplied, reported as one `unknown` entry for that job and
|
|
59
|
+
nothing else — see "Supplying job outputs" below;
|
|
59
60
|
- a reusable workflow we cannot read — private, deleted, a ref that does not
|
|
60
61
|
exist, a `uses:` built from an expression, or one nested past GitHub's
|
|
61
62
|
four-level limit;
|
|
@@ -83,7 +84,8 @@ Auth is any token with `contents: read`, `actions: read`, and
|
|
|
83
84
|
|
|
84
85
|
```sh
|
|
85
86
|
GH_TOKEN=... willfire --repo owner/repo --pr 123 \
|
|
86
|
-
[--action opened|synchronize|reopened] [--json]
|
|
87
|
+
[--action opened|synchronize|reopened] [--json] \
|
|
88
|
+
[--execute owner/repo:job1,job2]...
|
|
87
89
|
```
|
|
88
90
|
|
|
89
91
|
Plain-text output is one line per entry, then a `# read owner/repo@ref -> sha`
|
|
@@ -100,8 +102,87 @@ workflows — both the local `./.github/workflows/x.yml` form and the cross-repo
|
|
|
100
102
|
commit and the callee then read at that commit. Jobs whose `if` is false are
|
|
101
103
|
predicted as `skipped` entries, matching how they appear in the checks UI.
|
|
102
104
|
|
|
103
|
-
Things that cannot be known statically
|
|
104
|
-
|
|
105
|
+
Things that cannot be known statically are reported as `unknown` rather than
|
|
106
|
+
guessed.
|
|
107
|
+
|
|
108
|
+
## Supplying job outputs
|
|
109
|
+
|
|
110
|
+
A matrix built from another job's output is the common way a workflow decides
|
|
111
|
+
its own check names:
|
|
112
|
+
|
|
113
|
+
```yaml
|
|
114
|
+
strategy:
|
|
115
|
+
matrix:
|
|
116
|
+
language: ${{ fromJSON(needs.detect.outputs.coverage_languages) }}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Given those outputs, willfire expands it. `expandWorkflowJobs` takes a `scope`
|
|
120
|
+
whose `needs` maps a job id to its outputs:
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
await expandWorkflowJobs(wf, ctx, fetchWorkflow, source, {
|
|
124
|
+
needs: { detect: { outputs: { coverage_languages: '["typescript"]' } } },
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Values are raw strings — what a step wrote to `$GITHUB_OUTPUT`, and what the
|
|
129
|
+
runner substitutes. Parsing them here would break the guards written against
|
|
130
|
+
them: `!= '[]'` compares a string to a string, and an array on the left makes
|
|
131
|
+
it unknown. `fromJSON` is the only thing that turns one into a structure.
|
|
132
|
+
|
|
133
|
+
`outputs` must be the job's *complete* output set, because a key absent from it
|
|
134
|
+
reads as the empty string — the same answer the runner gives for an output no
|
|
135
|
+
step wrote. A job you know nothing about belongs left out entirely; every
|
|
136
|
+
lookup against it then stays unknown.
|
|
137
|
+
|
|
138
|
+
`needs` is workflow-scoped and is not inherited across a reusable-workflow
|
|
139
|
+
call: a callee's `needs.detect` is the callee's own job.
|
|
140
|
+
|
|
141
|
+
Nothing in willfire works out what those outputs are on its own. `predict`
|
|
142
|
+
supplies none unless the caller grants execution — see below — so a dynamic
|
|
143
|
+
matrix stays `unknown` by default.
|
|
144
|
+
|
|
145
|
+
## Executing granted jobs
|
|
146
|
+
|
|
147
|
+
The job those outputs come from is usually a few shell steps over the checked
|
|
148
|
+
out tree — cheap to run for real. `predict` will do that, but only for jobs
|
|
149
|
+
the caller names:
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
await predict(octokit, "owner/repo", 123, {
|
|
153
|
+
execute: [{ repo: "the-org/conventions", jobs: ["detect"] }],
|
|
154
|
+
});
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
```sh
|
|
158
|
+
willfire --repo owner/repo --pr 123 \
|
|
159
|
+
--execute the-org/conventions:detect
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
A grant names the repo the workflow *file* lives in — for a reusable workflow,
|
|
163
|
+
the callee — and the job ids within it. Before expansion reads `needs`, each
|
|
164
|
+
granted job that is predicted to run is executed: the PR's head tree is
|
|
165
|
+
materialized from a tarball, the job's steps run in order under their declared
|
|
166
|
+
shell and env, step-level `if:` guards are evaluated, composite actions are
|
|
167
|
+
fetched at their pinned commit and recursed into, and a bare
|
|
168
|
+
`actions/checkout` is satisfied by the tree already present. What the steps
|
|
169
|
+
write to `$GITHUB_OUTPUT` becomes the job's outputs, exactly as if they had
|
|
170
|
+
been supplied by hand.
|
|
171
|
+
|
|
172
|
+
Execution is mechanism, not policy: willfire knows nothing about any repo, and
|
|
173
|
+
with no grants nothing runs. The steps execute for real — nothing interprets
|
|
174
|
+
or approximates shell — so grant only jobs whose code you trust at the commit
|
|
175
|
+
being predicted; a granted job runs the PR's version of itself.
|
|
176
|
+
|
|
177
|
+
Anything execution cannot do faithfully fails the grant rather than guessing:
|
|
178
|
+
a JavaScript or Docker action, a checkout with inputs, a matrix'd or
|
|
179
|
+
containerized granted job, an undecidable step `if:`, a non-zero exit, output
|
|
180
|
+
willfire cannot parse. The failure does not change any verdict — entries that
|
|
181
|
+
needed the outputs stay `unknown`, with the reason threaded through:
|
|
182
|
+
|
|
183
|
+
```
|
|
184
|
+
dynamic matrix; executing 'detect' failed: step 'scan': exited 1 (...)
|
|
185
|
+
```
|
|
105
186
|
|
|
106
187
|
## Development
|
|
107
188
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { parseArgs } from "./parseArgs.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { parseArgs } from "./parseArgs.js";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type ExecutionGrant } from "../execute.js";
|
|
2
|
+
import type { PrEventAction } from "../types.js";
|
|
3
|
+
export declare function parseArgs(argv: string[]): {
|
|
4
|
+
repo: string;
|
|
5
|
+
pr: number;
|
|
6
|
+
json: boolean;
|
|
7
|
+
action?: PrEventAction;
|
|
8
|
+
execute: ExecutionGrant[];
|
|
9
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { parseGrant } from "../execute.js";
|
|
2
|
+
const USAGE = "usage: predict --repo owner/name --pr N [--action opened|synchronize|reopened]" +
|
|
3
|
+
" [--execute owner/repo:job1,job2]... [--json]";
|
|
4
|
+
const isPrEventAction = (v) => v === "opened" || v === "synchronize" || v === "reopened";
|
|
5
|
+
export function parseArgs(argv) {
|
|
6
|
+
const get = (flag) => {
|
|
7
|
+
const i = argv.indexOf(flag);
|
|
8
|
+
return i >= 0 ? argv[i + 1] : undefined;
|
|
9
|
+
};
|
|
10
|
+
const repo = get("--repo");
|
|
11
|
+
const pr = get("--pr");
|
|
12
|
+
if (!repo || !pr) {
|
|
13
|
+
console.error(USAGE);
|
|
14
|
+
process.exit(2);
|
|
15
|
+
}
|
|
16
|
+
// An unrecognised action is refused rather than ignored. Silently falling
|
|
17
|
+
// back to the guess would turn a typo into a wrong prediction, which is the
|
|
18
|
+
// failure this flag exists to remove.
|
|
19
|
+
const action = get("--action");
|
|
20
|
+
if (action !== undefined && !isPrEventAction(action)) {
|
|
21
|
+
console.error(`unknown --action: ${action}`);
|
|
22
|
+
console.error(USAGE);
|
|
23
|
+
process.exit(2);
|
|
24
|
+
}
|
|
25
|
+
// Repeatable, one grant per flag. A malformed grant is refused for the same
|
|
26
|
+
// reason a bad --action is: silently dropping it would predict without the
|
|
27
|
+
// execution the caller thought they asked for.
|
|
28
|
+
const execute = [];
|
|
29
|
+
for (let i = 0; i < argv.length; i++) {
|
|
30
|
+
if (argv[i] !== "--execute")
|
|
31
|
+
continue;
|
|
32
|
+
const spec = argv[i + 1];
|
|
33
|
+
const grant = spec == null ? null : parseGrant(spec);
|
|
34
|
+
if (grant == null) {
|
|
35
|
+
console.error(`bad --execute: ${spec}`);
|
|
36
|
+
console.error(USAGE);
|
|
37
|
+
process.exit(2);
|
|
38
|
+
}
|
|
39
|
+
execute.push(grant);
|
|
40
|
+
}
|
|
41
|
+
return { repo, pr: Number(pr), json: argv.includes("--json"), action, execute };
|
|
42
|
+
}
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Usage: pnpm predict --repo owner/name --pr N [--json]
|
|
3
|
+
//
|
|
4
|
+
// Auth: GH_TOKEN or GITHUB_TOKEN env var (any token with
|
|
5
|
+
// contents/actions/pull-requests read). Inside an action, pass the workflow's
|
|
6
|
+
// GITHUB_TOKEN.
|
|
7
|
+
import { parseArgs } from "./cli/parseArgs.js";
|
|
8
|
+
import { isWorkflowEntry } from "./entries/isWorkflowEntry.js";
|
|
9
|
+
import { makeOctokit } from "./predict/makeOctokit.js";
|
|
10
|
+
import { predict } from "./predict/predict.js";
|
|
11
|
+
const isMain = /cli\.(ts|js)$|\/willfire$/.test(process.argv[1] ?? "");
|
|
12
|
+
if (isMain) {
|
|
13
|
+
const args = parseArgs(process.argv.slice(2));
|
|
14
|
+
const prediction = await predict(makeOctokit(), args.repo, args.pr, {
|
|
15
|
+
action: args.action,
|
|
16
|
+
execute: args.execute,
|
|
17
|
+
});
|
|
18
|
+
const { entries, skip, sources } = prediction;
|
|
19
|
+
if (args.json) {
|
|
20
|
+
console.log(JSON.stringify(prediction, null, 2));
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
if (skip) {
|
|
24
|
+
console.log(`# ${skip} -> nothing dispatches`);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
for (const e of entries) {
|
|
28
|
+
if (isWorkflowEntry(e))
|
|
29
|
+
console.log(`# ${e.workflow} :: ${e.status} (${e.reason})`);
|
|
30
|
+
else {
|
|
31
|
+
const name = e.checkName ?? `${e.job} (name unresolved)`;
|
|
32
|
+
console.log(`${e.workflow} :: ${name} :: ${e.status}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// Last, and on the skip path too, so a red gate's first question — which
|
|
37
|
+
// commits was this read from? — is answered wherever the reader lands.
|
|
38
|
+
for (const s of sources)
|
|
39
|
+
console.log(`# read ${s.owner}/${s.repo}@${s.ref} -> ${s.sha}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Execute a job the caller granted, to learn what static reading cannot.
|
|
3
|
+
*
|
|
4
|
+
* A dynamic matrix — `language: ${{ fromJSON(needs.detect.outputs.x) }}` — is
|
|
5
|
+
* the values another job computes at runtime. No amount of reading the YAML
|
|
6
|
+
* yields them; the fleet's `detect` job runs a script over the repo tree and
|
|
7
|
+
* writes what it finds to `$GITHUB_OUTPUT`. So this module runs that job the
|
|
8
|
+
* way the runner would: materialize the tree at the pinned commit, walk the
|
|
9
|
+
* steps in order, execute each `run:` under its declared shell and env, and
|
|
10
|
+
* assemble the job's `outputs:` map from what the steps actually wrote.
|
|
11
|
+
*
|
|
12
|
+
* Three rules keep this honest:
|
|
13
|
+
*
|
|
14
|
+
* 1. **Nothing runs without a grant.** willfire has no opinion about which
|
|
15
|
+
* jobs are safe to execute; the caller names them, one repo and job id at
|
|
16
|
+
* a time, and everything else stays as unresolved as it was.
|
|
17
|
+
* 2. **Run it, never interpret it.** The `run:` script is handed to the shell
|
|
18
|
+
* the step declares, with the env it declares. What lands in
|
|
19
|
+
* `$GITHUB_OUTPUT` is the answer; no shell text is ever parsed for meaning.
|
|
20
|
+
* 3. **Anything off the modelled path is a hard stop with a reason.** A
|
|
21
|
+
* JavaScript action, an undecidable `if:`, a `${{ }}` that will not
|
|
22
|
+
* resolve, a step that exits non-zero — each fails the execution and says
|
|
23
|
+
* what it hit, and the consumers of that job's outputs stay unresolved.
|
|
24
|
+
* Guessing is the one move this module never makes.
|
|
25
|
+
*
|
|
26
|
+
* `actions/checkout` is the deliberate exception to rule 2. It is provided by
|
|
27
|
+
* the runner, not run from its repo, and its whole postcondition — the
|
|
28
|
+
* workspace tree at the commit under test — is something the executor has
|
|
29
|
+
* already satisfied by materializing the tree. A bare checkout is therefore
|
|
30
|
+
* recorded as done; a checkout *with inputs* is not modelled and stops.
|
|
31
|
+
*/
|
|
32
|
+
import { type Scope } from "./expr.js";
|
|
33
|
+
import type { ResolveRef, WorkflowSource } from "./types.js";
|
|
34
|
+
/**
|
|
35
|
+
* Permission to execute named jobs from one repo's workflows.
|
|
36
|
+
*
|
|
37
|
+
* `repo` is the repo the *workflow file* lives in — for a fleet consumer
|
|
38
|
+
* calling `testing-conventions/.github/workflows/testing-conventions.yml@v0`,
|
|
39
|
+
* that is `thekevinscott/testing-conventions`, whatever repo the PR is on.
|
|
40
|
+
* The grant is deliberately this narrow: a job id alone would execute
|
|
41
|
+
* whatever any transitively-reached workflow happens to call by that name.
|
|
42
|
+
*/
|
|
43
|
+
export interface ExecutionGrant {
|
|
44
|
+
/** `owner/name` of the repo whose workflow defines the jobs. */
|
|
45
|
+
repo: string;
|
|
46
|
+
/** Job ids within that repo's workflows that may be executed. */
|
|
47
|
+
jobs: string[];
|
|
48
|
+
}
|
|
49
|
+
/** `owner/repo:job1,job2` as the CLI spells a grant. */
|
|
50
|
+
export declare function parseGrant(spec: string): ExecutionGrant | null;
|
|
51
|
+
/** One shell invocation, fully specified — nothing is inherited implicitly. */
|
|
52
|
+
export interface RunSpec {
|
|
53
|
+
script: string;
|
|
54
|
+
shell: "bash" | "sh";
|
|
55
|
+
cwd: string;
|
|
56
|
+
env: Record<string, string>;
|
|
57
|
+
}
|
|
58
|
+
export interface RunResult {
|
|
59
|
+
code: number;
|
|
60
|
+
/** Captured so a failing step can say *why* in its reason. */
|
|
61
|
+
stderr: string;
|
|
62
|
+
}
|
|
63
|
+
export type RunCommand = (spec: RunSpec) => Promise<RunResult>;
|
|
64
|
+
/**
|
|
65
|
+
* Materialize a repo tree at a commit and return its root directory, or null
|
|
66
|
+
* when it cannot be had. Must not throw.
|
|
67
|
+
*/
|
|
68
|
+
export type ProvideTree = (source: WorkflowSource) => Promise<string | null>;
|
|
69
|
+
/** The three reaches into the world an execution needs, bundled for injection. */
|
|
70
|
+
export interface ExecDeps {
|
|
71
|
+
provideTree: ProvideTree;
|
|
72
|
+
runCommand: RunCommand;
|
|
73
|
+
resolveRef: ResolveRef;
|
|
74
|
+
}
|
|
75
|
+
export type ExecOutcome = {
|
|
76
|
+
ok: true;
|
|
77
|
+
outputs: Record<string, string>;
|
|
78
|
+
} | {
|
|
79
|
+
ok: false;
|
|
80
|
+
reason: string;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* What expansion asks of an executor. The caller decides *whether* a job
|
|
84
|
+
* runs with its own scope — the executor only decides what running it
|
|
85
|
+
* yields. Step-level guards inside the job are evaluated here, against the
|
|
86
|
+
* fixed facts of the run (notably `github.repository`, which the fleet's
|
|
87
|
+
* hermetic-vs-published guards are written against).
|
|
88
|
+
*/
|
|
89
|
+
export interface JobExecutor {
|
|
90
|
+
granted(source: WorkflowSource, jobId: string): boolean;
|
|
91
|
+
executeJob(jobId: string, job: any, wf: any, scope: Scope): Promise<ExecOutcome>;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* The `$GITHUB_OUTPUT` file format: `name=value` lines, or a
|
|
95
|
+
* `name<<DELIMITER … DELIMITER` heredoc for multi-line values. Anything else
|
|
96
|
+
* fails the parse — the runner fails the step on a malformed line, so
|
|
97
|
+
* tolerating one here would invent outputs a real run never had.
|
|
98
|
+
*/
|
|
99
|
+
export declare function parseGithubOutput(text: string): Record<string, string> | null;
|
|
100
|
+
export declare function makeExecutor(opts: {
|
|
101
|
+
grants: ExecutionGrant[];
|
|
102
|
+
/**
|
|
103
|
+
* The PR's own repo at the head commit — what `actions/checkout` provides
|
|
104
|
+
* on a real runner, wherever the workflow file itself lives. A reusable
|
|
105
|
+
* workflow's jobs run in the caller's workspace; this is that fact.
|
|
106
|
+
*/
|
|
107
|
+
workspace: WorkflowSource;
|
|
108
|
+
deps: ExecDeps;
|
|
109
|
+
}): JobExecutor;
|
|
110
|
+
/**
|
|
111
|
+
* The runner's default shell invocations, faithfully: `bash --noprofile
|
|
112
|
+
* --norc -e -o pipefail` and `sh -e`. Nothing of the parent environment
|
|
113
|
+
* leaks in beyond what the spec names.
|
|
114
|
+
*/
|
|
115
|
+
export declare const runShell: RunCommand;
|
|
116
|
+
/**
|
|
117
|
+
* Materialize repo trees from tarballs, one download per commit however many
|
|
118
|
+
* steps ask. GitHub's tarballs wrap the tree in a single
|
|
119
|
+
* `owner-repo-shortsha/` directory, which is unwrapped so callers get the
|
|
120
|
+
* tree root itself. Extraction shells out to `tar` through the same
|
|
121
|
+
* `RunCommand` seam every other subprocess uses.
|
|
122
|
+
*/
|
|
123
|
+
export declare function makeTreeProvider(download: (source: WorkflowSource) => Promise<Uint8Array | null>, runCommand: RunCommand): ProvideTree;
|