@intentius/chant-lexicon-forgejo 0.124.57 → 0.124.58
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/integrity.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"algorithm": "sha256",
|
|
3
3
|
"artifacts": {
|
|
4
|
-
"manifest.json": "
|
|
4
|
+
"manifest.json": "b777da2653c844ff4bbc29657ffe48e5e540412f1b6622e40ebe8d3b2f0cccec",
|
|
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": "
|
|
12
|
+
"composite": "25e5d73ecbdcf0cc5b25304bc3aa47baed7872ac3a968ba3ede47fbfac4d96d0"
|
|
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.124.
|
|
3
|
+
"version": "0.124.58",
|
|
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.
|
|
58
|
-
"@intentius/chant-lexicon-github": "^0.124.
|
|
57
|
+
"@intentius/chant": "^0.124.58",
|
|
58
|
+
"@intentius/chant-lexicon-github": "^0.124.58"
|
|
59
59
|
},
|
|
60
60
|
"scripts": {
|
|
61
61
|
"generate": "tsx src/codegen/generate-cli.ts",
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
name: chant-pr-prod
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
push:
|
|
8
|
+
branches:
|
|
9
|
+
- main
|
|
10
|
+
issue_comment:
|
|
11
|
+
types:
|
|
12
|
+
- created
|
|
13
|
+
workflow_dispatch:
|
|
14
|
+
inputs:
|
|
15
|
+
stack:
|
|
16
|
+
description: The stack the action runs on
|
|
17
|
+
required: false
|
|
18
|
+
type: string
|
|
19
|
+
default: ''
|
|
20
|
+
action:
|
|
21
|
+
description: The action to run, by its name
|
|
22
|
+
required: false
|
|
23
|
+
type: string
|
|
24
|
+
default: ''
|
|
25
|
+
|
|
26
|
+
env:
|
|
27
|
+
CHANT_ENV: prod
|
|
28
|
+
|
|
29
|
+
jobs:
|
|
30
|
+
plan:
|
|
31
|
+
if: github.event_name == 'pull_request'
|
|
32
|
+
runs-on: docker
|
|
33
|
+
container: node:22
|
|
34
|
+
outputs:
|
|
35
|
+
report_0: '${{ steps.plan.outputs.report_0 }}'
|
|
36
|
+
report_1: '${{ steps.plan.outputs.report_1 }}'
|
|
37
|
+
report_2: '${{ steps.plan.outputs.report_2 }}'
|
|
38
|
+
report_3: '${{ steps.plan.outputs.report_3 }}'
|
|
39
|
+
steps:
|
|
40
|
+
- name: Check out the change
|
|
41
|
+
env:
|
|
42
|
+
CHANT_CHECKOUT_TOKEN: '${{ github.token }}'
|
|
43
|
+
run: |
|
|
44
|
+
set -eu
|
|
45
|
+
git config --global --add safe.directory "$PWD" 2>/dev/null || true
|
|
46
|
+
[ -d .git ] || git init -q .
|
|
47
|
+
git remote get-url origin >/dev/null 2>&1 || git remote add origin "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY"
|
|
48
|
+
if [ -n "${CHANT_CHECKOUT_TOKEN:-}" ]; then
|
|
49
|
+
chant_auth="$(printf 'x-access-token:%s' "$CHANT_CHECKOUT_TOKEN" | base64 | tr -d '\n')"
|
|
50
|
+
export GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=http.extraheader GIT_CONFIG_VALUE_0="AUTHORIZATION: basic $chant_auth"
|
|
51
|
+
unset chant_auth
|
|
52
|
+
fi
|
|
53
|
+
ref="$GITHUB_REF"
|
|
54
|
+
want="$GITHUB_SHA"
|
|
55
|
+
case "$ref" in
|
|
56
|
+
refs/heads/*) target="refs/remotes/origin/${ref#refs/heads/}" ;;
|
|
57
|
+
refs/tags/*) target="$ref" ;;
|
|
58
|
+
refs/*) target="refs/remotes/${ref#refs/}" ;;
|
|
59
|
+
*) target="refs/remotes/origin/chant-head" ;;
|
|
60
|
+
esac
|
|
61
|
+
if git rev-parse -q --verify HEAD >/dev/null; then git clean -ffdxq; fi
|
|
62
|
+
git -c protocol.version=2 fetch -q --prune --no-recurse-submodules origin '+refs/heads/*:refs/remotes/origin/*' '+refs/tags/*:refs/tags/*' "+$want:$target"
|
|
63
|
+
git -c protocol.version=2 fetch -q --no-tags origin '+refs/heads/chant/lifecycle:refs/heads/chant/lifecycle' 2>/dev/null || true
|
|
64
|
+
case "$ref" in
|
|
65
|
+
refs/heads/*) git checkout -q --force -B "${ref#refs/heads/}" "$target" ;;
|
|
66
|
+
*) git checkout -q --force --detach "$target" ;;
|
|
67
|
+
esac
|
|
68
|
+
- run: |
|
|
69
|
+
if [ -z "${CHANT_NO_FORGE_TOKEN:-}" ] && [ "${0#*/}" != "$0" ] && [ -f "$0" ] && ! { [ "${0##*/}" = sh ] || [ "${0##*/}" = bash ] || [ "${0##*/}" = dash ]; } && command -v env >/dev/null 2>&1 && command -v sh >/dev/null 2>&1; then exec env -u CHANT_FORGE_TOKEN -u CHANT_GITHUB_TOKEN -u CHANT_FORGEJO_TOKEN -u CHANT_GITLAB_TOKEN -u CHANT_CHECKOUT_TOKEN -u GITHUB_TOKEN -u GH_TOKEN -u FORGEJO_TOKEN -u GITEA_TOKEN -u GITLAB_TOKEN -u CI_JOB_TOKEN -u ACTIONS_RUNTIME_TOKEN CHANT_NO_FORGE_TOKEN=1 sh -e "$0"; fi; unset CHANT_FORGE_TOKEN CHANT_GITHUB_TOKEN CHANT_FORGEJO_TOKEN CHANT_GITLAB_TOKEN CHANT_CHECKOUT_TOKEN GITHUB_TOKEN GH_TOKEN FORGEJO_TOKEN GITEA_TOKEN GITLAB_TOKEN CI_JOB_TOKEN ACTIONS_RUNTIME_TOKEN
|
|
70
|
+
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)
|
|
71
|
+
- name: Plan the members this pull request reaches
|
|
72
|
+
id: plan
|
|
73
|
+
env:
|
|
74
|
+
BASE_SHA: '${{ github.event.pull_request.base.sha }}'
|
|
75
|
+
PR_NUMBER: '${{ github.event.pull_request.number }}'
|
|
76
|
+
run: |
|
|
77
|
+
if [ -z "${CHANT_NO_FORGE_TOKEN:-}" ] && [ "${0#*/}" != "$0" ] && [ -f "$0" ] && ! { [ "${0##*/}" = sh ] || [ "${0##*/}" = bash ] || [ "${0##*/}" = dash ]; } && command -v env >/dev/null 2>&1 && command -v sh >/dev/null 2>&1; then exec env -u CHANT_FORGE_TOKEN -u CHANT_GITHUB_TOKEN -u CHANT_FORGEJO_TOKEN -u CHANT_GITLAB_TOKEN -u CHANT_CHECKOUT_TOKEN -u GITHUB_TOKEN -u GH_TOKEN -u FORGEJO_TOKEN -u GITEA_TOKEN -u GITLAB_TOKEN -u CI_JOB_TOKEN -u ACTIONS_RUNTIME_TOKEN CHANT_NO_FORGE_TOKEN=1 sh -e "$0"; fi; unset CHANT_FORGE_TOKEN CHANT_GITHUB_TOKEN CHANT_FORGEJO_TOKEN CHANT_GITLAB_TOKEN CHANT_CHECKOUT_TOKEN GITHUB_TOKEN GH_TOKEN FORGEJO_TOKEN GITEA_TOKEN GITLAB_TOKEN CI_JOB_TOKEN ACTIONS_RUNTIME_TOKEN
|
|
78
|
+
chant_report="$PWD/.chant/pr"
|
|
79
|
+
chant_handover() { node -e 'const fs=require("fs"),p=require("path"),z=require("zlib");const [dir,out]=process.argv.slice(1);const CHUNK=1000000,PARTS=4,NOTE=["pr-plan.json","pr-note.md"];const all={};const walk=(d,r)=>{let n=[];try{n=fs.readdirSync(d).sort()}catch{return}for(const x of n){const f=p.join(d,x),k=r?r+"/"+x:x;let s;try{s=fs.lstatSync(f)}catch{continue}if(s.isDirectory())walk(f,k);else if(s.isFile())all[k]=fs.readFileSync(f).toString("base64")}};walk(dir,"");const pack=(o)=>z.gzipSync(JSON.stringify(o)).toString("base64");let b=pack(all);if(b.length>CHUNK*PARTS){b=pack(Object.fromEntries(Object.entries(all).filter(([k])=>NOTE.includes(k))));if(b.length>CHUNK*PARTS){b=pack({});console.error("chant: the plan report is too large to hand to the note job, even cut to the report and the note; it hands on none of it")}else console.error("chant: the plan report is too large to hand to the note job whole; it hands on pr-plan.json and pr-note.md")}let o="";for(let i=0;i*CHUNK<b.length;i++)o+="report_"+i+"="+b.slice(i*CHUNK,(i+1)*CHUNK)+"\n";fs.appendFileSync(out,o);' "$chant_report" "${GITHUB_OUTPUT:-/dev/null}" || echo "chant: the plan report could not be handed to the note job" >&2; }
|
|
80
|
+
trap chant_handover EXIT
|
|
81
|
+
npx --no-install plywood ci run plan --chant "npx --no-install plywood" --in-place --no-push --base "$BASE_SHA" --pr "$PR_NUMBER" --env prod --gate pr-apply --forge forgejo
|
|
82
|
+
plan-note:
|
|
83
|
+
needs:
|
|
84
|
+
- plan
|
|
85
|
+
if: always() && github.event_name == 'pull_request' && (needs.plan.result == 'success' || needs.plan.result == 'failure')
|
|
86
|
+
runs-on: docker
|
|
87
|
+
container: node:22
|
|
88
|
+
steps:
|
|
89
|
+
- name: Check out the target branch's commit
|
|
90
|
+
uses: https://code.forgejo.org/actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
91
|
+
with:
|
|
92
|
+
ref: '${{ github.event.pull_request.base.sha }}'
|
|
93
|
+
- name: Take the plan report from the plan job
|
|
94
|
+
run: |
|
|
95
|
+
set -u
|
|
96
|
+
node -e 'const fs=require("fs"),p=require("path"),z=require("zlib");const dir=process.argv[1];let b="";for(const l of fs.readFileSync(0,"utf8").split("\n")){if(!l.trim())continue;let s="";try{s=JSON.parse(l)}catch{}if(typeof s==="string")b+=s}if(!b){console.log("chant: the plan job handed on no report");process.exit(0)}let files;try{files=JSON.parse(z.gunzipSync(Buffer.from(b,"base64"),{maxOutputLength:268435456}).toString("utf8"))}catch(e){console.log("chant: the report the plan job handed on does not read: "+e.message);process.exit(0)}if(!files||typeof files!=="object"||Array.isArray(files)){console.log("chant: the report the plan job handed on is not a set of files");process.exit(0)}let n=0;for(const [k,v] of Object.entries(files)){const parts=k.split("/");if(typeof v!=="string"||k.length>1024||parts.some((x)=>!x||x==="."||x===".."||/[\\\x00-\x1f]/.test(x))){console.log("chant: left out "+JSON.stringify(k));continue}try{const f=p.join(dir,...parts);fs.mkdirSync(p.dirname(f),{recursive:true});fs.writeFileSync(f,Buffer.from(v,"base64"));n++}catch(e){console.log("chant: could not write "+JSON.stringify(k)+": "+e.message)}}console.log("chant: took "+n+" report files from the plan job")' .chant/pr <<'END_OF_REPORT'
|
|
97
|
+
${{ toJSON(needs.plan.outputs.report_0) }}
|
|
98
|
+
${{ toJSON(needs.plan.outputs.report_1) }}
|
|
99
|
+
${{ toJSON(needs.plan.outputs.report_2) }}
|
|
100
|
+
${{ toJSON(needs.plan.outputs.report_3) }}
|
|
101
|
+
END_OF_REPORT
|
|
102
|
+
- name: Keep the plan report
|
|
103
|
+
if: always()
|
|
104
|
+
uses: https://code.forgejo.org/actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5 # v3.2.1
|
|
105
|
+
with:
|
|
106
|
+
name: chant-pr-plan
|
|
107
|
+
path: .chant/pr
|
|
108
|
+
if-no-files-found: ignore
|
|
109
|
+
- name: Post the plan note and plywood/plan
|
|
110
|
+
if: always()
|
|
111
|
+
env:
|
|
112
|
+
PR_NUMBER: '${{ github.event.pull_request.number }}'
|
|
113
|
+
HEAD_SHA: '${{ github.sha }}'
|
|
114
|
+
PLAN_RESULT: '${{ needs.plan.result }}'
|
|
115
|
+
GITHUB_TOKEN: '${{ github.token }}'
|
|
116
|
+
run: npx --no-install plywood components pr-post --pr "$PR_NUMBER" --head "$HEAD_SHA" --env prod --output .chant/pr --forge forgejo --result "$PLAN_RESULT"
|
|
117
|
+
action:
|
|
118
|
+
if: (github.event_name == 'workflow_dispatch' && github.event.inputs.action != '') || (github.event_name == 'issue_comment' && startsWith(github.event.comment.body, '/plywood action '))
|
|
119
|
+
runs-on: docker
|
|
120
|
+
container: node:22
|
|
121
|
+
concurrency:
|
|
122
|
+
group: chant-action-prod
|
|
123
|
+
cancel-in-progress: false
|
|
124
|
+
steps:
|
|
125
|
+
- name: Check out the target branch's commit
|
|
126
|
+
uses: https://code.forgejo.org/actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
127
|
+
with:
|
|
128
|
+
fetch-depth: 0
|
|
129
|
+
- 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)
|
|
130
|
+
- name: Run the requested action under its gated request
|
|
131
|
+
env:
|
|
132
|
+
CHANT_ACTION_COMMENT: '${{ github.event.comment.body }}'
|
|
133
|
+
CHANT_ACTION_MEMBER: '${{ github.event.inputs.stack }}'
|
|
134
|
+
CHANT_ACTION: '${{ github.event.inputs.action }}'
|
|
135
|
+
PR_NUMBER: '${{ github.event.issue.number }}'
|
|
136
|
+
GITHUB_TOKEN: '${{ github.token }}'
|
|
137
|
+
run: |
|
|
138
|
+
set +e
|
|
139
|
+
npx --no-install plywood action --from-event
|
|
140
|
+
code="$?"
|
|
141
|
+
if [ "$code" -eq 3 ]; then echo "The action waits for an approval."; exit 0; fi
|
|
142
|
+
exit "$code"
|
|
143
|
+
record:
|
|
144
|
+
if: github.event_name == 'push'
|
|
145
|
+
runs-on: docker
|
|
146
|
+
container: node:22
|
|
147
|
+
concurrency:
|
|
148
|
+
group: chant-record-prod
|
|
149
|
+
cancel-in-progress: false
|
|
150
|
+
steps:
|
|
151
|
+
- uses: https://code.forgejo.org/actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
152
|
+
with:
|
|
153
|
+
fetch-depth: 0
|
|
154
|
+
- 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)
|
|
155
|
+
- name: Record the plan on the merged commit; nothing applies
|
|
156
|
+
env:
|
|
157
|
+
BASE_SHA: '${{ github.event.before }}'
|
|
158
|
+
GITHUB_TOKEN: '${{ github.token }}'
|
|
159
|
+
CHANT_RUNNER_KEY: '${{ secrets.CHANT_RUNNER_KEY }}'
|
|
160
|
+
run: |
|
|
161
|
+
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
|
|
162
|
+
npx --no-install plywood ci run record --chant "npx --no-install plywood" --in-place --base "$BASE_SHA" --env prod --gate pr-apply --forge forgejo
|
|
163
|
+
- name: Keep the record report
|
|
164
|
+
if: always()
|
|
165
|
+
uses: https://code.forgejo.org/actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5 # v3.2.1
|
|
166
|
+
with:
|
|
167
|
+
name: chant-pr-record
|
|
168
|
+
path: .chant/pr
|
|
169
|
+
if-no-files-found: ignore
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** The action job on Forgejo (#4654): the GitHub generator's job, reading Forgejo's payload, with no author check, and the same dispatch inputs. */
|
|
2
|
+
|
|
3
|
+
import { describe, expect, test } from "vitest";
|
|
4
|
+
import { parseYAML } from "@intentius/chant/yaml";
|
|
5
|
+
import type { DriverComponent } from "@intentius/chant/components/driver";
|
|
6
|
+
import { generateForgejoPipeline } from "./generate-pipeline";
|
|
7
|
+
|
|
8
|
+
const ESTATE: DriverComponent[] = [
|
|
9
|
+
{ name: "shop", dependsOn: [], deploy: [{ phase: "Apply", steps: [{ kind: "pulumi-up", stack: "shop/prod-us" }] }] },
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
const WORDS = { product: "plywood", noun: ["stack", "stacks"] as [string, string], commands: { preview: "plan" as const, action: "action" as const }, bin: "npx --no-install plywood" };
|
|
13
|
+
|
|
14
|
+
type Doc = { on: Record<string, { inputs?: Record<string, unknown> }>; jobs: Record<string, { if?: string; steps: Array<{ run?: string }> }> };
|
|
15
|
+
|
|
16
|
+
describe("the Forgejo workflow's action job", () => {
|
|
17
|
+
const yaml = generateForgejoPipeline(ESTATE, { env: "prod", prLoop: { words: WORDS, actionJob: true } }).yaml;
|
|
18
|
+
const doc = parseYAML(yaml) as Doc;
|
|
19
|
+
|
|
20
|
+
test("the dispatch carries the stack and action inputs, and the comment check asks no author", () => {
|
|
21
|
+
expect(Object.keys(doc.on.workflow_dispatch!.inputs!)).toEqual(["stack", "action"]);
|
|
22
|
+
expect(doc.jobs.action!.if).toContain("startsWith(github.event.comment.body, '/plywood action ')");
|
|
23
|
+
expect(doc.jobs.action!.if).not.toContain("author_association");
|
|
24
|
+
expect(doc.jobs.action!.steps.at(-1)!.run).toContain("npx --no-install plywood action --from-event");
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test("golden", async () => {
|
|
28
|
+
await expect(yaml).toMatchFileSnapshot("./__golden__/pr-loop-action.forgejo.yml");
|
|
29
|
+
});
|
|
30
|
+
});
|