@intentius/chant-lexicon-github 0.124.45 → 0.124.48
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/action-pins.d.ts +17 -27
- package/dist/action-pins.d.ts.map +1 -1
- package/dist/action-pins.js +39 -27
- package/dist/components/ci-jobs.d.ts +5 -2
- package/dist/components/ci-jobs.d.ts.map +1 -1
- package/dist/components/ci-jobs.js +8 -5
- package/dist/components/generate-op-pipeline.d.ts +7 -0
- package/dist/components/generate-op-pipeline.d.ts.map +1 -1
- package/dist/components/generate-op-pipeline.js +26 -3
- package/dist/components/generate-op-waves-pipeline.d.ts +13 -3
- package/dist/components/generate-op-waves-pipeline.d.ts.map +1 -1
- package/dist/components/generate-op-waves-pipeline.js +24 -5
- package/dist/components/generate-pipeline.d.ts.map +1 -1
- package/dist/components/generate-pipeline.js +55 -10
- package/dist/components/review-jobs.d.ts +55 -0
- package/dist/components/review-jobs.d.ts.map +1 -0
- package/dist/components/review-jobs.js +130 -0
- package/dist/composites/cache.d.ts.map +1 -1
- package/dist/composites/cache.js +2 -1
- package/dist/composites/checkout.d.ts +3 -3
- package/dist/composites/checkout.js +1 -1
- package/dist/composites/docker-build.js +4 -4
- package/dist/composites/download-artifact.d.ts.map +1 -1
- package/dist/composites/download-artifact.js +2 -1
- package/dist/composites/go-ci.js +4 -4
- package/dist/composites/node-pipeline.js +5 -5
- package/dist/composites/python-ci.js +2 -2
- package/dist/composites/setup-go.d.ts.map +1 -1
- package/dist/composites/setup-go.js +2 -1
- package/dist/composites/setup-node.d.ts +3 -3
- package/dist/composites/setup-node.js +1 -1
- package/dist/composites/setup-python.d.ts.map +1 -1
- package/dist/composites/setup-python.js +2 -1
- package/dist/composites/upload-artifact.d.ts.map +1 -1
- package/dist/composites/upload-artifact.js +2 -1
- package/dist/integrity.json +2 -2
- package/dist/manifest.json +1 -1
- package/package.json +2 -2
- package/src/action-pins.test.ts +29 -6
- package/src/action-pins.ts +48 -34
- package/src/components/__fixtures__/pr-loop-build.github.golden.yml +8 -9
- package/src/components/__fixtures__/pr-loop-record.github.golden.yml +4 -5
- package/src/components/__fixtures__/pr-loop-waves.github.golden.yml +16 -17
- package/src/components/__fixtures__/pr-loop.github.golden.yml +8 -9
- package/src/components/__golden__/op-waves-jobs.yml +71 -9
- package/src/components/ci-jobs.ts +8 -5
- package/src/components/generate-op-pipeline.review.test.ts +152 -0
- package/src/components/generate-op-pipeline.test.ts +5 -4
- package/src/components/generate-op-pipeline.ts +33 -3
- package/src/components/generate-op-waves-pipeline.test.ts +2 -1
- package/src/components/generate-op-waves-pipeline.ts +25 -5
- package/src/components/generate-pipeline.test.ts +10 -9
- package/src/components/generate-pipeline.ts +57 -9
- package/src/components/generate-pr-pipeline.locks.test.ts +68 -0
- package/src/components/generate-pr-pipeline.test.ts +6 -4
- package/src/components/generate-pr-waves-pipeline.test.ts +3 -2
- package/src/components/review-jobs.ts +165 -0
- package/src/composites/cache.ts +2 -1
- package/src/composites/checkout.ts +4 -4
- package/src/composites/composites.test.ts +23 -22
- package/src/composites/docker-build.ts +4 -4
- package/src/composites/download-artifact.ts +2 -1
- package/src/composites/go-ci.ts +4 -4
- package/src/composites/node-pipeline.ts +5 -5
- package/src/composites/python-ci.ts +2 -2
- package/src/composites/setup-go.ts +2 -1
- package/src/composites/setup-node.ts +4 -4
- package/src/composites/setup-python.ts +2 -1
- package/src/composites/upload-artifact.ts +2 -1
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two jobs of a split review (#4326): `ScheduledOpSpec.reviewAgent`.
|
|
3
|
+
*
|
|
4
|
+
* An Op that runs a `reviewAgent` step in `handoff` mode runs the change's
|
|
5
|
+
* code (`chant run` loads the pull request's Op files) beside a model. This
|
|
6
|
+
* generator keeps the forge write token out of that job and posts the note
|
|
7
|
+
* from another one, as terragucci's review does (`render-review.ts`: the
|
|
8
|
+
* `review` and `review-note` jobs):
|
|
9
|
+
*
|
|
10
|
+
* - the review job holds `contents: read` and no forge token in any step's
|
|
11
|
+
* environment, bar the checkout script's fetches (`checkoutScript`,
|
|
12
|
+
* ../../../../packages/core/src/ci-handover.ts). Every later step starts
|
|
13
|
+
* without the token variables (`dropForgeTokens`). The `chant run` step is
|
|
14
|
+
* its last, and it hands the review directory on as the job's outputs
|
|
15
|
+
* (`handoverTrap`), in place of an artifact upload that would start beside
|
|
16
|
+
* whatever the change's code left running.
|
|
17
|
+
* - the note job checks nothing out. It takes the outputs back as data
|
|
18
|
+
* (`takeOverScript`), installs the chant release this lexicon belongs to
|
|
19
|
+
* and runs `postReviewNote` with the job's token. The Op's name comes from
|
|
20
|
+
* this file, not from the review, which the change's code wrote.
|
|
21
|
+
*
|
|
22
|
+
* Forgejo's runner ignores `permissions:` and may put its token in a step's
|
|
23
|
+
* environment, so the review job drops the token variables on both forges.
|
|
24
|
+
*/
|
|
25
|
+
import type { OpTrigger, PipelineMember } from "@intentius/chant/lexicon";
|
|
26
|
+
/** The name of the note job beside the Op's own job. */
|
|
27
|
+
export declare function reviewNoteJobName(jobName: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* Refuse a spec whose review cannot be split the way this shape needs:
|
|
30
|
+
* a trigger with no pull request to post on, a finding-mode that would give
|
|
31
|
+
* the review job a write scope, or an additive scope that would.
|
|
32
|
+
*/
|
|
33
|
+
export declare function assertReviewSplit(name: string, trigger: OpTrigger, findingMode: string, permissions: Record<string, string> | undefined): void;
|
|
34
|
+
export interface ReviewJobsInput {
|
|
35
|
+
/** The Op's name: what `chant run` targets and what keys the note. */
|
|
36
|
+
name: string;
|
|
37
|
+
/** The Op's job name. */
|
|
38
|
+
jobName: string;
|
|
39
|
+
image: string;
|
|
40
|
+
/** The invocation of the Op, `chant run <name>` by default. */
|
|
41
|
+
invocation: string;
|
|
42
|
+
/** Setup steps, as built by `setupStepDoc`. */
|
|
43
|
+
setup: Array<Record<string, unknown>>;
|
|
44
|
+
beforeScript: readonly string[];
|
|
45
|
+
extraScript: readonly string[];
|
|
46
|
+
/** The Op's own per-job environment (`ScheduledOpSpec.variables`). */
|
|
47
|
+
variables?: Record<string, string>;
|
|
48
|
+
member?: PipelineMember;
|
|
49
|
+
}
|
|
50
|
+
/** The review job and the note job of one split review. */
|
|
51
|
+
export declare function reviewJobs(i: ReviewJobsInput): {
|
|
52
|
+
review: Record<string, unknown>;
|
|
53
|
+
note: Record<string, unknown>;
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=review-jobs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-jobs.d.ts","sourceRoot":"","sources":["../../src/components/review-jobs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAW1E,wDAAwD;AACxD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,GAAG,IAAI,CAkB9I;AAuCD,MAAM,WAAW,eAAe;IAC9B,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAC;IACb,yBAAyB;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,UAAU,EAAE,MAAM,CAAC;IACnB,+CAA+C;IAC/C,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACtC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,MAAM,CAAC,EAAE,cAAc,CAAC;CACzB;AAED,2DAA2D;AAC3D,wBAAgB,UAAU,CAAC,CAAC,EAAE,eAAe,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAwCjH"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two jobs of a split review (#4326): `ScheduledOpSpec.reviewAgent`.
|
|
3
|
+
*
|
|
4
|
+
* An Op that runs a `reviewAgent` step in `handoff` mode runs the change's
|
|
5
|
+
* code (`chant run` loads the pull request's Op files) beside a model. This
|
|
6
|
+
* generator keeps the forge write token out of that job and posts the note
|
|
7
|
+
* from another one, as terragucci's review does (`render-review.ts`: the
|
|
8
|
+
* `review` and `review-note` jobs):
|
|
9
|
+
*
|
|
10
|
+
* - the review job holds `contents: read` and no forge token in any step's
|
|
11
|
+
* environment, bar the checkout script's fetches (`checkoutScript`,
|
|
12
|
+
* ../../../../packages/core/src/ci-handover.ts). Every later step starts
|
|
13
|
+
* without the token variables (`dropForgeTokens`). The `chant run` step is
|
|
14
|
+
* its last, and it hands the review directory on as the job's outputs
|
|
15
|
+
* (`handoverTrap`), in place of an artifact upload that would start beside
|
|
16
|
+
* whatever the change's code left running.
|
|
17
|
+
* - the note job checks nothing out. It takes the outputs back as data
|
|
18
|
+
* (`takeOverScript`), installs the chant release this lexicon belongs to
|
|
19
|
+
* and runs `postReviewNote` with the job's token. The Op's name comes from
|
|
20
|
+
* this file, not from the review, which the change's code wrote.
|
|
21
|
+
*
|
|
22
|
+
* Forgejo's runner ignores `permissions:` and may put its token in a step's
|
|
23
|
+
* environment, so the review job drops the token variables on both forges.
|
|
24
|
+
*/
|
|
25
|
+
import { readFileSync } from "node:fs";
|
|
26
|
+
import { GITHUB_JOB_TOKEN, GITHUB_RUNNER } from "@intentius/chant/ci-jobs";
|
|
27
|
+
import { CHECKOUT_TOKEN_ENV, checkoutScript, dropForgeTokens, handoverOutputs, handoverTrap, takeOverScript } from "@intentius/chant/ci-handover";
|
|
28
|
+
/** The variable `reviewAgent` reads its handoff directory from (`REVIEW_DIR_ENV`, review-agent.ts). */
|
|
29
|
+
const REVIEW_DIR_ENV = "CHANT_REVIEW_DIR";
|
|
30
|
+
/** Where the review job writes the review, from the directory the step starts in. */
|
|
31
|
+
const REVIEW_DIR = ".chant/review";
|
|
32
|
+
/** The id of the review job's `chant run` step, which its outputs come from. */
|
|
33
|
+
const REVIEW_STEP_ID = "chant-review";
|
|
34
|
+
/** The name of the note job beside the Op's own job. */
|
|
35
|
+
export function reviewNoteJobName(jobName) {
|
|
36
|
+
return `${jobName}-note`;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Refuse a spec whose review cannot be split the way this shape needs:
|
|
40
|
+
* a trigger with no pull request to post on, a finding-mode that would give
|
|
41
|
+
* the review job a write scope, or an additive scope that would.
|
|
42
|
+
*/
|
|
43
|
+
export function assertReviewSplit(name, trigger, findingMode, permissions) {
|
|
44
|
+
if (trigger.kind !== "pull_request") {
|
|
45
|
+
throw new Error(`Scheduled Op "${name}" sets reviewAgent, which posts the review as a note on the pull request that triggered the run, but its trigger is "${trigger.kind}". Give it a { kind: "pull_request" } trigger.`);
|
|
46
|
+
}
|
|
47
|
+
if (findingMode !== "report") {
|
|
48
|
+
throw new Error(`Scheduled Op "${name}" sets reviewAgent with findingMode "${findingMode}". The review job holds no forge write token, and the note job posts instead, so the Op's own finding-mode must be "report".`);
|
|
49
|
+
}
|
|
50
|
+
for (const [scope, level] of Object.entries(permissions ?? {})) {
|
|
51
|
+
if (level === "write" && scope !== "id-token") {
|
|
52
|
+
throw new Error(`Scheduled Op "${name}" sets reviewAgent and adds the permission "${scope}: write". The review job runs the change's code and may hold only "id-token: write" beyond contents: read.`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/** The chant release the note job installs: this lexicon's own, which releases in lockstep with `@intentius/chant`. */
|
|
57
|
+
function chantVersion() {
|
|
58
|
+
const pkg = JSON.parse(readFileSync(new URL("../../package.json", import.meta.url), "utf8"));
|
|
59
|
+
if (typeof pkg.version !== "string" || pkg.version === "") {
|
|
60
|
+
throw new Error("the github lexicon's package.json has no version to pin the review note job's chant to");
|
|
61
|
+
}
|
|
62
|
+
return pkg.version;
|
|
63
|
+
}
|
|
64
|
+
/** What the note job runs under node: `postReviewNote` over the review the review job handed on. Plain JavaScript, no `${{ }}`. */
|
|
65
|
+
const NOTE_SCRIPT = [
|
|
66
|
+
'import { postReviewNote } from "@intentius/chant/op/activities/review-agent";',
|
|
67
|
+
`const { CHANT_OP: op, ${REVIEW_DIR_ENV}: dir } = process.env;`,
|
|
68
|
+
"const result = await postReviewNote({ op, dir });",
|
|
69
|
+
"console.log(result.reason);",
|
|
70
|
+
"if (!result.posted) process.exitCode = 1;",
|
|
71
|
+
].join("\n");
|
|
72
|
+
/** Where the note job puts the review it took back: outside any checkout, which it has none of. */
|
|
73
|
+
const NOTE_DIR = '"${RUNNER_TEMP:-/tmp}/chant-review"';
|
|
74
|
+
/** The note step's shell: install the pinned chant beside the review and run {@link NOTE_SCRIPT} with tsx. */
|
|
75
|
+
function noteScript(version) {
|
|
76
|
+
return [
|
|
77
|
+
`review=${NOTE_DIR}`,
|
|
78
|
+
'dir="${RUNNER_TEMP:-/tmp}/chant-review-note"',
|
|
79
|
+
'mkdir -p "$dir"',
|
|
80
|
+
'cd "$dir"',
|
|
81
|
+
"echo '{\"private\":true}' > package.json",
|
|
82
|
+
`npm install --omit=peer --no-audit --no-fund --loglevel=error @intentius/chant@${version}`,
|
|
83
|
+
"cat > note.mjs <<'NOTE'",
|
|
84
|
+
NOTE_SCRIPT,
|
|
85
|
+
"NOTE",
|
|
86
|
+
`${REVIEW_DIR_ENV}="$review" node --import tsx note.mjs`,
|
|
87
|
+
].join("\n");
|
|
88
|
+
}
|
|
89
|
+
/** The review job and the note job of one split review. */
|
|
90
|
+
export function reviewJobs(i) {
|
|
91
|
+
const drop = dropForgeTokens("sh");
|
|
92
|
+
const rooted = !i.member || i.member.dir === "." || i.member.dir === "";
|
|
93
|
+
const headStep = (line) => ({ run: `${drop}\n${line}` });
|
|
94
|
+
const review = {
|
|
95
|
+
"runs-on": GITHUB_RUNNER,
|
|
96
|
+
container: i.image,
|
|
97
|
+
...(i.variables && Object.keys(i.variables).length > 0 ? { env: i.variables } : {}),
|
|
98
|
+
outputs: handoverOutputs(REVIEW_STEP_ID, "github"),
|
|
99
|
+
steps: [
|
|
100
|
+
// A script, not actions/checkout: the token reaches the fetches alone, and the base branch's history comes with them for the diff.
|
|
101
|
+
{
|
|
102
|
+
name: "Check out the change",
|
|
103
|
+
...(rooted ? {} : { "working-directory": "." }),
|
|
104
|
+
env: { [CHECKOUT_TOKEN_ENV]: GITHUB_JOB_TOKEN },
|
|
105
|
+
run: checkoutScript(true),
|
|
106
|
+
},
|
|
107
|
+
...i.setup,
|
|
108
|
+
...i.beforeScript.map(headStep),
|
|
109
|
+
// The job's last step: it hands the review directory on as the job's outputs when it ends, however it ends.
|
|
110
|
+
{
|
|
111
|
+
id: REVIEW_STEP_ID,
|
|
112
|
+
name: "Run the Op and keep its review",
|
|
113
|
+
env: { [REVIEW_DIR_ENV]: REVIEW_DIR },
|
|
114
|
+
run: [drop, ...handoverTrap(REVIEW_DIR, "github"), i.invocation, ...i.extraScript].join("\n"),
|
|
115
|
+
},
|
|
116
|
+
],
|
|
117
|
+
};
|
|
118
|
+
const note = {
|
|
119
|
+
needs: i.jobName,
|
|
120
|
+
if: `needs.${i.jobName}.result == 'success'`,
|
|
121
|
+
"runs-on": GITHUB_RUNNER,
|
|
122
|
+
container: i.image,
|
|
123
|
+
permissions: { "pull-requests": "write" },
|
|
124
|
+
steps: [
|
|
125
|
+
{ name: "Take the review from the review job", run: takeOverScript(i.jobName, NOTE_DIR, "github") },
|
|
126
|
+
{ name: "Post the review as a note", env: { GITHUB_TOKEN: GITHUB_JOB_TOKEN, CHANT_OP: i.name }, run: noteScript(chantVersion()) },
|
|
127
|
+
],
|
|
128
|
+
};
|
|
129
|
+
return { review, note };
|
|
130
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/composites/cache.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/composites/cache.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAE1C,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;KACvD,CAAC;CACH;AAED,eAAO,MAAM,WAAW;;EAeb,CAAC"}
|
package/dist/composites/cache.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Composite, mergeDefaults } from "@intentius/chant";
|
|
2
|
+
import { actionRef } from "../action-pins.js";
|
|
2
3
|
import { Step } from "../generated/index.js";
|
|
3
4
|
export const CacheAction = Composite((props) => {
|
|
4
5
|
const { defaults } = props;
|
|
@@ -10,7 +11,7 @@ export const CacheAction = Composite((props) => {
|
|
|
10
11
|
withObj["restore-keys"] = props.restoreKeys.join("\n");
|
|
11
12
|
const step = new Step(mergeDefaults({
|
|
12
13
|
name: "Cache",
|
|
13
|
-
uses: "actions/cache
|
|
14
|
+
uses: actionRef("actions/cache"),
|
|
14
15
|
with: withObj,
|
|
15
16
|
}, defaults?.step));
|
|
16
17
|
return { step };
|
|
@@ -8,9 +8,9 @@ export interface CheckoutProps {
|
|
|
8
8
|
submodules?: boolean | string;
|
|
9
9
|
sshKey?: string;
|
|
10
10
|
/**
|
|
11
|
-
* `"
|
|
12
|
-
*
|
|
13
|
-
*
|
|
11
|
+
* `"sha"` (default) emits the commit SHA from the pin table with the version as
|
|
12
|
+
* a YAML comment, which passes GHA021, GHA029 and GHA059. `"tag"` emits the
|
|
13
|
+
* action's major tag.
|
|
14
14
|
*/
|
|
15
15
|
pin?: ActionPinMode;
|
|
16
16
|
defaults?: {
|
|
@@ -18,7 +18,7 @@ export const Checkout = Composite((props) => {
|
|
|
18
18
|
withObj["ssh-key"] = props.sshKey;
|
|
19
19
|
const step = new Step(mergeDefaults({
|
|
20
20
|
name: "Checkout",
|
|
21
|
-
uses: actionRef("actions/checkout", props.pin),
|
|
21
|
+
uses: actionRef("actions/checkout", props.pin ?? "sha"),
|
|
22
22
|
...(Object.keys(withObj).length > 0 ? { with: withObj } : {}),
|
|
23
23
|
}, defaults?.step));
|
|
24
24
|
return { step };
|
|
@@ -7,7 +7,7 @@ export const DockerBuild = Composite((props) => {
|
|
|
7
7
|
const checkout = new Step({ name: "Checkout", uses: actionRef("actions/checkout") });
|
|
8
8
|
const login = new Step({
|
|
9
9
|
name: "Log in to container registry",
|
|
10
|
-
uses: "docker/login-action
|
|
10
|
+
uses: actionRef("docker/login-action"),
|
|
11
11
|
with: {
|
|
12
12
|
registry,
|
|
13
13
|
username: "${{ github.actor }}",
|
|
@@ -16,7 +16,7 @@ export const DockerBuild = Composite((props) => {
|
|
|
16
16
|
});
|
|
17
17
|
const setupBuildx = new Step({
|
|
18
18
|
name: "Set up Docker Buildx",
|
|
19
|
-
uses: "docker/setup-buildx-action
|
|
19
|
+
uses: actionRef("docker/setup-buildx-action"),
|
|
20
20
|
});
|
|
21
21
|
// Build tags for metadata action
|
|
22
22
|
const tags = [`${imageName}:${tag}`];
|
|
@@ -26,7 +26,7 @@ export const DockerBuild = Composite((props) => {
|
|
|
26
26
|
const metadata = new Step({
|
|
27
27
|
name: "Extract metadata",
|
|
28
28
|
id: "meta",
|
|
29
|
-
uses: "docker/metadata-action
|
|
29
|
+
uses: actionRef("docker/metadata-action"),
|
|
30
30
|
with: {
|
|
31
31
|
images: imageName,
|
|
32
32
|
tags: tags.join("\n"),
|
|
@@ -49,7 +49,7 @@ export const DockerBuild = Composite((props) => {
|
|
|
49
49
|
}
|
|
50
50
|
const buildPush = new Step({
|
|
51
51
|
name: "Build and push",
|
|
52
|
-
uses: "docker/build-push-action
|
|
52
|
+
uses: actionRef("docker/build-push-action"),
|
|
53
53
|
with: buildPushWith,
|
|
54
54
|
});
|
|
55
55
|
const job = new Job(mergeDefaults({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"download-artifact.d.ts","sourceRoot":"","sources":["../../src/composites/download-artifact.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"download-artifact.d.ts","sourceRoot":"","sources":["../../src/composites/download-artifact.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAE1C,MAAM,WAAW,qBAAqB;IACpC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;KACvD,CAAC;CACH;AAED,eAAO,MAAM,gBAAgB;;EAcP,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Composite, mergeDefaults } from "@intentius/chant";
|
|
2
|
+
import { actionRef } from "../action-pins.js";
|
|
2
3
|
import { Step } from "../generated/index.js";
|
|
3
4
|
export const DownloadArtifact = Composite((props) => {
|
|
4
5
|
const { defaults } = props;
|
|
@@ -11,7 +12,7 @@ export const DownloadArtifact = Composite((props) => {
|
|
|
11
12
|
withObj["merge-multiple"] = String(props.mergeMultiple);
|
|
12
13
|
const step = new Step(mergeDefaults({
|
|
13
14
|
name: "Download Artifact",
|
|
14
|
-
uses: "actions/download-artifact
|
|
15
|
+
uses: actionRef("actions/download-artifact"),
|
|
15
16
|
...(Object.keys(withObj).length > 0 ? { with: withObj } : {}),
|
|
16
17
|
}, defaults?.step));
|
|
17
18
|
return { step };
|
package/dist/composites/go-ci.js
CHANGED
|
@@ -10,7 +10,7 @@ export const GoCI = Composite((props) => {
|
|
|
10
10
|
new Step({ name: "Checkout", uses: actionRef("actions/checkout") }),
|
|
11
11
|
new Step({
|
|
12
12
|
name: "Setup Go",
|
|
13
|
-
uses: "actions/setup-go
|
|
13
|
+
uses: actionRef("actions/setup-go"),
|
|
14
14
|
with: { "go-version": goVersion },
|
|
15
15
|
}),
|
|
16
16
|
new Step({ name: "Build", run: buildCommand }),
|
|
@@ -23,7 +23,7 @@ export const GoCI = Composite((props) => {
|
|
|
23
23
|
new Step({ name: "Checkout", uses: actionRef("actions/checkout") }),
|
|
24
24
|
new Step({
|
|
25
25
|
name: "Setup Go",
|
|
26
|
-
uses: "actions/setup-go
|
|
26
|
+
uses: actionRef("actions/setup-go"),
|
|
27
27
|
with: { "go-version": goVersion },
|
|
28
28
|
}),
|
|
29
29
|
new Step({ name: "Test", run: testCommand }),
|
|
@@ -37,12 +37,12 @@ export const GoCI = Composite((props) => {
|
|
|
37
37
|
new Step({ name: "Checkout", uses: actionRef("actions/checkout") }),
|
|
38
38
|
new Step({
|
|
39
39
|
name: "Setup Go",
|
|
40
|
-
uses: "actions/setup-go
|
|
40
|
+
uses: actionRef("actions/setup-go"),
|
|
41
41
|
with: { "go-version": goVersion },
|
|
42
42
|
}),
|
|
43
43
|
new Step({
|
|
44
44
|
name: "Lint",
|
|
45
|
-
uses: "golangci/golangci-lint-action
|
|
45
|
+
uses: actionRef("golangci/golangci-lint-action"),
|
|
46
46
|
with: { args: lintCommand },
|
|
47
47
|
}),
|
|
48
48
|
],
|
|
@@ -24,7 +24,7 @@ const cacheConfig = {
|
|
|
24
24
|
cache: undefined,
|
|
25
25
|
installCmd: "bun install --frozen-lockfile",
|
|
26
26
|
runPrefix: "bun run",
|
|
27
|
-
setupAction: "oven-sh/setup-bun
|
|
27
|
+
setupAction: actionRef("oven-sh/setup-bun"),
|
|
28
28
|
},
|
|
29
29
|
};
|
|
30
30
|
export const NodePipeline = Composite((props) => {
|
|
@@ -36,7 +36,7 @@ export const NodePipeline = Composite((props) => {
|
|
|
36
36
|
// ── Build job steps ────────────────────────────────────────────────
|
|
37
37
|
const buildCheckout = new Step({ name: "Checkout", uses: actionRef("actions/checkout") });
|
|
38
38
|
const buildSetup = isBun
|
|
39
|
-
? new Step({ name: "Setup Bun", uses: "oven-sh/setup-bun
|
|
39
|
+
? new Step({ name: "Setup Bun", uses: actionRef("oven-sh/setup-bun") })
|
|
40
40
|
: new Step({
|
|
41
41
|
name: "Setup Node.js",
|
|
42
42
|
uses: actionRef("actions/setup-node"),
|
|
@@ -46,7 +46,7 @@ export const NodePipeline = Composite((props) => {
|
|
|
46
46
|
const buildRun = new Step({ name: "Build", run: `${run} ${buildScript}` });
|
|
47
47
|
const buildUpload = new Step({
|
|
48
48
|
name: "Upload build artifacts",
|
|
49
|
-
uses: "actions/upload-artifact
|
|
49
|
+
uses: actionRef("actions/upload-artifact"),
|
|
50
50
|
with: {
|
|
51
51
|
name: artifactName,
|
|
52
52
|
path: buildArtifactPaths.join("\n"),
|
|
@@ -60,7 +60,7 @@ export const NodePipeline = Composite((props) => {
|
|
|
60
60
|
// ── Test job steps ─────────────────────────────────────────────────
|
|
61
61
|
const testCheckout = new Step({ name: "Checkout", uses: actionRef("actions/checkout") });
|
|
62
62
|
const testSetup = isBun
|
|
63
|
-
? new Step({ name: "Setup Bun", uses: "oven-sh/setup-bun
|
|
63
|
+
? new Step({ name: "Setup Bun", uses: actionRef("oven-sh/setup-bun") })
|
|
64
64
|
: new Step({
|
|
65
65
|
name: "Setup Node.js",
|
|
66
66
|
uses: actionRef("actions/setup-node"),
|
|
@@ -69,7 +69,7 @@ export const NodePipeline = Composite((props) => {
|
|
|
69
69
|
const testInstall = new Step({ name: "Install dependencies", run: install });
|
|
70
70
|
const testDownload = new Step({
|
|
71
71
|
name: "Download build artifacts",
|
|
72
|
-
uses: "actions/download-artifact
|
|
72
|
+
uses: actionRef("actions/download-artifact"),
|
|
73
73
|
with: { name: artifactName },
|
|
74
74
|
});
|
|
75
75
|
const testRun = new Step({ name: "Test", run: `${run} ${testScript}` });
|
|
@@ -19,7 +19,7 @@ export const PythonCI = Composite((props) => {
|
|
|
19
19
|
new Step({ name: "Checkout", uses: actionRef("actions/checkout") }),
|
|
20
20
|
new Step({
|
|
21
21
|
name: "Setup Python",
|
|
22
|
-
uses: "actions/setup-python
|
|
22
|
+
uses: actionRef("actions/setup-python"),
|
|
23
23
|
with: { "python-version": pythonVersion, cache: cacheType },
|
|
24
24
|
}),
|
|
25
25
|
...installSteps,
|
|
@@ -34,7 +34,7 @@ export const PythonCI = Composite((props) => {
|
|
|
34
34
|
new Step({ name: "Checkout", uses: actionRef("actions/checkout") }),
|
|
35
35
|
new Step({
|
|
36
36
|
name: "Setup Python",
|
|
37
|
-
uses: "actions/setup-python
|
|
37
|
+
uses: actionRef("actions/setup-python"),
|
|
38
38
|
with: { "python-version": pythonVersion, cache: cacheType },
|
|
39
39
|
}),
|
|
40
40
|
...installSteps.map((s) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup-go.d.ts","sourceRoot":"","sources":["../../src/composites/setup-go.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"setup-go.d.ts","sourceRoot":"","sources":["../../src/composites/setup-go.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAE1C,MAAM,WAAW,YAAY;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;KACvD,CAAC;CACH;AAED,eAAO,MAAM,OAAO;;EAcP,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Composite, mergeDefaults } from "@intentius/chant";
|
|
2
|
+
import { actionRef } from "../action-pins.js";
|
|
2
3
|
import { Step } from "../generated/index.js";
|
|
3
4
|
export const SetupGo = Composite((props) => {
|
|
4
5
|
const { defaults } = props;
|
|
@@ -11,7 +12,7 @@ export const SetupGo = Composite((props) => {
|
|
|
11
12
|
withObj.cache = String(props.cache);
|
|
12
13
|
const step = new Step(mergeDefaults({
|
|
13
14
|
name: "Setup Go",
|
|
14
|
-
uses: "actions/setup-go
|
|
15
|
+
uses: actionRef("actions/setup-go"),
|
|
15
16
|
...(Object.keys(withObj).length > 0 ? { with: withObj } : {}),
|
|
16
17
|
}, defaults?.step));
|
|
17
18
|
return { step };
|
|
@@ -6,9 +6,9 @@ export interface SetupNodeProps {
|
|
|
6
6
|
cache?: string;
|
|
7
7
|
cacheFilePath?: string;
|
|
8
8
|
/**
|
|
9
|
-
* `"
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* `"sha"` (default) emits the commit SHA from the pin table with the version as
|
|
10
|
+
* a YAML comment, which passes GHA021, GHA029 and GHA059. `"tag"` emits the
|
|
11
|
+
* action's major tag.
|
|
12
12
|
*/
|
|
13
13
|
pin?: ActionPinMode;
|
|
14
14
|
defaults?: {
|
|
@@ -14,7 +14,7 @@ export const SetupNode = Composite((props) => {
|
|
|
14
14
|
withObj["cache-dependency-path"] = props.cacheFilePath;
|
|
15
15
|
const step = new Step(mergeDefaults({
|
|
16
16
|
name: "Setup Node.js",
|
|
17
|
-
uses: actionRef("actions/setup-node", props.pin),
|
|
17
|
+
uses: actionRef("actions/setup-node", props.pin ?? "sha"),
|
|
18
18
|
...(Object.keys(withObj).length > 0 ? { with: withObj } : {}),
|
|
19
19
|
}, defaults?.step));
|
|
20
20
|
return { step };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup-python.d.ts","sourceRoot":"","sources":["../../src/composites/setup-python.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"setup-python.d.ts","sourceRoot":"","sources":["../../src/composites/setup-python.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAE1C,MAAM,WAAW,gBAAgB;IAC/B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;KACvD,CAAC;CACH;AAED,eAAO,MAAM,WAAW;;EAcP,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Composite, mergeDefaults } from "@intentius/chant";
|
|
2
|
+
import { actionRef } from "../action-pins.js";
|
|
2
3
|
import { Step } from "../generated/index.js";
|
|
3
4
|
export const SetupPython = Composite((props) => {
|
|
4
5
|
const { defaults } = props;
|
|
@@ -11,7 +12,7 @@ export const SetupPython = Composite((props) => {
|
|
|
11
12
|
withObj.architecture = props.architecture;
|
|
12
13
|
const step = new Step(mergeDefaults({
|
|
13
14
|
name: "Setup Python",
|
|
14
|
-
uses: "actions/setup-python
|
|
15
|
+
uses: actionRef("actions/setup-python"),
|
|
15
16
|
...(Object.keys(withObj).length > 0 ? { with: withObj } : {}),
|
|
16
17
|
}, defaults?.step));
|
|
17
18
|
return { step };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"upload-artifact.d.ts","sourceRoot":"","sources":["../../src/composites/upload-artifact.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"upload-artifact.d.ts","sourceRoot":"","sources":["../../src/composites/upload-artifact.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAE1C,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;KACvD,CAAC;CACH;AAED,eAAO,MAAM,cAAc;;EAgBP,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Composite, mergeDefaults } from "@intentius/chant";
|
|
2
|
+
import { actionRef } from "../action-pins.js";
|
|
2
3
|
import { Step } from "../generated/index.js";
|
|
3
4
|
export const UploadArtifact = Composite((props) => {
|
|
4
5
|
const { defaults } = props;
|
|
@@ -12,7 +13,7 @@ export const UploadArtifact = Composite((props) => {
|
|
|
12
13
|
withObj["compression-level"] = String(props.compressionLevel);
|
|
13
14
|
const step = new Step(mergeDefaults({
|
|
14
15
|
name: "Upload Artifact",
|
|
15
|
-
uses: "actions/upload-artifact
|
|
16
|
+
uses: actionRef("actions/upload-artifact"),
|
|
16
17
|
with: withObj,
|
|
17
18
|
}, defaults?.step));
|
|
18
19
|
return { step };
|
package/dist/integrity.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"algorithm": "sha256",
|
|
3
3
|
"artifacts": {
|
|
4
|
-
"manifest.json": "
|
|
4
|
+
"manifest.json": "2ab0288c67ef2f7a4bb7460a92ba6c3b41b4a9df4a621345b785232106686f03",
|
|
5
5
|
"meta.json": "c50e0ef3845c370c3ad2210b8bba455980417c0f818aa6ed46e06d4fb8b1b9f9",
|
|
6
6
|
"types/index.d.ts": "0ead95536e947ddfb98a5acf0ddb88547913b5a53a342df67711c59266f84b3e",
|
|
7
7
|
"rules/deprecated-action-version.ts": "a9ba7cc924ff1c7055110416d8989273690415bfb5e8dcc32dc9431b9351f5ca",
|
|
@@ -78,5 +78,5 @@
|
|
|
78
78
|
"skills/chant-github-patterns.md": "bb3abef289a8fdfcf07d6bb2d7289dcb2f38bc0cb0321ea320b78b45a6f548c0",
|
|
79
79
|
"skills/chant-github-security.md": "aab111cb0871cad30281ce48d7da23663689619351029219e2be019a1a61e394"
|
|
80
80
|
},
|
|
81
|
-
"composite": "
|
|
81
|
+
"composite": "16abcb23dd004ef25298433d5f4d8fbbe6f21bd10e7ab5db5706818ba499f918"
|
|
82
82
|
}
|
package/dist/manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intentius/chant-lexicon-github",
|
|
3
|
-
"version": "0.124.
|
|
3
|
+
"version": "0.124.48",
|
|
4
4
|
"description": "GitHub Actions lexicon for chant — declarative IaC in TypeScript",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://intentius.io/chant",
|
|
@@ -61,6 +61,6 @@
|
|
|
61
61
|
"typescript": "^5.9.3"
|
|
62
62
|
},
|
|
63
63
|
"peerDependencies": {
|
|
64
|
-
"@intentius/chant": "^0.124.
|
|
64
|
+
"@intentius/chant": "^0.124.48"
|
|
65
65
|
}
|
|
66
66
|
}
|
package/src/action-pins.test.ts
CHANGED
|
@@ -6,7 +6,12 @@ import { Workflow, Job } from "./generated/index";
|
|
|
6
6
|
import { Checkout } from "./composites/checkout";
|
|
7
7
|
import { SetupNode } from "./composites/setup-node";
|
|
8
8
|
import { githubSerializer } from "./serializer";
|
|
9
|
+
import { ACTION_PINS as CORE_PINS } from "@intentius/chant/action-pins";
|
|
9
10
|
import { ACTION_PINS, actionRef } from "./action-pins";
|
|
11
|
+
import { CacheAction } from "./composites/cache";
|
|
12
|
+
import { DockerBuild } from "./composites/docker-build";
|
|
13
|
+
import { GoCI } from "./composites/go-ci";
|
|
14
|
+
import { UploadArtifact } from "./composites/upload-artifact";
|
|
10
15
|
import { gha021 } from "./lint/post-synth/gha021";
|
|
11
16
|
import { gha029 } from "./lint/post-synth/gha029";
|
|
12
17
|
import { gha059 } from "./lint/post-synth/gha059";
|
|
@@ -47,15 +52,33 @@ describe("action pins (#2510)", () => {
|
|
|
47
52
|
}
|
|
48
53
|
});
|
|
49
54
|
|
|
50
|
-
test("
|
|
51
|
-
|
|
52
|
-
|
|
55
|
+
test("every row is a row of core's table (#4410)", () => {
|
|
56
|
+
const coreShas = new Set(Object.values(CORE_PINS).map((p) => p.sha));
|
|
57
|
+
for (const [slug, pin] of Object.entries(ACTION_PINS)) {
|
|
58
|
+
expect({ slug, inCore: coreShas.has(pin.sha) }).toEqual({ slug, inCore: true });
|
|
59
|
+
}
|
|
60
|
+
expect(ACTION_PINS["actions/setup-node"].sha).toBe(CORE_PINS.setupNode7.sha);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("composites default to the pinned SHA with the release comment (#4410)", () => {
|
|
64
|
+
const uses = (c: { step: unknown }) => ((c.step as { props: unknown }).props as { uses?: string }).uses;
|
|
65
|
+
expect(uses(Checkout({}))).toBe(actionRef("actions/checkout", "sha"));
|
|
66
|
+
expect(uses(SetupNode({}))).toBe(actionRef("actions/setup-node", "sha"));
|
|
67
|
+
expect(uses(CacheAction({ path: "p", key: "k" }))).toBe(actionRef("actions/cache", "sha"));
|
|
68
|
+
expect(uses(UploadArtifact({ name: "n", path: "p" }))).toBe(actionRef("actions/upload-artifact", "sha"));
|
|
69
|
+
expect(actionRef("actions/checkout", "sha")).toMatch(/^actions\/checkout@[0-9a-f]{40} # v\d+\.\d+\.\d+$/);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test("pin: \"tag\" still emits the major tag, and an explicit ref wins", () => {
|
|
73
|
+
expect((Checkout({ pin: "tag" }).step.props as { uses?: string }).uses).toBe("actions/checkout@v7");
|
|
74
|
+
const mine = CacheAction({ path: "p", key: "k", defaults: { step: { uses: "actions/cache@v3" } } });
|
|
75
|
+
expect((mine.step.props as { uses?: string }).uses).toBe("actions/cache@v3");
|
|
53
76
|
});
|
|
54
77
|
|
|
55
78
|
test("pin: \"sha\" writes the SHA as the ref and the version as a YAML comment", () => {
|
|
56
79
|
const yaml = workflowYaml("sha");
|
|
57
80
|
expect(yaml).toContain(`uses: actions/checkout@${ACTION_PINS["actions/checkout"].sha} # v7.0.1\n`);
|
|
58
|
-
expect(yaml).toContain(`uses: actions/setup-node@${ACTION_PINS["actions/setup-node"].sha} #
|
|
81
|
+
expect(yaml).toContain(`uses: actions/setup-node@${ACTION_PINS["actions/setup-node"].sha} # ${ACTION_PINS["actions/setup-node"].version}\n`);
|
|
59
82
|
expect(yaml).not.toMatch(/uses: '/);
|
|
60
83
|
});
|
|
61
84
|
|
|
@@ -63,8 +86,8 @@ describe("action pins (#2510)", () => {
|
|
|
63
86
|
expect(pinningFindings(workflowYaml("sha"))).toEqual([]);
|
|
64
87
|
});
|
|
65
88
|
|
|
66
|
-
test("the
|
|
67
|
-
const messages = pinningFindings(workflowYaml()).map((d) => d.message);
|
|
89
|
+
test("the tag warning names the exact fix", () => {
|
|
90
|
+
const messages = pinningFindings(workflowYaml("tag")).map((d) => d.message);
|
|
68
91
|
expect(messages).toHaveLength(2);
|
|
69
92
|
expect(messages[0]).toContain(`\`uses: ${actionRef("actions/checkout", "sha")}\``);
|
|
70
93
|
expect(messages[0]).toContain(`Checkout({ pin: "sha" })`);
|