@intentius/chant-lexicon-forgejo 0.62.0 → 0.64.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/components/generate-op-pipeline.d.ts +37 -5
- package/dist/components/generate-op-pipeline.d.ts.map +1 -1
- package/dist/integrity.json +2 -2
- package/dist/manifest.json +1 -1
- package/package.json +3 -3
- package/src/components/generate-op-pipeline.test.ts +55 -8
- package/src/components/generate-op-pipeline.ts +54 -5
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
* no mapping in ../actions.ts passes through verbatim and resolves only if
|
|
29
29
|
* the runner can fetch it.
|
|
30
30
|
*
|
|
31
|
-
* `comment` (#2231) crosses over
|
|
31
|
+
* `comment` (#2231) crosses over, since chant #2291: it posts onto the
|
|
32
32
|
* triggering pull request by shelling to `gh` against `${GITHUB_API_URL}`,
|
|
33
33
|
* and a Forgejo Actions job already sets that (and `github.token`) the same
|
|
34
34
|
* way a GitHub Actions job does. This generator used to refuse the mode by
|
|
@@ -38,10 +38,42 @@
|
|
|
38
38
|
* false — the failure was `gh api` resolving a *relative* path against
|
|
39
39
|
* `/api/v3`, which Forgejo does not serve, not an unreachable forge. See
|
|
40
40
|
* `reconcilePr`'s `postOrUpdateComment` (`packages/core/src/op/activities/reconcile.ts`)
|
|
41
|
-
* for the fix.
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
41
|
+
* for the fix.
|
|
42
|
+
*
|
|
43
|
+
* `issue` (`gh issue create`/`postOrUpdateGithubIssue`) does not cross over,
|
|
44
|
+
* and chant #2315 is why: it remained un-refused-but-unverified after #2304
|
|
45
|
+
* lifted `comment`'s refusal, and settling that gap the same way — against a
|
|
46
|
+
* real instance rather than a mock — found a real failure, so the refusal
|
|
47
|
+
* below is reinstated rather than lifted. Tested against the same
|
|
48
|
+
* 12.0.4+gitea-1.22.0 image (`codeberg.org/forgejo/forgejo:12`) with a repo,
|
|
49
|
+
* an issue, and a pull request created on it: the *read* half of
|
|
50
|
+
* `postOrUpdateGithubIssue` checks out fine on Forgejo — plain paginated
|
|
51
|
+
* `GET .../issues?state=open` (no `/search/issues`, confirmed absent from a
|
|
52
|
+
* live Forgejo's own OpenAPI spec) returns pull requests interleaved with
|
|
53
|
+
* issues exactly as GitHub's endpoint does, and the `.pull_request == null`
|
|
54
|
+
* filter and the marker `startswith` match both behave identically to
|
|
55
|
+
* GitHub. The *write* half does not: `postOrUpdateGithubIssue`'s POST and
|
|
56
|
+
* PATCH calls carry only `GH_TOKEN` (in fact, on the `issue` path, not even
|
|
57
|
+
* that — `reconcilePr` hands it `execAsync` with no `env` override at all,
|
|
58
|
+
* chant #2320), and `gh`'s own documented environment variables (`gh help
|
|
59
|
+
* environment`) scope `GH_TOKEN`/`GITHUB_TOKEN` to "github.com or a subdomain
|
|
60
|
+
* of ghe.com" — never a self-hosted Forgejo. A `GH_DEBUG=api` POST against
|
|
61
|
+
* the live instance, with `GH_TOKEN` and `GITHUB_API_URL` set exactly as the
|
|
62
|
+
* generated workflow sets them, sent no `Authorization` header at all and
|
|
63
|
+
* Forgejo answered `{"message":"token is required"}` (HTTP 401); adding
|
|
64
|
+
* `GH_HOST` alongside `GH_TOKEN` made no difference. Only `GH_ENTERPRISE_TOKEN`
|
|
65
|
+
* paired with a matching `GH_HOST` authenticated the same call. Since neither
|
|
66
|
+
* `postOrUpdateGithubIssue` nor its caller sets either, every write this mode
|
|
67
|
+
* makes on Forgejo fails — not a slow search, a 401 on every run. The same
|
|
68
|
+
* shape (`GH_TOKEN` only, no `GH_HOST`/`GH_ENTERPRISE_TOKEN`) is what
|
|
69
|
+
* `postOrUpdateComment`'s writes carry too, which means #2304's "verified
|
|
70
|
+
* against a real Forgejo instance" could not have gone through the generated
|
|
71
|
+
* workflow's own credential path — either that session had a `gh auth login`
|
|
72
|
+
* already stored for the test instance, which a real Actions job's fresh
|
|
73
|
+
* checkout never has, or a different `gh` build was in play. That is
|
|
74
|
+
* `comment` mode's problem to re-verify, not `issue` mode's, and out of
|
|
75
|
+
* scope for chant #2315; flagged here because finding it is what closes that
|
|
76
|
+
* issue's question of whether to lift or reinstate this refusal.
|
|
45
77
|
*
|
|
46
78
|
* A spec's `environment` (#2257) is dropped on the same terms as
|
|
47
79
|
* `permissions:`, and for a stronger reason: Forgejo Actions has no
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-op-pipeline.d.ts","sourceRoot":"","sources":["../../src/components/generate-op-pipeline.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"generate-op-pipeline.d.ts","sourceRoot":"","sources":["../../src/components/generate-op-pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoHG;AAOH,OAAO,KAAK,EACV,wBAAwB,EACxB,gBAAgB,EAChB,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAA2B,KAAK,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAmCjF;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,eAAe,EAAE,EACtB,OAAO,GAAE,wBAA6B,EACtC,cAAc,GAAE,qBAA0B,GACzC,gBAAgB,CA4ClB"}
|
package/dist/integrity.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"algorithm": "sha256",
|
|
3
3
|
"artifacts": {
|
|
4
|
-
"manifest.json": "
|
|
4
|
+
"manifest.json": "b27a0caa6602113e3055867aa963f678a9711619cf73741170ae05938f562af0",
|
|
5
5
|
"meta.json": "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
|
|
6
6
|
"types/index.d.ts": "66204549b2a864ab5489e3f02c1878e73ab4b3c9d938cfb480b66f71543a43de",
|
|
7
7
|
"rules/delegate-to-github.ts": "1060cda40f4b73d6cca3ba3fa13b80b4886147d4034c88584c2d80c5510dbe5e",
|
|
@@ -9,5 +9,5 @@
|
|
|
9
9
|
"rules/wfj011.ts": "fcb8bf6685d744af20ad804ce929488257995c74b9a3353b2eacae3768d1c83e",
|
|
10
10
|
"skills/chant-forgejo.md": "a1a560429db736c187e0b34cf8dd9efc6ad771afefcbf6f802d160d3d5274257"
|
|
11
11
|
},
|
|
12
|
-
"composite": "
|
|
12
|
+
"composite": "a8a40b48d5887134deb8e9feb9ffa1ea5502fd1e4c9ce7462f48d10368e1d881"
|
|
13
13
|
}
|
package/dist/manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intentius/chant-lexicon-forgejo",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.64.0",
|
|
4
4
|
"description": "Forgejo / Codeberg / Gitea Actions lexicon for chant — a thin GitHub Actions dialect",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://intentius.io/chant",
|
|
@@ -54,8 +54,8 @@
|
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
56
|
"zod": "^4.3.6",
|
|
57
|
-
"@intentius/chant": "^0.
|
|
58
|
-
"@intentius/chant-lexicon-github": "^0.
|
|
57
|
+
"@intentius/chant": "^0.64.0",
|
|
58
|
+
"@intentius/chant-lexicon-github": "^0.64.0"
|
|
59
59
|
},
|
|
60
60
|
"scripts": {
|
|
61
61
|
"generate": "tsx src/codegen/generate-cli.ts",
|
|
@@ -33,7 +33,7 @@ describe("generateForgejoOpPipeline: structure (github-shaped)", () => {
|
|
|
33
33
|
test("one file per scheduled Op, each a valid workflow with one job", () => {
|
|
34
34
|
const specs: ScheduledOpSpec[] = [
|
|
35
35
|
{ name: "actions-audit", schedule: "0 6 * * *" },
|
|
36
|
-
{ name: "prod-reconcile", schedule: "0 * * * *", findingMode: "
|
|
36
|
+
{ name: "prod-reconcile", schedule: "0 * * * *", findingMode: "pull-request" },
|
|
37
37
|
];
|
|
38
38
|
const result = generateForgejoOpPipeline(specs);
|
|
39
39
|
|
|
@@ -78,7 +78,7 @@ describe("generateForgejoOpPipeline: dialect applied", () => {
|
|
|
78
78
|
describe("generateForgejoOpPipeline: non-cron trigger survives the dialect transform (#2084)", () => {
|
|
79
79
|
test("a pull_request trigger round-trips through the Forgejo dialect, with permissions: still dropped", () => {
|
|
80
80
|
const specs: ScheduledOpSpec[] = [
|
|
81
|
-
{ name: "tf-plan", trigger: { kind: "pull_request", branches: ["main"] }, findingMode: "
|
|
81
|
+
{ name: "tf-plan", trigger: { kind: "pull_request", branches: ["main"] }, findingMode: "pull-request" },
|
|
82
82
|
];
|
|
83
83
|
const fj = generateForgejoOpPipeline(specs);
|
|
84
84
|
const gh = generateGithubOpPipeline(specs);
|
|
@@ -149,6 +149,35 @@ describe("generateForgejoOpPipeline: comment finding mode crosses over (#2291)",
|
|
|
149
149
|
});
|
|
150
150
|
});
|
|
151
151
|
|
|
152
|
+
describe("generateForgejoOpPipeline: issue finding mode is refused by name (#2315)", () => {
|
|
153
|
+
// `comment` (above) was checked against a real Forgejo instance and cleared
|
|
154
|
+
// (#2291, #2304). `issue` stayed un-refused-but-unverified after that —
|
|
155
|
+
// this is the same settling, and it came out the other way: a real
|
|
156
|
+
// instance showed the write half of `postOrUpdateGithubIssue` cannot
|
|
157
|
+
// authenticate (`gh`'s GH_TOKEN never reaches a self-hosted Forgejo), so
|
|
158
|
+
// the refusal this mode used to carry (pre-#2304, for a different reason)
|
|
159
|
+
// is reinstated rather than left lifted. See the module doc above for the
|
|
160
|
+
// reproduction.
|
|
161
|
+
test("findingMode issue is refused, naming the Op and the real-instance failure", () => {
|
|
162
|
+
const specs: ScheduledOpSpec[] = [{ name: "prod-watch", schedule: "0 6 * * *", findingMode: "issue" }];
|
|
163
|
+
expect(() => generateForgejoOpPipeline(specs)).toThrow(
|
|
164
|
+
/Scheduled Op "prod-watch".*findingMode "issue".*token is required/s,
|
|
165
|
+
);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
test("github generates the same spec cleanly, so the refusal is forgejo's and not the shared builder's", () => {
|
|
169
|
+
const specs: ScheduledOpSpec[] = [{ name: "prod-watch", schedule: "0 6 * * *", findingMode: "issue" }];
|
|
170
|
+
expect(() => generateGithubOpPipeline(specs)).not.toThrow();
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test("a pull_request-triggered Op is refused the same way — issue mode needs no trigger to fail on", () => {
|
|
174
|
+
const specs: ScheduledOpSpec[] = [
|
|
175
|
+
{ name: "tf-plan", trigger: { kind: "pull_request", branches: ["main"] }, findingMode: "issue" },
|
|
176
|
+
];
|
|
177
|
+
expect(() => generateForgejoOpPipeline(specs)).toThrow(/findingMode "issue"/);
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
152
181
|
/**
|
|
153
182
|
* #2242 crosses the dialect asymmetrically: Forgejo runs `uses:` steps, so a
|
|
154
183
|
* spec's `setup` list is emitted; it ignores `permissions:`, so an additive
|
|
@@ -225,16 +254,34 @@ describe("generateForgejoOpPipeline: the gated apply on push (#2243)", () => {
|
|
|
225
254
|
* always carries, unconditionally) defaults to `sh`, and `sh` rejects `set
|
|
226
255
|
* -o pipefail`. This generator reuses github's `buildGithubOpPipelineDocs`
|
|
227
256
|
* to build the job, then the dialect transform in ../dialect.ts to cross
|
|
228
|
-
* it, so the fix has to survive both:
|
|
229
|
-
* `shell
|
|
257
|
+
* it, so the fix has to survive both: the exit-code capture is plain POSIX
|
|
258
|
+
* `sh` (chant #2321 — no `shell: bash` to drop or rename in the first
|
|
259
|
+
* place, unlike before #2321, when an unconditional `shell: bash` broke
|
|
260
|
+
* any consumer image without bash — see the sibling test below).
|
|
230
261
|
*/
|
|
231
|
-
test("the
|
|
262
|
+
test("the exit-code capture crosses the Forgejo dialect with no shell override — its job runs in a container, whose default shell is sh", () => {
|
|
232
263
|
const doc = parseFile(generateForgejoOpPipeline([pushSpec]).files[0].yaml);
|
|
233
264
|
const job = doc.jobs!["app-apply"];
|
|
234
265
|
expect(job.container).toBe("node:22-slim");
|
|
235
266
|
const step = job.steps.find((s) => s.id === "chant-run");
|
|
236
|
-
expect(step?.
|
|
237
|
-
expect(step?.
|
|
267
|
+
expect(step?.shell).toBeUndefined();
|
|
268
|
+
expect(step?.run).not.toContain("pipefail");
|
|
269
|
+
expect(step?.run).toContain('[ "$code" -eq 0 ] || exit "$code"');
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* chant #2321 — same regression as the github generator's, since this one
|
|
274
|
+
* reuses `buildGithubOpPipelineDocs` to build the job before crossing the
|
|
275
|
+
* dialect: a consumer's non-bash `options.image` (alpine, distroless, …)
|
|
276
|
+
* must not get an unconditional `shell: bash` it cannot run.
|
|
277
|
+
*/
|
|
278
|
+
test("a consumer-set non-bash image's gated job can still start on Forgejo (#2321)", () => {
|
|
279
|
+
const doc = parseFile(generateForgejoOpPipeline([pushSpec], { image: "alpine:3.20" }).files[0].yaml);
|
|
280
|
+
const job = doc.jobs!["app-apply"];
|
|
281
|
+
expect(job.container).toBe("alpine:3.20");
|
|
282
|
+
const step = job.steps.find((s) => s.id === "chant-run");
|
|
283
|
+
expect(step?.shell).toBeUndefined();
|
|
284
|
+
expect(step?.run).not.toContain("pipefail");
|
|
238
285
|
});
|
|
239
286
|
});
|
|
240
287
|
|
|
@@ -277,7 +324,7 @@ describe("generateForgejoOpPipeline: a dropped deployment environment (#2257)",
|
|
|
277
324
|
|
|
278
325
|
test("a spec with no environment emits the bytes it emitted before the option existed", () => {
|
|
279
326
|
const yaml = generateForgejoOpPipeline([
|
|
280
|
-
{ name: "actions-audit", schedule: "0 6 * * *", findingMode: "
|
|
327
|
+
{ name: "actions-audit", schedule: "0 6 * * *", findingMode: "pull-request" },
|
|
281
328
|
]).files[0].yaml;
|
|
282
329
|
expect(yaml).toBe(AUDIT_YAML_BEFORE_2257);
|
|
283
330
|
});
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
* no mapping in ../actions.ts passes through verbatim and resolves only if
|
|
29
29
|
* the runner can fetch it.
|
|
30
30
|
*
|
|
31
|
-
* `comment` (#2231) crosses over
|
|
31
|
+
* `comment` (#2231) crosses over, since chant #2291: it posts onto the
|
|
32
32
|
* triggering pull request by shelling to `gh` against `${GITHUB_API_URL}`,
|
|
33
33
|
* and a Forgejo Actions job already sets that (and `github.token`) the same
|
|
34
34
|
* way a GitHub Actions job does. This generator used to refuse the mode by
|
|
@@ -38,10 +38,42 @@
|
|
|
38
38
|
* false — the failure was `gh api` resolving a *relative* path against
|
|
39
39
|
* `/api/v3`, which Forgejo does not serve, not an unreachable forge. See
|
|
40
40
|
* `reconcilePr`'s `postOrUpdateComment` (`packages/core/src/op/activities/reconcile.ts`)
|
|
41
|
-
* for the fix.
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
41
|
+
* for the fix.
|
|
42
|
+
*
|
|
43
|
+
* `issue` (`gh issue create`/`postOrUpdateGithubIssue`) does not cross over,
|
|
44
|
+
* and chant #2315 is why: it remained un-refused-but-unverified after #2304
|
|
45
|
+
* lifted `comment`'s refusal, and settling that gap the same way — against a
|
|
46
|
+
* real instance rather than a mock — found a real failure, so the refusal
|
|
47
|
+
* below is reinstated rather than lifted. Tested against the same
|
|
48
|
+
* 12.0.4+gitea-1.22.0 image (`codeberg.org/forgejo/forgejo:12`) with a repo,
|
|
49
|
+
* an issue, and a pull request created on it: the *read* half of
|
|
50
|
+
* `postOrUpdateGithubIssue` checks out fine on Forgejo — plain paginated
|
|
51
|
+
* `GET .../issues?state=open` (no `/search/issues`, confirmed absent from a
|
|
52
|
+
* live Forgejo's own OpenAPI spec) returns pull requests interleaved with
|
|
53
|
+
* issues exactly as GitHub's endpoint does, and the `.pull_request == null`
|
|
54
|
+
* filter and the marker `startswith` match both behave identically to
|
|
55
|
+
* GitHub. The *write* half does not: `postOrUpdateGithubIssue`'s POST and
|
|
56
|
+
* PATCH calls carry only `GH_TOKEN` (in fact, on the `issue` path, not even
|
|
57
|
+
* that — `reconcilePr` hands it `execAsync` with no `env` override at all,
|
|
58
|
+
* chant #2320), and `gh`'s own documented environment variables (`gh help
|
|
59
|
+
* environment`) scope `GH_TOKEN`/`GITHUB_TOKEN` to "github.com or a subdomain
|
|
60
|
+
* of ghe.com" — never a self-hosted Forgejo. A `GH_DEBUG=api` POST against
|
|
61
|
+
* the live instance, with `GH_TOKEN` and `GITHUB_API_URL` set exactly as the
|
|
62
|
+
* generated workflow sets them, sent no `Authorization` header at all and
|
|
63
|
+
* Forgejo answered `{"message":"token is required"}` (HTTP 401); adding
|
|
64
|
+
* `GH_HOST` alongside `GH_TOKEN` made no difference. Only `GH_ENTERPRISE_TOKEN`
|
|
65
|
+
* paired with a matching `GH_HOST` authenticated the same call. Since neither
|
|
66
|
+
* `postOrUpdateGithubIssue` nor its caller sets either, every write this mode
|
|
67
|
+
* makes on Forgejo fails — not a slow search, a 401 on every run. The same
|
|
68
|
+
* shape (`GH_TOKEN` only, no `GH_HOST`/`GH_ENTERPRISE_TOKEN`) is what
|
|
69
|
+
* `postOrUpdateComment`'s writes carry too, which means #2304's "verified
|
|
70
|
+
* against a real Forgejo instance" could not have gone through the generated
|
|
71
|
+
* workflow's own credential path — either that session had a `gh auth login`
|
|
72
|
+
* already stored for the test instance, which a real Actions job's fresh
|
|
73
|
+
* checkout never has, or a different `gh` build was in play. That is
|
|
74
|
+
* `comment` mode's problem to re-verify, not `issue` mode's, and out of
|
|
75
|
+
* scope for chant #2315; flagged here because finding it is what closes that
|
|
76
|
+
* issue's question of whether to lift or reinstate this refusal.
|
|
45
77
|
*
|
|
46
78
|
* A spec's `environment` (#2257) is dropped on the same terms as
|
|
47
79
|
* `permissions:`, and for a stronger reason: Forgejo Actions has no
|
|
@@ -147,6 +179,23 @@ export function generateForgejoOpPipeline(
|
|
|
147
179
|
// in #2291 once a real Forgejo instance showed the forge itself was never
|
|
148
180
|
// the obstacle — see the module doc above.
|
|
149
181
|
|
|
182
|
+
// `findingMode: "issue"` is refused by name here (#2315): unlike `comment`,
|
|
183
|
+
// a real Forgejo instance did not clear it — see the module doc above for
|
|
184
|
+
// the reproduction.
|
|
185
|
+
for (const spec of ops) {
|
|
186
|
+
if (spec.findingMode === "issue") {
|
|
187
|
+
throw new Error(
|
|
188
|
+
`Scheduled Op "${spec.name}" has findingMode "issue", which opens or edits a GitHub-shaped issue by ` +
|
|
189
|
+
`shelling to \`gh\`. Checked against a real Forgejo 12.0.4+gitea-1.22.0 instance (chant #2315): the ` +
|
|
190
|
+
`search this mode does works there, but the POST/PATCH it writes with does not — \`gh\`'s own ` +
|
|
191
|
+
`GH_TOKEN/GITHUB_TOKEN only authenticate a request to github.com or a ghe.com subdomain, never a ` +
|
|
192
|
+
`self-hosted Forgejo, and neither this mode nor its caller sets GH_HOST or GH_ENTERPRISE_TOKEN, so ` +
|
|
193
|
+
`every write fails with Forgejo's "token is required" (HTTP 401). Use findingMode "comment" on a ` +
|
|
194
|
+
`pull_request trigger here, or generate this Op for github.`,
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
150
199
|
// `emitGatedOutputs: false` (#2294): forgejo never carries a gate-notice job
|
|
151
200
|
// (`gatedNoticeDoc` never crosses the dialect, below), so the job outputs
|
|
152
201
|
// and the `node -e` step that populate them would have no reader.
|