@intentius/chant-lexicon-forgejo 0.124.34 → 0.124.35

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "algorithm": "sha256",
3
3
  "artifacts": {
4
- "manifest.json": "b9a3a3ed1bc08c5e4bfe6311c531cf2f2f664ad9639c705adfc319a71f8c70b5",
4
+ "manifest.json": "744c5731711b70aafb4e430afc5129f41da39e8af51e8f3b4fabb2df335f3c6b",
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": "4c57276189ca07ad4cc41532db77033d92535de9e8648b7eb57f689cabe859c1"
12
+ "composite": "26f4073d11a86c32993d764931fb8e7a5079ad4f555d9d55926a1875ca9e6c0e"
13
13
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forgejo",
3
- "version": "0.124.34",
3
+ "version": "0.124.35",
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.34",
3
+ "version": "0.124.35",
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.34",
58
- "@intentius/chant-lexicon-github": "^0.124.34"
57
+ "@intentius/chant": "^0.124.35",
58
+ "@intentius/chant-lexicon-github": "^0.124.35"
59
59
  },
60
60
  "scripts": {
61
61
  "generate": "tsx src/codegen/generate-cli.ts",
@@ -7,6 +7,8 @@ on:
7
7
  push:
8
8
  branches:
9
9
  - main
10
+ tags:
11
+ - ci/green/**
10
12
 
11
13
  env:
12
14
  CHANT_ENV: prod
@@ -39,8 +41,39 @@ jobs:
39
41
  name: chant-pr-plan
40
42
  path: .chant/pr
41
43
  if-no-files-found: ignore
44
+ record:
45
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/heads/')
46
+ runs-on: docker
47
+ container: node:22
48
+ concurrency:
49
+ group: chant-record-prod
50
+ cancel-in-progress: false
51
+ steps:
52
+ - uses: https://code.forgejo.org/actions/checkout@v7
53
+ with:
54
+ fetch-depth: 0
55
+ - run: command -v tofu >/dev/null 2>&1 || (curl -fsSL https://get.opentofu.org/install-opentofu.sh -o /tmp/install-opentofu.sh && sh /tmp/install-opentofu.sh --install-method standalone)
56
+ - name: Build the templates
57
+ run: chant build --env prod
58
+ - name: Lint the project
59
+ run: chant lint
60
+ - name: Record the plan on the merged commit; nothing applies
61
+ env:
62
+ BASE_SHA: '${{ github.event.before }}'
63
+ GITHUB_TOKEN: '${{ github.token }}'
64
+ CHANT_RUNNER_KEY: '${{ secrets.CHANT_RUNNER_KEY }}'
65
+ run: |
66
+ if [ -z "$BASE_SHA" ] || [ "$BASE_SHA" = "0000000000000000000000000000000000000000" ]; then git fetch origin "main" && BASE_SHA="$(git merge-base FETCH_HEAD "$GITHUB_SHA")"; if [ "$BASE_SHA" = "$GITHUB_SHA" ]; then BASE_SHA="$(git rev-parse --verify --quiet "$GITHUB_SHA^" || echo 4b825dc642cb6eb9a060e54bf8d69288fbee4904)"; fi; fi; export BASE_SHA
67
+ chant ci run record --in-place --base "$BASE_SHA" --env prod --gate pr-apply --forge forgejo
68
+ - name: Keep the record report
69
+ if: always()
70
+ uses: https://code.forgejo.org/actions/upload-artifact@v3
71
+ with:
72
+ name: chant-pr-record
73
+ path: .chant/pr
74
+ if-no-files-found: ignore
42
75
  apply:
43
- if: github.event_name == 'push'
76
+ if: startsWith(github.ref, 'refs/tags/ci/green/')
44
77
  runs-on: docker
45
78
  container: node:22
46
79
  concurrency:
@@ -61,14 +94,13 @@ jobs:
61
94
  path: .chant/pr-resume/pr-apply.json
62
95
  key: chant-apply-prod-${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
63
96
  restore-keys: chant-apply-prod-${{ github.sha }}-
64
- - name: Apply the plan a reviewer approved
97
+ - name: Apply the newest green commit under the merged changes' approvals
65
98
  env:
66
- BASE_SHA: '${{ github.event.before }}'
67
99
  GITHUB_TOKEN: '${{ github.token }}'
68
100
  CHANT_RUNNER_KEY: '${{ secrets.CHANT_RUNNER_KEY }}'
69
101
  run: |
70
- if [ -z "$BASE_SHA" ] || [ "$BASE_SHA" = "0000000000000000000000000000000000000000" ]; then git fetch origin "main" && BASE_SHA="$(git merge-base FETCH_HEAD "$GITHUB_SHA")"; if [ "$BASE_SHA" = "$GITHUB_SHA" ]; then BASE_SHA="$(git rev-parse --verify --quiet "$GITHUB_SHA^" || echo 4b825dc642cb6eb9a060e54bf8d69288fbee4904)"; fi; fi; export BASE_SHA
71
- chant ci run apply --in-place --base "$BASE_SHA" --env prod --gate pr-apply --forge forgejo
102
+ git fetch --quiet --tags origin "+refs/heads/main:refs/remotes/origin/main" && GREEN_SHA="$(chant ci last-green)" && git checkout --quiet --detach "$GREEN_SHA"
103
+ chant ci run apply --in-place --env prod --gate pr-apply --forge forgejo
72
104
  - name: Keep the record for a re-run
73
105
  if: always()
74
106
  uses: https://code.forgejo.org/actions/cache/save@v4
@@ -7,6 +7,8 @@ on:
7
7
  push:
8
8
  branches:
9
9
  - main
10
+ tags:
11
+ - ci/green/**
10
12
 
11
13
  env:
12
14
  CHANT_ENV: prod
@@ -35,13 +37,42 @@ jobs:
35
37
  name: chant-pr-plan
36
38
  path: .chant/pr
37
39
  if-no-files-found: ignore
40
+ record:
41
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/heads/')
42
+ runs-on: docker
43
+ container: node:22
44
+ concurrency:
45
+ group: chant-record-prod
46
+ cancel-in-progress: false
47
+ steps:
48
+ - uses: https://code.forgejo.org/actions/checkout@v7
49
+ with:
50
+ fetch-depth: 0
51
+ - run: command -v tofu >/dev/null 2>&1 || (curl -fsSL https://get.opentofu.org/install-opentofu.sh -o /tmp/install-opentofu.sh && sh /tmp/install-opentofu.sh --install-method standalone)
52
+ - name: Record the plan on the merged commit; nothing applies
53
+ env:
54
+ BASE_SHA: '${{ github.event.before }}'
55
+ GITHUB_TOKEN: '${{ github.token }}'
56
+ CHANT_RUNNER_KEY: '${{ secrets.CHANT_RUNNER_KEY }}'
57
+ run: |
58
+ if [ -z "$BASE_SHA" ] || [ "$BASE_SHA" = "0000000000000000000000000000000000000000" ]; then git fetch origin "main" && BASE_SHA="$(git merge-base FETCH_HEAD "$GITHUB_SHA")"; if [ "$BASE_SHA" = "$GITHUB_SHA" ]; then BASE_SHA="$(git rev-parse --verify --quiet "$GITHUB_SHA^" || echo 4b825dc642cb6eb9a060e54bf8d69288fbee4904)"; fi; fi; export BASE_SHA
59
+ chant ci run record --in-place --base "$BASE_SHA" --env prod --gate pr-apply --forge forgejo
60
+ - name: Keep the record report
61
+ if: always()
62
+ uses: https://code.forgejo.org/actions/upload-artifact@v3
63
+ with:
64
+ name: chant-pr-record
65
+ path: .chant/pr
66
+ if-no-files-found: ignore
38
67
  apply-wave-1:
39
- if: github.event_name == 'push'
68
+ if: startsWith(github.ref, 'refs/tags/ci/green/')
40
69
  runs-on: docker
41
70
  container: node:22
42
71
  concurrency:
43
72
  group: chant-apply-prod
44
73
  cancel-in-progress: false
74
+ outputs:
75
+ green-sha: '${{ steps.apply.outputs.green-sha }}'
45
76
  steps:
46
77
  - uses: https://code.forgejo.org/actions/checkout@v7
47
78
  with:
@@ -53,14 +84,15 @@ jobs:
53
84
  path: .chant/pr-resume/pr-apply.json
54
85
  key: chant-apply-prod-${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}-wave-1
55
86
  restore-keys: chant-apply-prod-${{ github.sha }}-
56
- - name: Apply wave 1, under the approval its plan has
87
+ - name: Apply wave 1 of the newest green commit, under the approval its plan has
88
+ id: apply
57
89
  env:
58
- BASE_SHA: '${{ github.event.before }}'
59
90
  GITHUB_TOKEN: '${{ github.token }}'
60
91
  CHANT_RUNNER_KEY: '${{ secrets.CHANT_RUNNER_KEY }}'
61
92
  run: |
62
- if [ -z "$BASE_SHA" ] || [ "$BASE_SHA" = "0000000000000000000000000000000000000000" ]; then git fetch origin "main" && BASE_SHA="$(git merge-base FETCH_HEAD "$GITHUB_SHA")"; if [ "$BASE_SHA" = "$GITHUB_SHA" ]; then BASE_SHA="$(git rev-parse --verify --quiet "$GITHUB_SHA^" || echo 4b825dc642cb6eb9a060e54bf8d69288fbee4904)"; fi; fi; export BASE_SHA
63
- chant ci run apply --in-place --base "$BASE_SHA" --env prod --gate pr-apply --forge forgejo --wave-gate release --wave 1
93
+ git fetch --quiet --tags origin "+refs/heads/main:refs/remotes/origin/main" && GREEN_SHA="$(chant ci last-green)" && git checkout --quiet --detach "$GREEN_SHA"
94
+ echo "green-sha=$GREEN_SHA" >> "$GITHUB_OUTPUT"
95
+ chant ci run apply --in-place --env prod --gate pr-apply --forge forgejo --wave-gate release --wave 1
64
96
  - name: Keep the record for the next wave and a re-run
65
97
  if: always()
66
98
  uses: https://code.forgejo.org/actions/cache/save@v4
@@ -75,7 +107,7 @@ jobs:
75
107
  path: .chant/pr
76
108
  if-no-files-found: ignore
77
109
  apply-wave-2:
78
- if: github.event_name == 'push'
110
+ if: startsWith(github.ref, 'refs/tags/ci/green/')
79
111
  runs-on: docker
80
112
  needs:
81
113
  - apply-wave-1
@@ -83,6 +115,8 @@ jobs:
83
115
  concurrency:
84
116
  group: chant-apply-prod
85
117
  cancel-in-progress: false
118
+ outputs:
119
+ green-sha: '${{ steps.apply.outputs.green-sha }}'
86
120
  steps:
87
121
  - uses: https://code.forgejo.org/actions/checkout@v7
88
122
  with:
@@ -94,14 +128,16 @@ jobs:
94
128
  path: .chant/pr-resume/pr-apply.json
95
129
  key: chant-apply-prod-${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}-wave-2
96
130
  restore-keys: chant-apply-prod-${{ github.sha }}-
97
- - name: Apply wave 2, under the approval its plan has
131
+ - name: Apply wave 2 of the green commit wave 1 took, under the approval its plan has
132
+ id: apply
98
133
  env:
99
- BASE_SHA: '${{ github.event.before }}'
100
134
  GITHUB_TOKEN: '${{ github.token }}'
101
135
  CHANT_RUNNER_KEY: '${{ secrets.CHANT_RUNNER_KEY }}'
136
+ GREEN_SHA: '${{ needs.apply-wave-1.outputs.green-sha }}'
102
137
  run: |
103
- if [ -z "$BASE_SHA" ] || [ "$BASE_SHA" = "0000000000000000000000000000000000000000" ]; then git fetch origin "main" && BASE_SHA="$(git merge-base FETCH_HEAD "$GITHUB_SHA")"; if [ "$BASE_SHA" = "$GITHUB_SHA" ]; then BASE_SHA="$(git rev-parse --verify --quiet "$GITHUB_SHA^" || echo 4b825dc642cb6eb9a060e54bf8d69288fbee4904)"; fi; fi; export BASE_SHA
104
- chant ci run apply --in-place --base "$BASE_SHA" --env prod --gate pr-apply --forge forgejo --wave-gate release --wave 2
138
+ test -n "$GREEN_SHA" && git fetch --quiet --tags origin "+refs/heads/main:refs/remotes/origin/main" && git checkout --quiet --detach "$GREEN_SHA"
139
+ echo "green-sha=$GREEN_SHA" >> "$GITHUB_OUTPUT"
140
+ chant ci run apply --in-place --env prod --gate pr-apply --forge forgejo --wave-gate release --wave 2
105
141
  - name: Keep the record for the next wave and a re-run
106
142
  if: always()
107
143
  uses: https://code.forgejo.org/actions/cache/save@v4
@@ -7,6 +7,8 @@ on:
7
7
  push:
8
8
  branches:
9
9
  - main
10
+ tags:
11
+ - ci/green/**
10
12
 
11
13
  env:
12
14
  CHANT_ENV: prod
@@ -35,8 +37,35 @@ jobs:
35
37
  name: chant-pr-plan
36
38
  path: .chant/pr
37
39
  if-no-files-found: ignore
40
+ record:
41
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/heads/')
42
+ runs-on: docker
43
+ container: node:22
44
+ concurrency:
45
+ group: chant-record-prod
46
+ cancel-in-progress: false
47
+ steps:
48
+ - uses: https://code.forgejo.org/actions/checkout@v7
49
+ with:
50
+ fetch-depth: 0
51
+ - run: command -v tofu >/dev/null 2>&1 || (curl -fsSL https://get.opentofu.org/install-opentofu.sh -o /tmp/install-opentofu.sh && sh /tmp/install-opentofu.sh --install-method standalone)
52
+ - name: Record the plan on the merged commit; nothing applies
53
+ env:
54
+ BASE_SHA: '${{ github.event.before }}'
55
+ GITHUB_TOKEN: '${{ github.token }}'
56
+ CHANT_RUNNER_KEY: '${{ secrets.CHANT_RUNNER_KEY }}'
57
+ run: |
58
+ if [ -z "$BASE_SHA" ] || [ "$BASE_SHA" = "0000000000000000000000000000000000000000" ]; then git fetch origin "main" && BASE_SHA="$(git merge-base FETCH_HEAD "$GITHUB_SHA")"; if [ "$BASE_SHA" = "$GITHUB_SHA" ]; then BASE_SHA="$(git rev-parse --verify --quiet "$GITHUB_SHA^" || echo 4b825dc642cb6eb9a060e54bf8d69288fbee4904)"; fi; fi; export BASE_SHA
59
+ chant ci run record --in-place --base "$BASE_SHA" --env prod --gate pr-apply --forge forgejo
60
+ - name: Keep the record report
61
+ if: always()
62
+ uses: https://code.forgejo.org/actions/upload-artifact@v3
63
+ with:
64
+ name: chant-pr-record
65
+ path: .chant/pr
66
+ if-no-files-found: ignore
38
67
  apply:
39
- if: github.event_name == 'push'
68
+ if: startsWith(github.ref, 'refs/tags/ci/green/')
40
69
  runs-on: docker
41
70
  container: node:22
42
71
  concurrency:
@@ -53,14 +82,13 @@ jobs:
53
82
  path: .chant/pr-resume/pr-apply.json
54
83
  key: chant-apply-prod-${{ github.sha }}-${{ github.run_id }}-${{ github.run_attempt }}
55
84
  restore-keys: chant-apply-prod-${{ github.sha }}-
56
- - name: Apply the plan a reviewer approved
85
+ - name: Apply the newest green commit under the merged changes' approvals
57
86
  env:
58
- BASE_SHA: '${{ github.event.before }}'
59
87
  GITHUB_TOKEN: '${{ github.token }}'
60
88
  CHANT_RUNNER_KEY: '${{ secrets.CHANT_RUNNER_KEY }}'
61
89
  run: |
62
- if [ -z "$BASE_SHA" ] || [ "$BASE_SHA" = "0000000000000000000000000000000000000000" ]; then git fetch origin "main" && BASE_SHA="$(git merge-base FETCH_HEAD "$GITHUB_SHA")"; if [ "$BASE_SHA" = "$GITHUB_SHA" ]; then BASE_SHA="$(git rev-parse --verify --quiet "$GITHUB_SHA^" || echo 4b825dc642cb6eb9a060e54bf8d69288fbee4904)"; fi; fi; export BASE_SHA
63
- chant ci run apply --in-place --base "$BASE_SHA" --env prod --gate pr-apply --forge forgejo
90
+ git fetch --quiet --tags origin "+refs/heads/main:refs/remotes/origin/main" && GREEN_SHA="$(chant ci last-green)" && git checkout --quiet --detach "$GREEN_SHA"
91
+ chant ci run apply --in-place --env prod --gate pr-apply --forge forgejo
64
92
  - name: Keep the record for a re-run
65
93
  if: always()
66
94
  uses: https://code.forgejo.org/actions/cache/save@v4
@@ -14,7 +14,7 @@ import { describe, expect, test } from "vitest";
14
14
  import { parseYAML } from "@intentius/chant/yaml";
15
15
  import type { DriverComponent } from "@intentius/chant/components/driver";
16
16
  import { generateGithubPipeline } from "@intentius/chant-lexicon-github/components/generate-pipeline";
17
- import { githubBaseFallback } from "@intentius/chant/components/pr-pipeline";
17
+ import { githubBaseFallback, greenCheckout } from "@intentius/chant/components/pr-pipeline";
18
18
  import { generateForgejoPipeline } from "./generate-pipeline";
19
19
 
20
20
  const ESTATE: DriverComponent[] = [
@@ -43,7 +43,7 @@ describe("the Forgejo pull-request workflow", () => {
43
43
 
44
44
  test("both jobs run chant ci run with the runner key secret, as on GitHub (#4156)", () => {
45
45
  expect(result.yaml).toContain("chant ci run plan --in-place --no-push");
46
- expect(result.yaml.match(/CHANT_RUNNER_KEY: '\$\{\{ secrets\.CHANT_RUNNER_KEY \}\}'/g)).toHaveLength(2);
46
+ expect(result.yaml.match(/CHANT_RUNNER_KEY: '\$\{\{ secrets\.CHANT_RUNNER_KEY \}\}'/g)).toHaveLength(3);
47
47
  expect(result.yaml).not.toContain("chant components pr-");
48
48
  });
49
49
 
@@ -54,37 +54,47 @@ describe("the Forgejo pull-request workflow", () => {
54
54
  expect(result.yaml).not.toMatch(/^\s*permissions:/m);
55
55
  });
56
56
 
57
- test("a first push's all-zero github.event.before is settled before pr-apply reads it, as on GitHub (#4004)", () => {
57
+ test("a first push's all-zero github.event.before is settled before pr-record reads it, as on GitHub (#4004)", () => {
58
58
  const doc = parseYAML(result.yaml) as { jobs: Record<string, { steps: Array<{ run?: string }> }> };
59
- const apply = doc.jobs.apply!.steps.find((s) => s.run?.includes("ci run apply"))!.run!.trimEnd().split("\n");
60
- expect(apply[0]).toBe(githubBaseFallback());
61
- expect(apply[0]).toContain('git merge-base FETCH_HEAD "$GITHUB_SHA"');
62
- expect(apply[1]).toMatch(/^chant ci run apply --in-place --base "\$BASE_SHA"/);
59
+ const record = doc.jobs.record!.steps.find((s) => s.run?.includes("ci run record"))!.run!.trimEnd().split("\n");
60
+ expect(record[0]).toBe(githubBaseFallback());
61
+ expect(record[0]).toContain('git merge-base FETCH_HEAD "$GITHUB_SHA"');
62
+ expect(record[1]).toMatch(/^chant ci run record --in-place --base "\$BASE_SHA"/);
63
63
  expect(doc.jobs.plan!.steps.find((s) => s.run?.includes("ci run plan"))!.run).not.toContain("0000000000000000000000000000000000000000");
64
64
  });
65
65
 
66
+ test("a pushed ci/green/ tag starts the apply, which checks out the newest green commit; a branch push records (#4168 step 9)", () => {
67
+ // Forgejo Actions has no workflow_run, so the apply follows the tag the tick pushes.
68
+ const doc = parseYAML(result.yaml) as { on: unknown; jobs: Record<string, { if?: string; steps: Array<{ run?: string }> }> };
69
+ expect(doc.on).toEqual({ pull_request: { branches: ["main"] }, push: { branches: ["main"], tags: ["ci/green/**"] } });
70
+ expect(doc.jobs.record!.if).toBe("github.event_name == 'push' && startsWith(github.ref, 'refs/heads/')");
71
+ expect(doc.jobs.apply!.if).toBe("startsWith(github.ref, 'refs/tags/ci/green/')");
72
+ const apply = doc.jobs.apply!.steps.find((s) => s.run?.includes("ci run apply"))!.run!.trimEnd().split("\n");
73
+ expect(apply).toEqual([greenCheckout('"main"'), "chant ci run apply --in-place --env prod --gate pr-apply --forge forgejo"]);
74
+ });
75
+
66
76
  test("events and reportUrl reach Forgejo's jobs as they reach GitHub's (#4007)", () => {
67
77
  const yaml = generateForgejoPipeline(ESTATE, { env: "prod", prLoop: { applyOnMerge: true, events: true, reportUrl: "file:///srv/chant-reports" } }).yaml;
68
- expect(yaml.match(/--forge forgejo --events-json --report-url "file:\/\/\/srv\/chant-reports"/g)).toHaveLength(2);
69
- expect(yaml.match(/CHANT_RUN_EVENTS_DIR: \.chant\/pr\/run-events/g)).toHaveLength(2);
78
+ expect(yaml.match(/--forge forgejo --events-json --report-url "file:\/\/\/srv\/chant-reports"/g)).toHaveLength(3);
79
+ expect(yaml.match(/CHANT_RUN_EVENTS_DIR: \.chant\/pr\/run-events/g)).toHaveLength(3);
70
80
  });
71
81
 
72
82
  test("the apply keeps its resume record in the runner's cache, through the Forgejo mirror of actions/cache (#3543)", () => {
73
83
  expect(result.yaml).toContain("uses: https://code.forgejo.org/actions/cache/restore@v4");
74
84
  expect(result.yaml).toContain("uses: https://code.forgejo.org/actions/cache/save@v4");
75
85
  // ci run's inner pr-apply resumes from it (#4156): the job runs in place, where the cache restored it.
76
- expect(result.yaml).toContain("chant ci run apply --in-place --base");
86
+ expect(result.yaml).toContain("chant ci run apply --in-place --env prod");
77
87
  });
78
88
 
79
89
  test("keeps its reports with upload-artifact v3, the version a Forgejo runner runs, while GitHub keeps v4 (#4008)", () => {
80
90
  // v4 refuses a runner that reads as GitHub Enterprise Server, as Forgejo's does.
81
- expect(result.yaml.match(/uses: https:\/\/code\.forgejo\.org\/actions\/upload-artifact@v3$/gm)).toHaveLength(2);
91
+ expect(result.yaml.match(/uses: https:\/\/code\.forgejo\.org\/actions\/upload-artifact@v3$/gm)).toHaveLength(3);
82
92
  expect(result.yaml).not.toMatch(/(upload|download)-artifact@v4/);
83
93
  // v3 uploads hidden files with no input asking for it, so .chant/pr is still kept.
84
94
  expect(result.yaml).not.toContain("include-hidden-files");
85
95
  expect(result.yaml).toContain("path: .chant/pr");
86
96
  const github = generateGithubPipeline(ESTATE, { env: "prod", prLoop: { applyOnMerge: true } }).yaml;
87
- expect(github.match(/uses: actions\/upload-artifact@v4$/gm)).toHaveLength(2);
97
+ expect(github.match(/uses: actions\/upload-artifact@v4$/gm)).toHaveLength(3);
88
98
  expect(github).toContain("include-hidden-files: true");
89
99
  });
90
100
 
@@ -29,8 +29,28 @@ describe("the Forgejo pull-request workflow with a gate per wave (#4003)", () =>
29
29
  expect(result.yaml).toBe(readFileSync(GOLDEN, "utf-8"));
30
30
  });
31
31
 
32
+ test("wave 1 takes the newest green commit, and each later wave applies the one wave 1 took (#4221)", () => {
33
+ const jobs = doc.jobs as unknown as Record<string, { outputs?: Record<string, string>; steps: Array<{ id?: string; run?: string; env?: Record<string, string> }> }>;
34
+ const waves = Object.keys(jobs).filter((name) => name.startsWith("apply-wave-")).length;
35
+ expect(waves).toBeGreaterThan(1);
36
+ for (let k = 1; k <= waves; k++) {
37
+ const job = jobs[`apply-wave-${k}`]!;
38
+ expect(job.outputs).toEqual({ "green-sha": "${{ steps.apply.outputs.green-sha }}" });
39
+ const step = job.steps.find((s) => s.id === "apply")!;
40
+ expect(step.run).toContain('echo "green-sha=$GREEN_SHA" >> "$GITHUB_OUTPUT"');
41
+ if (k === 1) {
42
+ expect(step.run).toContain('GREEN_SHA="$(chant ci last-green)"');
43
+ expect(step.env?.GREEN_SHA).toBeUndefined();
44
+ } else {
45
+ expect(step.run).not.toContain("chant ci last-green");
46
+ expect(step.run).toContain('test -n "$GREEN_SHA"');
47
+ expect(step.env?.GREEN_SHA).toBe(`\${{ needs.apply-wave-${k - 1}.outputs.green-sha }}`);
48
+ }
49
+ }
50
+ });
51
+
32
52
  test("an apply job per wave on Forgejo's runner, each passing its wave and talking to Forgejo", () => {
33
- expect(Object.keys(doc.jobs)).toEqual(["plan", "apply-wave-1", "apply-wave-2"]);
53
+ expect(Object.keys(doc.jobs)).toEqual(["plan", "record", "apply-wave-1", "apply-wave-2"]);
34
54
  expect(doc.jobs["apply-wave-2"]!.needs).toEqual(["apply-wave-1"]);
35
55
  for (const k of [1, 2]) {
36
56
  const job = doc.jobs[`apply-wave-${k}`]!;