@intentius/chant-lexicon-forgejo 0.124.13 → 0.124.15

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.
@@ -0,0 +1,38 @@
1
+ /**
2
+ * The Forgejo dialect of the three generated pipelines (#3765). Each forgejo
3
+ * generator builds github's document and hands it here: action refs and
4
+ * runner labels rewritten ({@link transformWorkflowObject}), `permissions:`
5
+ * dropped (the runner reads none), and a job's `environment:` dropped with a
6
+ * header note naming it, since Forgejo Actions has no environments.
7
+ */
8
+ import type { GithubOpPipelineDoc } from "@intentius/chant-lexicon-github/components/generate-op-pipeline";
9
+ import { type ForgejoDialectOptions } from "../dialect.js";
10
+ /** Apply the Forgejo dialect to one section of a pipeline doc. */
11
+ export declare function forgejoize(value: Record<string, unknown>, dialect: ForgejoDialectOptions): Record<string, unknown>;
12
+ /**
13
+ * Strip each job's `environment:` (#2257). Forgejo Actions has no
14
+ * environments, so the key would read as a deployment gate and hold nothing
15
+ * back. Dropped here rather than in the dialect's own `DROPPED_KEYS`, so it
16
+ * touches the generated pipelines alone and leaves every other document the
17
+ * dialect transforms as it is.
18
+ */
19
+ export declare function withoutEnvironment(jobsDoc: Record<string, unknown>): Record<string, unknown>;
20
+ /** The header of an Op's workflow whose environment gate did not survive the crossing. */
21
+ export declare function droppedEnvironmentHeader(environmentName: string): string[];
22
+ /** The header of an Op waves workflow, naming each wave whose environment was dropped as `wave -> environment`. */
23
+ export declare function droppedWaveEnvironmentsHeader(dropped: readonly string[]): string[];
24
+ /**
25
+ * The token a Forgejo job uses for what the job token cannot do, such as
26
+ * dispatching a workflow: the `CHANT_FORGE_TOKEN` secret, a token with the
27
+ * `write:repository` scope.
28
+ */
29
+ export declare const FORGE_TOKEN_ENV: {
30
+ CHANT_FORGE_TOKEN: string;
31
+ };
32
+ /**
33
+ * A github workflow document under the Forgejo dialect: every section
34
+ * transformed, each job's `environment:` dropped, `permissions:` emptied, and
35
+ * `header` above it when given.
36
+ */
37
+ export declare function forgejoWorkflowDoc(doc: GithubOpPipelineDoc, dialect: ForgejoDialectOptions, header?: string[]): GithubOpPipelineDoc;
38
+ //# sourceMappingURL=ci-jobs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ci-jobs.d.ts","sourceRoot":"","sources":["../../src/components/ci-jobs.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iEAAiE,CAAC;AAC3G,OAAO,EAA2B,KAAK,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAEjF,kEAAkE;AAClE,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,qBAAqB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAElH;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAQ5F;AAED,0FAA0F;AAC1F,wBAAgB,wBAAwB,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,EAAE,CAQ1E;AAED,mHAAmH;AACnH,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAOlF;AAED;;;;GAIG;AACH,eAAO,MAAM,eAAe;IAAK,iBAAiB;CAAqC,CAAC;AAExF;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,mBAAmB,EAAE,OAAO,EAAE,qBAAqB,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,mBAAmB,CAYnI"}
@@ -86,7 +86,7 @@
86
86
  * sibling Op's job receives.
87
87
  */
88
88
  import type { ComponentPipelineOptions, OpPipelineResult, ScheduledOpSpec } from "@intentius/chant/lexicon";
89
- import { type ForgejoDialectOptions } from "../dialect.js";
89
+ import type { ForgejoDialectOptions } from "../dialect.js";
90
90
  /**
91
91
  * Synthesize one `.forgejo/workflows/*.yml` per scheduled Op. Reuses github's
92
92
  * trigger/job structure ({@link buildGithubOpPipelineDocs}) — its `setup`-step
@@ -1 +1 @@
1
- {"version":3,"file":"generate-op-pipeline.d.ts","sourceRoot":"","sources":["../../src/components/generate-op-pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsFG;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,CA6BlB"}
1
+ {"version":3,"file":"generate-op-pipeline.d.ts","sourceRoot":"","sources":["../../src/components/generate-op-pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsFG;AAMH,OAAO,KAAK,EACV,wBAAwB,EACxB,gBAAgB,EAChB,eAAe,EAChB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAGxD;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,eAAe,EAAE,EACtB,OAAO,GAAE,wBAA6B,EACtC,cAAc,GAAE,qBAA0B,GACzC,gBAAgB,CAmBlB"}
@@ -17,7 +17,7 @@
17
17
  */
18
18
  import type { OpWavesSpec } from "@intentius/chant/op/op-waves";
19
19
  import type { OpWavesPipelineOptions, OpWavesPipelineResult } from "@intentius/chant/lexicon";
20
- import { type ForgejoDialectOptions } from "../dialect.js";
20
+ import type { ForgejoDialectOptions } from "../dialect.js";
21
21
  /** Render an Op waves spec as one Forgejo Actions workflow, `<name>.yml`. */
22
22
  export declare function generateForgejoOpWavesPipeline(spec: OpWavesSpec, options: OpWavesPipelineOptions, dialectOptions?: ForgejoDialectOptions): OpWavesPipelineResult;
23
23
  //# sourceMappingURL=generate-op-waves-pipeline.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"generate-op-waves-pipeline.d.ts","sourceRoot":"","sources":["../../src/components/generate-op-waves-pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,KAAK,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAC9F,OAAO,EAA2B,KAAK,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAMjF,6EAA6E;AAC7E,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,sBAAsB,EAC/B,cAAc,GAAE,qBAA0B,GACzC,qBAAqB,CA0DvB"}
1
+ {"version":3,"file":"generate-op-waves-pipeline.d.ts","sourceRoot":"","sources":["../../src/components/generate-op-waves-pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,KAAK,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAC9F,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAGxD,6EAA6E;AAC7E,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,sBAAsB,EAC/B,cAAc,GAAE,qBAA0B,GACzC,qBAAqB,CAgBvB"}
@@ -25,7 +25,7 @@
25
25
  */
26
26
  import type { DriverComponent } from "@intentius/chant/components/driver";
27
27
  import type { ComponentPipelineOptions, ComponentPipelineResult } from "@intentius/chant/lexicon";
28
- import { type ForgejoDialectOptions } from "../dialect.js";
28
+ import type { ForgejoDialectOptions } from "../dialect.js";
29
29
  /**
30
30
  * Synthesize a `.forgejo/workflows/*.yml` pipeline from a set of components.
31
31
  * Reuses github's job/`needs:`/artifact structure ({@link buildGithubPipelineDoc}),
@@ -1 +1 @@
1
- {"version":3,"file":"generate-pipeline.d.ts","sourceRoot":"","sources":["../../src/components/generate-pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAOH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAC1E,OAAO,KAAK,EACV,wBAAwB,EACxB,uBAAuB,EACxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAA2B,KAAK,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAOjF;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,eAAe,EAAE,EAC7B,OAAO,GAAE,wBAA6B,EACtC,cAAc,GAAE,qBAA0B,GACzC,uBAAuB,CAsBzB"}
1
+ {"version":3,"file":"generate-pipeline.d.ts","sourceRoot":"","sources":["../../src/components/generate-pipeline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAOH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAC1E,OAAO,KAAK,EACV,wBAAwB,EACxB,uBAAuB,EACxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAGxD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,eAAe,EAAE,EAC7B,OAAO,GAAE,wBAA6B,EACtC,cAAc,GAAE,qBAA0B,GACzC,uBAAuB,CAsBzB"}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "algorithm": "sha256",
3
3
  "artifacts": {
4
- "manifest.json": "d8319d0917ce1f80b9eb35bc5141f99b2ef6d6be4f473df11dae4f103c956b6f",
4
+ "manifest.json": "ee4a8346762f955023d0dec3fd0db793b88d4a9a47f8343fd70d671bc747261e",
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": "f28d7fb69fb1cfd992496ef41fda0ea5ccd54a29b84ea1c501a44f6a3992c4d5"
11
11
  },
12
- "composite": "4488f3b6018bfd9aff8fa6a9d36832a5a9137f58413efac2ff2a026465f5fd48"
12
+ "composite": "571a078b5d84f95c5d8c19aabee54d82895f4e1fd01f9eec855a0b84b7971bb6"
13
13
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forgejo",
3
- "version": "0.124.13",
3
+ "version": "0.124.15",
4
4
  "chantVersion": ">=0.1.0",
5
5
  "namespace": "Forgejo",
6
6
  "intrinsics": [],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentius/chant-lexicon-forgejo",
3
- "version": "0.124.13",
3
+ "version": "0.124.15",
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.124.13",
58
- "@intentius/chant-lexicon-github": "^0.124.13"
57
+ "@intentius/chant": "^0.124.15",
58
+ "@intentius/chant-lexicon-github": "^0.124.15"
59
59
  },
60
60
  "scripts": {
61
61
  "generate": "tsx src/codegen/generate-cli.ts",
@@ -0,0 +1,80 @@
1
+ /**
2
+ * The Forgejo dialect of the three generated pipelines (#3765). Each forgejo
3
+ * generator builds github's document and hands it here: action refs and
4
+ * runner labels rewritten ({@link transformWorkflowObject}), `permissions:`
5
+ * dropped (the runner reads none), and a job's `environment:` dropped with a
6
+ * header note naming it, since Forgejo Actions has no environments.
7
+ */
8
+
9
+ import { githubSecret } from "@intentius/chant/ci-jobs";
10
+ import type { GithubOpPipelineDoc } from "@intentius/chant-lexicon-github/components/generate-op-pipeline";
11
+ import { transformWorkflowObject, type ForgejoDialectOptions } from "../dialect";
12
+
13
+ /** Apply the Forgejo dialect to one section of a pipeline doc. */
14
+ export function forgejoize(value: Record<string, unknown>, dialect: ForgejoDialectOptions): Record<string, unknown> {
15
+ return transformWorkflowObject(value, dialect).value as Record<string, unknown>;
16
+ }
17
+
18
+ /**
19
+ * Strip each job's `environment:` (#2257). Forgejo Actions has no
20
+ * environments, so the key would read as a deployment gate and hold nothing
21
+ * back. Dropped here rather than in the dialect's own `DROPPED_KEYS`, so it
22
+ * touches the generated pipelines alone and leaves every other document the
23
+ * dialect transforms as it is.
24
+ */
25
+ export function withoutEnvironment(jobsDoc: Record<string, unknown>): Record<string, unknown> {
26
+ return Object.fromEntries(
27
+ Object.entries(jobsDoc).map(([jobName, job]) => {
28
+ if (typeof job !== "object" || job === null || !("environment" in job)) return [jobName, job];
29
+ const { environment: _dropped, ...rest } = job as Record<string, unknown>;
30
+ return [jobName, rest];
31
+ }),
32
+ );
33
+ }
34
+
35
+ /** The header of an Op's workflow whose environment gate did not survive the crossing. */
36
+ export function droppedEnvironmentHeader(environmentName: string): string[] {
37
+ return [
38
+ `# chant dropped \`environment: ${environmentName}\` from this workflow: Forgejo Actions has no`,
39
+ "# environments, so there is no protection rule, required reviewer or wait timer for the key to",
40
+ "# name. This job is not held back by anything on the forge. What still stops the apply is chant's",
41
+ "# own gate: the run records a pending fact on the chant/lifecycle branch and ends, and `chant",
42
+ "# approve <op> <gate>` is what lets the next run through.",
43
+ ];
44
+ }
45
+
46
+ /** The header of an Op waves workflow, naming each wave whose environment was dropped as `wave -> environment`. */
47
+ export function droppedWaveEnvironmentsHeader(dropped: readonly string[]): string[] {
48
+ return [
49
+ `# chant dropped the environment of each of these waves: ${dropped.join(", ")}.`,
50
+ "# Forgejo Actions has no environments, so nothing on the forge holds these jobs.",
51
+ "# Each wave's own chant gate does: it records a pending fact on chant/lifecycle",
52
+ "# and the wave exits 3 until `chant approve` approves its set digest.",
53
+ ];
54
+ }
55
+
56
+ /**
57
+ * The token a Forgejo job uses for what the job token cannot do, such as
58
+ * dispatching a workflow: the `CHANT_FORGE_TOKEN` secret, a token with the
59
+ * `write:repository` scope.
60
+ */
61
+ export const FORGE_TOKEN_ENV = { CHANT_FORGE_TOKEN: githubSecret("CHANT_FORGE_TOKEN") };
62
+
63
+ /**
64
+ * A github workflow document under the Forgejo dialect: every section
65
+ * transformed, each job's `environment:` dropped, `permissions:` emptied, and
66
+ * `header` above it when given.
67
+ */
68
+ export function forgejoWorkflowDoc(doc: GithubOpPipelineDoc, dialect: ForgejoDialectOptions, header?: string[]): GithubOpPipelineDoc {
69
+ return {
70
+ ...(header ? { header } : {}),
71
+ // Forgejo Actions reads `name:` as GitHub does (#2601).
72
+ ...(doc.name ? { name: doc.name } : {}),
73
+ on: forgejoize(doc.on, dialect),
74
+ ...(doc.env ? { env: forgejoize(doc.env, dialect) } : {}),
75
+ concurrency: forgejoize(doc.concurrency, dialect),
76
+ permissions: {},
77
+ jobsDoc: forgejoize(withoutEnvironment(doc.jobsDoc), dialect),
78
+ ...(doc.gatedNoticeDoc ? { gatedNoticeDoc: forgejoize(doc.gatedNoticeDoc, dialect) } : {}),
79
+ };
80
+ }
@@ -89,47 +89,14 @@
89
89
  import {
90
90
  buildGithubOpPipelineDocs,
91
91
  emitOpPipelineYAML,
92
- type GithubOpPipelineDoc,
93
92
  } from "@intentius/chant-lexicon-github/components/generate-op-pipeline";
94
93
  import type {
95
94
  ComponentPipelineOptions,
96
95
  OpPipelineResult,
97
96
  ScheduledOpSpec,
98
97
  } from "@intentius/chant/lexicon";
99
- import { transformWorkflowObject, type ForgejoDialectOptions } from "../dialect";
100
-
101
- /** Apply the Forgejo dialect to one section of a pipeline doc. */
102
- function forgejoize(value: Record<string, unknown>, dialect: ForgejoDialectOptions): Record<string, unknown> {
103
- return transformWorkflowObject(value, dialect).value as Record<string, unknown>;
104
- }
105
-
106
- /**
107
- * Strip the job-level `environment:` github emitted (#2257). Forgejo Actions
108
- * has no environments, so the key would read as a deployment gate and hold
109
- * nothing back. Dropped from the rebuilt doc rather than from the dialect's
110
- * own `DROPPED_KEYS`, so this touches the Op generator alone and leaves every
111
- * other document the dialect transforms exactly as it emits today.
112
- */
113
- function withoutEnvironment(jobsDoc: Record<string, unknown>): Record<string, unknown> {
114
- return Object.fromEntries(
115
- Object.entries(jobsDoc).map(([jobName, job]) => {
116
- if (typeof job !== "object" || job === null || !("environment" in job)) return [jobName, job];
117
- const { environment: _dropped, ...rest } = job as Record<string, unknown>;
118
- return [jobName, rest];
119
- }),
120
- );
121
- }
122
-
123
- /** Say in the generated file which environment gate did not survive the crossing. */
124
- function droppedEnvironmentHeader(environmentName: string): string[] {
125
- return [
126
- `# chant dropped \`environment: ${environmentName}\` from this workflow: Forgejo Actions has no`,
127
- "# environments, so there is no protection rule, required reviewer or wait timer for the key to",
128
- "# name. This job is not held back by anything on the forge. What still stops the apply is chant's",
129
- "# own gate: the run records a pending fact on the chant/lifecycle branch and ends, and `chant",
130
- "# approve <op> <gate>` is what lets the next run through.",
131
- ];
132
- }
98
+ import type { ForgejoDialectOptions } from "../dialect";
99
+ import { droppedEnvironmentHeader, forgejoWorkflowDoc } from "./ci-jobs";
133
100
 
134
101
  /**
135
102
  * Synthesize one `.forgejo/workflows/*.yml` per scheduled Op. Reuses github's
@@ -156,20 +123,10 @@ export function generateForgejoOpPipeline(
156
123
  // read its Op's own `environment` off the input by position.
157
124
  files: files.map(({ name, doc }, index) => {
158
125
  const environment = ops[index].environment;
159
- const forgejoDoc: GithubOpPipelineDoc = {
160
- ...(environment ? { header: droppedEnvironmentHeader(environment.name) } : {}),
161
- // Forgejo Actions reads `name:` as GitHub does (#2601), so the Op's
162
- // name carries over and the Actions list shows it instead of the path.
163
- ...(doc.name ? { name: doc.name } : {}),
164
- on: forgejoize(doc.on, dialectOptions),
165
- ...(doc.env ? { env: forgejoize(doc.env, dialectOptions) } : {}),
166
- concurrency: forgejoize(doc.concurrency, dialectOptions),
167
- permissions: {},
168
- jobsDoc: forgejoize(withoutEnvironment(doc.jobsDoc), dialectOptions),
169
- // The gate-notice job (#3773), dialect applied like the Op's own job.
170
- ...(doc.gatedNoticeDoc ? { gatedNoticeDoc: forgejoize(doc.gatedNoticeDoc, dialectOptions) } : {}),
171
- };
172
- return { name, yaml: emitOpPipelineYAML(forgejoDoc) };
126
+ // The Op's name carries over, and the gate-notice job (#3773) takes the
127
+ // dialect like the Op's own job.
128
+ const header = environment ? droppedEnvironmentHeader(environment.name) : undefined;
129
+ return { name, yaml: emitOpPipelineYAML(forgejoWorkflowDoc(doc, dialectOptions, header)) };
173
130
  }),
174
131
  jobs,
175
132
  };
@@ -17,14 +17,11 @@
17
17
  */
18
18
 
19
19
  import { buildGithubOpWavesDoc } from "@intentius/chant-lexicon-github/components/generate-op-waves-pipeline";
20
- import { emitOpPipelineYAML, type GithubOpPipelineDoc } from "@intentius/chant-lexicon-github/components/generate-op-pipeline";
20
+ import { emitOpPipelineYAML } from "@intentius/chant-lexicon-github/components/generate-op-pipeline";
21
21
  import type { OpWavesSpec } from "@intentius/chant/op/op-waves";
22
22
  import type { OpWavesPipelineOptions, OpWavesPipelineResult } from "@intentius/chant/lexicon";
23
- import { transformWorkflowObject, type ForgejoDialectOptions } from "../dialect";
24
-
25
- function forgejoize(value: Record<string, unknown>, dialect: ForgejoDialectOptions): Record<string, unknown> {
26
- return transformWorkflowObject(value, dialect).value as Record<string, unknown>;
27
- }
23
+ import type { ForgejoDialectOptions } from "../dialect";
24
+ import { droppedWaveEnvironmentsHeader, FORGE_TOKEN_ENV, forgejoWorkflowDoc } from "./ci-jobs";
28
25
 
29
26
  /** Render an Op waves spec as one Forgejo Actions workflow, `<name>.yml`. */
30
27
  export function generateForgejoOpWavesPipeline(
@@ -33,60 +30,18 @@ export function generateForgejoOpWavesPipeline(
33
30
  dialectOptions: ForgejoDialectOptions = {},
34
31
  ): OpWavesPipelineResult {
35
32
  const { doc, jobs, resumeDoc, plansDoc } = buildGithubOpWavesDoc(spec, options);
36
- const jobsDoc = Object.fromEntries(
37
- Object.entries(doc.jobsDoc).map(([name, job]) => {
38
- const { environment: _dropped, ...rest } = job as Record<string, unknown>;
39
- return [name, rest];
40
- }),
41
- );
42
33
  const dropped = spec.waves.filter((w) => w.environment).map((w) => `${w.name} -> ${w.environment!.name}`);
43
- const forgejoDoc: GithubOpPipelineDoc = {
44
- ...(dropped.length > 0
45
- ? {
46
- header: [
47
- `# chant dropped the environment of each of these waves: ${dropped.join(", ")}.`,
48
- "# Forgejo Actions has no environments, so nothing on the forge holds these jobs.",
49
- "# Each wave's own chant gate does: it records a pending fact on chant/lifecycle",
50
- "# and the wave exits 3 until `chant approve` approves its set digest.",
51
- ],
52
- }
53
- : {}),
54
- name: doc.name,
55
- on: forgejoize(doc.on, dialectOptions),
56
- ...(doc.env ? { env: forgejoize(doc.env, dialectOptions) } : {}),
57
- concurrency: forgejoize(doc.concurrency, dialectOptions),
58
- permissions: {},
59
- jobsDoc: forgejoize(jobsDoc, dialectOptions),
60
- };
61
- const files = [{ name: `${spec.name}.yml`, yaml: emitOpPipelineYAML(forgejoDoc) }];
34
+ const header = dropped.length > 0 ? droppedWaveEnvironmentsHeader(dropped) : undefined;
35
+ const files = [{ name: `${spec.name}.yml`, yaml: emitOpPipelineYAML(forgejoWorkflowDoc(doc, dialectOptions, header)) }];
62
36
  if (resumeDoc) {
63
- const resumeJobs = forgejoize(resumeDoc.jobsDoc, dialectOptions) as Record<string, { steps: Array<Record<string, unknown>> }>;
64
- for (const job of Object.values(resumeJobs)) {
65
- for (const step of job.steps) if (step.env) step.env = { CHANT_FORGE_TOKEN: "${{ secrets.CHANT_FORGE_TOKEN }}" };
37
+ // Forgejo has no API to re-run a run, so resume dispatches the workflow
38
+ // again, with a token that may.
39
+ const resume = forgejoWorkflowDoc(resumeDoc, dialectOptions);
40
+ for (const job of Object.values(resume.jobsDoc) as Array<{ steps: Array<Record<string, unknown>> }>) {
41
+ for (const step of job.steps) if (step.env) step.env = { ...FORGE_TOKEN_ENV };
66
42
  }
67
- files.push({
68
- name: `${spec.name}-resume.yml`,
69
- yaml: emitOpPipelineYAML({
70
- name: resumeDoc.name!,
71
- on: forgejoize(resumeDoc.on, dialectOptions),
72
- concurrency: forgejoize(resumeDoc.concurrency, dialectOptions),
73
- permissions: {},
74
- jobsDoc: resumeJobs,
75
- }),
76
- });
77
- }
78
- if (plansDoc) {
79
- files.push({
80
- name: `${spec.name}-plans.yml`,
81
- yaml: emitOpPipelineYAML({
82
- name: plansDoc.name!,
83
- on: forgejoize(plansDoc.on, dialectOptions),
84
- ...(plansDoc.env ? { env: forgejoize(plansDoc.env, dialectOptions) } : {}),
85
- concurrency: forgejoize(plansDoc.concurrency, dialectOptions),
86
- permissions: {},
87
- jobsDoc: forgejoize(plansDoc.jobsDoc, dialectOptions),
88
- }),
89
- });
43
+ files.push({ name: `${spec.name}-resume.yml`, yaml: emitOpPipelineYAML(resume) });
90
44
  }
45
+ if (plansDoc) files.push({ name: `${spec.name}-plans.yml`, yaml: emitOpPipelineYAML(forgejoWorkflowDoc(plansDoc, dialectOptions)) });
91
46
  return { files, jobs };
92
47
  }
@@ -34,12 +34,8 @@ import type {
34
34
  ComponentPipelineOptions,
35
35
  ComponentPipelineResult,
36
36
  } from "@intentius/chant/lexicon";
37
- import { transformWorkflowObject, type ForgejoDialectOptions } from "../dialect";
38
-
39
- /** Apply the Forgejo dialect to one section of the pipeline doc. */
40
- function forgejoize(value: Record<string, unknown>, dialect: ForgejoDialectOptions): Record<string, unknown> {
41
- return transformWorkflowObject(value, dialect).value as Record<string, unknown>;
42
- }
37
+ import type { ForgejoDialectOptions } from "../dialect";
38
+ import { forgejoize } from "./ci-jobs";
43
39
 
44
40
  /**
45
41
  * Synthesize a `.forgejo/workflows/*.yml` pipeline from a set of components.