@intentius/chant-lexicon-github 0.0.18
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 +31 -0
- package/dist/manifest.json +15 -0
- package/dist/meta.json +135 -0
- package/dist/rules/deprecated-action-version.ts +49 -0
- package/dist/rules/detect-secrets.ts +53 -0
- package/dist/rules/extract-inline-structs.ts +62 -0
- package/dist/rules/file-job-limit.ts +49 -0
- package/dist/rules/gha006.ts +58 -0
- package/dist/rules/gha009.ts +42 -0
- package/dist/rules/gha011.ts +40 -0
- package/dist/rules/gha017.ts +32 -0
- package/dist/rules/gha018.ts +40 -0
- package/dist/rules/gha019.ts +72 -0
- package/dist/rules/job-timeout.ts +59 -0
- package/dist/rules/missing-recommended-inputs.ts +61 -0
- package/dist/rules/no-hardcoded-secrets.ts +46 -0
- package/dist/rules/no-raw-expressions.ts +51 -0
- package/dist/rules/suggest-cache.ts +71 -0
- package/dist/rules/use-condition-builders.ts +45 -0
- package/dist/rules/use-matrix-builder.ts +44 -0
- package/dist/rules/use-typed-actions.ts +47 -0
- package/dist/rules/validate-concurrency.ts +66 -0
- package/dist/rules/yaml-helpers.ts +129 -0
- package/dist/skills/chant-github.md +29 -0
- package/dist/skills/github-actions-patterns.md +93 -0
- package/dist/types/index.d.ts +358 -0
- package/package.json +33 -0
- package/src/codegen/docs-cli.ts +3 -0
- package/src/codegen/docs.ts +1138 -0
- package/src/codegen/generate-cli.ts +36 -0
- package/src/codegen/generate-lexicon.ts +58 -0
- package/src/codegen/generate-typescript.ts +149 -0
- package/src/codegen/generate.ts +141 -0
- package/src/codegen/naming.ts +57 -0
- package/src/codegen/package.ts +65 -0
- package/src/codegen/parse.ts +700 -0
- package/src/codegen/patches.ts +46 -0
- package/src/composites/cache.ts +25 -0
- package/src/composites/checkout.ts +31 -0
- package/src/composites/composites.test.ts +675 -0
- package/src/composites/deploy-environment.ts +77 -0
- package/src/composites/docker-build.ts +120 -0
- package/src/composites/download-artifact.ts +24 -0
- package/src/composites/go-ci.ts +91 -0
- package/src/composites/index.ts +26 -0
- package/src/composites/node-ci.ts +71 -0
- package/src/composites/node-pipeline.ts +151 -0
- package/src/composites/python-ci.ts +92 -0
- package/src/composites/setup-go.ts +24 -0
- package/src/composites/setup-node.ts +26 -0
- package/src/composites/setup-python.ts +24 -0
- package/src/composites/upload-artifact.ts +27 -0
- package/src/coverage.ts +49 -0
- package/src/expression.test.ts +147 -0
- package/src/expression.ts +214 -0
- package/src/generated/index.d.ts +358 -0
- package/src/generated/index.ts +29 -0
- package/src/generated/lexicon-github.json +135 -0
- package/src/generated/runtime.ts +4 -0
- package/src/import/generator.test.ts +110 -0
- package/src/import/generator.ts +119 -0
- package/src/import/parser.test.ts +98 -0
- package/src/import/parser.ts +73 -0
- package/src/index.ts +53 -0
- package/src/lint/post-synth/gha006.ts +58 -0
- package/src/lint/post-synth/gha009.ts +42 -0
- package/src/lint/post-synth/gha011.ts +40 -0
- package/src/lint/post-synth/gha017.ts +32 -0
- package/src/lint/post-synth/gha018.ts +40 -0
- package/src/lint/post-synth/gha019.ts +72 -0
- package/src/lint/post-synth/post-synth.test.ts +318 -0
- package/src/lint/post-synth/yaml-helpers.ts +129 -0
- package/src/lint/rules/data/deprecated-versions.ts +13 -0
- package/src/lint/rules/data/known-actions.ts +13 -0
- package/src/lint/rules/data/recommended-inputs.ts +10 -0
- package/src/lint/rules/data/secret-patterns.ts +31 -0
- package/src/lint/rules/deprecated-action-version.ts +49 -0
- package/src/lint/rules/detect-secrets.ts +53 -0
- package/src/lint/rules/extract-inline-structs.ts +62 -0
- package/src/lint/rules/file-job-limit.ts +49 -0
- package/src/lint/rules/index.ts +17 -0
- package/src/lint/rules/job-timeout.ts +59 -0
- package/src/lint/rules/missing-recommended-inputs.ts +61 -0
- package/src/lint/rules/no-hardcoded-secrets.ts +46 -0
- package/src/lint/rules/no-raw-expressions.ts +51 -0
- package/src/lint/rules/rules.test.ts +365 -0
- package/src/lint/rules/suggest-cache.ts +71 -0
- package/src/lint/rules/use-condition-builders.ts +45 -0
- package/src/lint/rules/use-matrix-builder.ts +44 -0
- package/src/lint/rules/use-typed-actions.ts +47 -0
- package/src/lint/rules/validate-concurrency.ts +66 -0
- package/src/lsp/completions.test.ts +9 -0
- package/src/lsp/completions.ts +20 -0
- package/src/lsp/hover.test.ts +9 -0
- package/src/lsp/hover.ts +38 -0
- package/src/package-cli.ts +42 -0
- package/src/plugin.test.ts +128 -0
- package/src/plugin.ts +408 -0
- package/src/serializer.test.ts +270 -0
- package/src/serializer.ts +383 -0
- package/src/skills/github-actions-patterns.md +93 -0
- package/src/spec/fetch.ts +55 -0
- package/src/validate-cli.ts +19 -0
- package/src/validate.test.ts +12 -0
- package/src/validate.ts +32 -0
- package/src/variables.ts +44 -0
|
@@ -0,0 +1,1138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Documentation generation for GitHub Actions lexicon.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { dirname, join } from "path";
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
7
|
+
import { docsPipeline, writeDocsSite, type DocsConfig } from "@intentius/chant/codegen/docs";
|
|
8
|
+
|
|
9
|
+
function serviceFromType(resourceType: string): string {
|
|
10
|
+
const parts = resourceType.split("::");
|
|
11
|
+
return parts.length >= 2 ? parts[1] : "Actions";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const overview = `The **GitHub Actions** lexicon provides typed constructors for GitHub Actions
|
|
15
|
+
workflow configuration. It covers workflows, jobs, steps, triggers, strategy,
|
|
16
|
+
permissions, concurrency, and more.
|
|
17
|
+
|
|
18
|
+
Install it with:
|
|
19
|
+
|
|
20
|
+
\`\`\`bash
|
|
21
|
+
npm install --save-dev @intentius/chant-lexicon-github
|
|
22
|
+
\`\`\`
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
{{file:docs-snippets/src/quickstart.ts}}
|
|
27
|
+
|
|
28
|
+
The lexicon provides **2 resources** (Workflow, Job), **13 composites** (Checkout, SetupNode, SetupGo, SetupPython, CacheAction, UploadArtifact, DownloadArtifact, NodeCI, NodePipeline, PythonCI, DockerBuild, DeployEnvironment, GoCI) + **3 presets** (BunPipeline, PnpmPipeline, YarnPipeline), a typed **Expression** system with 24 GitHub and 5 Runner context variables, and **13 lint rules** + **6 post-synth checks**.
|
|
29
|
+
`;
|
|
30
|
+
|
|
31
|
+
const outputFormat = `The GitHub Actions lexicon serializes resources into **\`.github/workflows/*.yml\`** YAML files.
|
|
32
|
+
Keys use kebab-case for job properties and snake_case for trigger event names.
|
|
33
|
+
|
|
34
|
+
## Building
|
|
35
|
+
|
|
36
|
+
Run \`chant build\` to produce workflow YAML from your declarations:
|
|
37
|
+
|
|
38
|
+
\`\`\`bash
|
|
39
|
+
chant build src/ --output .github/workflows/ci.yml
|
|
40
|
+
# Or build all workflow files
|
|
41
|
+
chant build
|
|
42
|
+
\`\`\`
|
|
43
|
+
|
|
44
|
+
The generated file includes:
|
|
45
|
+
|
|
46
|
+
- \`name:\` — workflow display name
|
|
47
|
+
- \`on:\` — trigger events (push, pull_request, schedule, workflow_dispatch, etc.)
|
|
48
|
+
- \`permissions:\` — workflow-level GITHUB_TOKEN permissions
|
|
49
|
+
- \`jobs:\` — job definitions with kebab-case keys
|
|
50
|
+
|
|
51
|
+
## Key conversions
|
|
52
|
+
|
|
53
|
+
| Chant (TypeScript) | YAML output | Rule |
|
|
54
|
+
|--------------------|-------------|------|
|
|
55
|
+
| \`export const buildApp = new Job({...})\` | \`jobs: build-app:\` | Export name → kebab-case job key |
|
|
56
|
+
| \`"runs-on": "ubuntu-latest"\` | \`runs-on: ubuntu-latest\` | Property names match GitHub spec |
|
|
57
|
+
| \`timeoutMinutes: 15\` | \`timeout-minutes: 15\` | camelCase → kebab-case for job properties |
|
|
58
|
+
| \`new Step({ uses: "actions/checkout@v4" })\` | \`- uses: actions/checkout@v4\` | Steps serialize as sequence entries |
|
|
59
|
+
|
|
60
|
+
## Validating locally
|
|
61
|
+
|
|
62
|
+
The output is standard GitHub Actions YAML. Validate locally with \`act\` or push to GitHub:
|
|
63
|
+
|
|
64
|
+
\`\`\`bash
|
|
65
|
+
# Using act for local testing
|
|
66
|
+
act -W .github/workflows/ci.yml
|
|
67
|
+
|
|
68
|
+
# Using GitHub's workflow validation (requires push)
|
|
69
|
+
git add .github/workflows/ci.yml
|
|
70
|
+
git push
|
|
71
|
+
\`\`\`
|
|
72
|
+
|
|
73
|
+
## Compatibility
|
|
74
|
+
|
|
75
|
+
The output is compatible with:
|
|
76
|
+
- GitHub Actions (any GitHub.com or GitHub Enterprise Server)
|
|
77
|
+
- \`act\` local runner
|
|
78
|
+
- VS Code GitHub Actions extension
|
|
79
|
+
- Any tool that processes \`.github/workflows/*.yml\` files`;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Generate documentation for the GitHub Actions lexicon.
|
|
83
|
+
*/
|
|
84
|
+
export async function generateDocs(opts?: { verbose?: boolean }): Promise<void> {
|
|
85
|
+
const pkgDir = dirname(dirname(dirname(fileURLToPath(import.meta.url))));
|
|
86
|
+
|
|
87
|
+
const config: DocsConfig = {
|
|
88
|
+
name: "github",
|
|
89
|
+
displayName: "GitHub Actions",
|
|
90
|
+
description: "Typed constructors for GitHub Actions workflow configuration",
|
|
91
|
+
distDir: join(pkgDir, "dist"),
|
|
92
|
+
outDir: join(pkgDir, "docs"),
|
|
93
|
+
overview,
|
|
94
|
+
outputFormat,
|
|
95
|
+
serviceFromType,
|
|
96
|
+
suppressPages: ["intrinsics", "rules"],
|
|
97
|
+
examplesDir: join(pkgDir, "examples"),
|
|
98
|
+
extraPages: [
|
|
99
|
+
{
|
|
100
|
+
slug: "getting-started",
|
|
101
|
+
title: "Getting Started",
|
|
102
|
+
description: "Step-by-step guide to building your first GitHub Actions workflow with chant",
|
|
103
|
+
content: `## 1. Install
|
|
104
|
+
|
|
105
|
+
\`\`\`bash
|
|
106
|
+
mkdir my-project && cd my-project
|
|
107
|
+
npm init -y
|
|
108
|
+
npm install --save-dev @intentius/chant @intentius/chant-lexicon-github typescript
|
|
109
|
+
\`\`\`
|
|
110
|
+
|
|
111
|
+
## 2. Create your workflow
|
|
112
|
+
|
|
113
|
+
Create \`src/ci.ts\`:
|
|
114
|
+
|
|
115
|
+
{{file:docs-snippets/src/quickstart.ts}}
|
|
116
|
+
|
|
117
|
+
## 3. Build
|
|
118
|
+
|
|
119
|
+
\`\`\`bash
|
|
120
|
+
chant build src/ --output .github/workflows/ci.yml
|
|
121
|
+
\`\`\`
|
|
122
|
+
|
|
123
|
+
This produces \`.github/workflows/ci.yml\`:
|
|
124
|
+
|
|
125
|
+
\`\`\`yaml
|
|
126
|
+
name: CI
|
|
127
|
+
on:
|
|
128
|
+
push:
|
|
129
|
+
branches:
|
|
130
|
+
- main
|
|
131
|
+
pull_request:
|
|
132
|
+
branches:
|
|
133
|
+
- main
|
|
134
|
+
permissions:
|
|
135
|
+
contents: read
|
|
136
|
+
jobs:
|
|
137
|
+
build:
|
|
138
|
+
runs-on: ubuntu-latest
|
|
139
|
+
timeout-minutes: 15
|
|
140
|
+
steps:
|
|
141
|
+
- name: Checkout
|
|
142
|
+
uses: actions/checkout@v4
|
|
143
|
+
- name: Setup Node.js
|
|
144
|
+
uses: actions/setup-node@v4
|
|
145
|
+
with:
|
|
146
|
+
node-version: '22'
|
|
147
|
+
cache: npm
|
|
148
|
+
- name: Install
|
|
149
|
+
run: npm ci
|
|
150
|
+
- name: Build
|
|
151
|
+
run: npm run build
|
|
152
|
+
- name: Test
|
|
153
|
+
run: npm test
|
|
154
|
+
\`\`\`
|
|
155
|
+
|
|
156
|
+
## 4. Lint
|
|
157
|
+
|
|
158
|
+
\`\`\`bash
|
|
159
|
+
chant lint src/
|
|
160
|
+
\`\`\`
|
|
161
|
+
|
|
162
|
+
Lint checks for common issues — missing timeouts, hardcoded secrets, raw expression strings, and more. See the [Lint Rules](/chant/lexicons/github/lint-rules/) page for the full list.
|
|
163
|
+
|
|
164
|
+
## 5. Deploy
|
|
165
|
+
|
|
166
|
+
Commit the generated YAML and push:
|
|
167
|
+
|
|
168
|
+
\`\`\`bash
|
|
169
|
+
git add .github/workflows/ci.yml
|
|
170
|
+
git commit -m "Add CI workflow"
|
|
171
|
+
git push
|
|
172
|
+
\`\`\`
|
|
173
|
+
|
|
174
|
+
GitHub automatically picks up any \`.github/workflows/*.yml\` files and runs them on the configured triggers.
|
|
175
|
+
|
|
176
|
+
## Next steps
|
|
177
|
+
|
|
178
|
+
- [Workflow Concepts](/chant/lexicons/github/workflow-concepts/) — resource types, triggers, permissions
|
|
179
|
+
- [Expressions](/chant/lexicons/github/expressions/) — typed expression system and condition helpers
|
|
180
|
+
- [Composites](/chant/lexicons/github/composites/) — pre-built action wrappers (Checkout, SetupNode, etc.)
|
|
181
|
+
- [Lint Rules](/chant/lexicons/github/lint-rules/) — 13 lint rules and 6 post-synth checks`,
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
slug: "workflow-concepts",
|
|
185
|
+
title: "Workflow Concepts",
|
|
186
|
+
description: "Resource types, triggers, jobs, steps, permissions, and strategy in the GitHub Actions lexicon",
|
|
187
|
+
content: `## Resource types
|
|
188
|
+
|
|
189
|
+
The lexicon provides 2 resource types and several property types:
|
|
190
|
+
|
|
191
|
+
### Resources
|
|
192
|
+
|
|
193
|
+
| Type | Description |
|
|
194
|
+
|------|-------------|
|
|
195
|
+
| \`Workflow\` | Top-level workflow configuration — name, triggers, permissions, concurrency |
|
|
196
|
+
| \`Job\` | A job within a workflow — runs-on, steps, strategy, needs, outputs |
|
|
197
|
+
|
|
198
|
+
### Property types
|
|
199
|
+
|
|
200
|
+
| Type | Used in | Description |
|
|
201
|
+
|------|---------|-------------|
|
|
202
|
+
| \`Step\` | Job | A single step — run command or action usage |
|
|
203
|
+
| \`Strategy\` | Job | Matrix strategy for parallel job execution |
|
|
204
|
+
| \`Permissions\` | Workflow, Job | GITHUB_TOKEN permission scopes |
|
|
205
|
+
| \`Concurrency\` | Workflow, Job | Concurrency group and cancel-in-progress settings |
|
|
206
|
+
| \`PushTrigger\` | Workflow (on) | Push event trigger with branch/tag/path filters |
|
|
207
|
+
| \`PullRequestTrigger\` | Workflow (on) | Pull request event trigger with filters |
|
|
208
|
+
| \`ScheduleTrigger\` | Workflow (on) | Cron-based schedule trigger |
|
|
209
|
+
| \`WorkflowDispatchTrigger\` | Workflow (on) | Manual dispatch with typed inputs |
|
|
210
|
+
| \`Environment\` | Job | Deployment environment with protection rules |
|
|
211
|
+
| \`Output\` | Job | Job output values for downstream jobs |
|
|
212
|
+
|
|
213
|
+
## Triggers
|
|
214
|
+
|
|
215
|
+
Triggers define when a workflow runs. Pass them in the \`on:\` field:
|
|
216
|
+
|
|
217
|
+
\`\`\`typescript
|
|
218
|
+
import { Workflow } from "@intentius/chant-lexicon-github";
|
|
219
|
+
|
|
220
|
+
export const workflow = new Workflow({
|
|
221
|
+
name: "CI",
|
|
222
|
+
on: {
|
|
223
|
+
push: { branches: ["main", "release/*"] },
|
|
224
|
+
pull_request: {
|
|
225
|
+
branches: ["main"],
|
|
226
|
+
types: ["opened", "synchronize"],
|
|
227
|
+
},
|
|
228
|
+
schedule: [{ cron: "0 0 * * 1" }], // Weekly on Monday
|
|
229
|
+
workflow_dispatch: { // Manual trigger
|
|
230
|
+
inputs: {
|
|
231
|
+
environment: {
|
|
232
|
+
description: "Deploy target",
|
|
233
|
+
required: true,
|
|
234
|
+
type: "choice",
|
|
235
|
+
options: ["staging", "production"],
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
});
|
|
241
|
+
\`\`\`
|
|
242
|
+
|
|
243
|
+
## Jobs and steps
|
|
244
|
+
|
|
245
|
+
Each exported \`Job\` becomes a job entry under \`jobs:\`. Steps run sequentially within a job:
|
|
246
|
+
|
|
247
|
+
\`\`\`typescript
|
|
248
|
+
import { Job, Step, Checkout, SetupNode } from "@intentius/chant-lexicon-github";
|
|
249
|
+
|
|
250
|
+
export const test = new Job({
|
|
251
|
+
"runs-on": "ubuntu-latest",
|
|
252
|
+
timeoutMinutes: 10,
|
|
253
|
+
steps: [
|
|
254
|
+
Checkout({}).step,
|
|
255
|
+
SetupNode({ nodeVersion: "22", cache: "npm" }).step,
|
|
256
|
+
new Step({ name: "Install", run: "npm ci" }),
|
|
257
|
+
new Step({ name: "Test", run: "npm test" }),
|
|
258
|
+
],
|
|
259
|
+
});
|
|
260
|
+
\`\`\`
|
|
261
|
+
|
|
262
|
+
Key job properties:
|
|
263
|
+
- \`runs-on\` — **required**. Runner label (\`ubuntu-latest\`, \`macos-latest\`, \`windows-latest\`).
|
|
264
|
+
- \`steps\` — **required**. Array of \`Step\` objects.
|
|
265
|
+
- \`timeoutMinutes\` — maximum job duration (recommended, flagged by GHA014 if missing).
|
|
266
|
+
- \`needs\` — job dependencies for execution ordering.
|
|
267
|
+
- \`if\` — conditional execution using Expressions.
|
|
268
|
+
- \`strategy\` — matrix builds for parallel execution.
|
|
269
|
+
|
|
270
|
+
## Matrix strategy
|
|
271
|
+
|
|
272
|
+
Run a job across multiple configurations:
|
|
273
|
+
|
|
274
|
+
\`\`\`typescript
|
|
275
|
+
import { Job, Step, Checkout, SetupNode } from "@intentius/chant-lexicon-github";
|
|
276
|
+
|
|
277
|
+
export const test = new Job({
|
|
278
|
+
"runs-on": "ubuntu-latest",
|
|
279
|
+
strategy: {
|
|
280
|
+
matrix: {
|
|
281
|
+
"node-version": ["18", "20", "22"],
|
|
282
|
+
os: ["ubuntu-latest", "macos-latest"],
|
|
283
|
+
},
|
|
284
|
+
"fail-fast": false,
|
|
285
|
+
},
|
|
286
|
+
steps: [
|
|
287
|
+
Checkout({}).step,
|
|
288
|
+
SetupNode({ nodeVersion: "\${{ matrix.node-version }}", cache: "npm" }).step,
|
|
289
|
+
new Step({ name: "Test", run: "npm test" }),
|
|
290
|
+
],
|
|
291
|
+
});
|
|
292
|
+
\`\`\`
|
|
293
|
+
|
|
294
|
+
## Permissions
|
|
295
|
+
|
|
296
|
+
Control GITHUB_TOKEN permissions at the workflow or job level:
|
|
297
|
+
|
|
298
|
+
\`\`\`typescript
|
|
299
|
+
import { Workflow, Job, Step } from "@intentius/chant-lexicon-github";
|
|
300
|
+
|
|
301
|
+
// Workflow-level (applies to all jobs)
|
|
302
|
+
export const workflow = new Workflow({
|
|
303
|
+
name: "Release",
|
|
304
|
+
on: { push: { tags: ["v*"] } },
|
|
305
|
+
permissions: {
|
|
306
|
+
contents: "write",
|
|
307
|
+
packages: "write",
|
|
308
|
+
"id-token": "write",
|
|
309
|
+
},
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
// Job-level (overrides workflow permissions for this job)
|
|
313
|
+
export const publish = new Job({
|
|
314
|
+
"runs-on": "ubuntu-latest",
|
|
315
|
+
permissions: { contents: "read", packages: "write" },
|
|
316
|
+
steps: [
|
|
317
|
+
new Step({ name: "Publish", run: "npm publish" }),
|
|
318
|
+
],
|
|
319
|
+
});
|
|
320
|
+
\`\`\`
|
|
321
|
+
|
|
322
|
+
Available permission scopes: \`actions\`, \`checks\`, \`contents\`, \`deployments\`, \`id-token\`, \`issues\`, \`packages\`, \`pages\`, \`pull-requests\`, \`repository-projects\`, \`security-events\`, \`statuses\`. Values: \`"read"\`, \`"write"\`, \`"none"\`.
|
|
323
|
+
|
|
324
|
+
## Concurrency
|
|
325
|
+
|
|
326
|
+
Prevent concurrent runs of the same workflow or job:
|
|
327
|
+
|
|
328
|
+
\`\`\`typescript
|
|
329
|
+
import { Workflow } from "@intentius/chant-lexicon-github";
|
|
330
|
+
|
|
331
|
+
export const workflow = new Workflow({
|
|
332
|
+
name: "Deploy",
|
|
333
|
+
on: { push: { branches: ["main"] } },
|
|
334
|
+
concurrency: {
|
|
335
|
+
group: "deploy-\${{ github.ref }}",
|
|
336
|
+
"cancel-in-progress": true,
|
|
337
|
+
},
|
|
338
|
+
});
|
|
339
|
+
\`\`\`
|
|
340
|
+
|
|
341
|
+
## Job dependencies
|
|
342
|
+
|
|
343
|
+
Use \`needs\` to order jobs and pass outputs between them:
|
|
344
|
+
|
|
345
|
+
\`\`\`typescript
|
|
346
|
+
import { Job, Step } from "@intentius/chant-lexicon-github";
|
|
347
|
+
|
|
348
|
+
export const build = new Job({
|
|
349
|
+
"runs-on": "ubuntu-latest",
|
|
350
|
+
outputs: { version: "\${{ steps.version.outputs.value }}" },
|
|
351
|
+
steps: [
|
|
352
|
+
new Step({
|
|
353
|
+
id: "version",
|
|
354
|
+
name: "Get version",
|
|
355
|
+
run: 'echo "value=$(node -p \\"require(\'./package.json\').version\\")" >> $GITHUB_OUTPUT',
|
|
356
|
+
}),
|
|
357
|
+
],
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
export const deploy = new Job({
|
|
361
|
+
"runs-on": "ubuntu-latest",
|
|
362
|
+
needs: ["build"],
|
|
363
|
+
steps: [
|
|
364
|
+
new Step({
|
|
365
|
+
name: "Deploy",
|
|
366
|
+
run: "echo Deploying version \${{ needs.build.outputs.version }}",
|
|
367
|
+
}),
|
|
368
|
+
],
|
|
369
|
+
});
|
|
370
|
+
\`\`\``,
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
slug: "expressions",
|
|
374
|
+
title: "Expressions",
|
|
375
|
+
description: "Typed expression system, condition helpers, and utility functions for GitHub Actions",
|
|
376
|
+
content: `The Expression system provides type-safe access to GitHub Actions \`\${{ }}\` expressions. Instead of writing raw strings, use the typed helpers for better IDE support and lint coverage.
|
|
377
|
+
|
|
378
|
+
{{file:docs-snippets/src/expressions-usage.ts}}
|
|
379
|
+
|
|
380
|
+
## Expression class
|
|
381
|
+
|
|
382
|
+
The \`Expression\` class wraps a raw expression string and provides operator methods:
|
|
383
|
+
|
|
384
|
+
| Method | Example | Result |
|
|
385
|
+
|--------|---------|--------|
|
|
386
|
+
| \`.and(other)\` | \`github.ref.eq("refs/heads/main").and(isPR)\` | \`\${{ github.ref == 'refs/heads/main' && ... }}\` |
|
|
387
|
+
| \`.or(other)\` | \`isMain.or(isDev)\` | \`\${{ ... \\|\\| ... }}\` |
|
|
388
|
+
| \`.not()\` | \`isPR.not()\` | \`\${{ !(...) }}\` |
|
|
389
|
+
| \`.eq(value)\` | \`github.ref.eq("refs/heads/main")\` | \`\${{ github.ref == 'refs/heads/main' }}\` |
|
|
390
|
+
| \`.ne(value)\` | \`github.eventName.ne("schedule")\` | \`\${{ github.event_name != 'schedule' }}\` |
|
|
391
|
+
|
|
392
|
+
## Context accessors
|
|
393
|
+
|
|
394
|
+
The \`github\` and \`runner\` objects provide typed access to context properties:
|
|
395
|
+
|
|
396
|
+
\`\`\`typescript
|
|
397
|
+
import { github, runner } from "@intentius/chant-lexicon-github";
|
|
398
|
+
|
|
399
|
+
github.ref // ${{ github.ref }}
|
|
400
|
+
github.sha // ${{ github.sha }}
|
|
401
|
+
github.actor // ${{ github.actor }}
|
|
402
|
+
runner.os // ${{ runner.os }}
|
|
403
|
+
runner.arch // ${{ runner.arch }}
|
|
404
|
+
\`\`\`
|
|
405
|
+
|
|
406
|
+
See [Variables](/chant/lexicons/github/variables/) for the full reference table.
|
|
407
|
+
|
|
408
|
+
## Dynamic context accessors
|
|
409
|
+
|
|
410
|
+
Access dynamic context values — secrets, matrix, step outputs, job outputs, inputs, vars, env:
|
|
411
|
+
|
|
412
|
+
\`\`\`typescript
|
|
413
|
+
import { secrets, matrix, steps, needs, inputs, vars, env } from "@intentius/chant-lexicon-github";
|
|
414
|
+
|
|
415
|
+
secrets("NPM_TOKEN") // ${{ secrets.NPM_TOKEN }}
|
|
416
|
+
matrix("node-version") // ${{ matrix.node-version }}
|
|
417
|
+
steps("build").outputs("path") // ${{ steps.build.outputs.path }}
|
|
418
|
+
needs("build").outputs("version") // ${{ needs.build.outputs.version }}
|
|
419
|
+
inputs("environment") // ${{ inputs.environment }}
|
|
420
|
+
vars("API_URL") // ${{ vars.API_URL }}
|
|
421
|
+
env("NODE_ENV") // ${{ env.NODE_ENV }}
|
|
422
|
+
\`\`\`
|
|
423
|
+
|
|
424
|
+
## Condition helpers
|
|
425
|
+
|
|
426
|
+
Status check functions for job and step \`if:\` fields:
|
|
427
|
+
|
|
428
|
+
| Function | Expression | Description |
|
|
429
|
+
|----------|-----------|-------------|
|
|
430
|
+
| \`always()\` | \`\${{ always() }}\` | Always run, regardless of status |
|
|
431
|
+
| \`failure()\` | \`\${{ failure() }}\` | Run only if a previous step failed |
|
|
432
|
+
| \`success()\` | \`\${{ success() }}\` | Run only if all previous steps succeeded (default) |
|
|
433
|
+
| \`cancelled()\` | \`\${{ cancelled() }}\` | Run only if the workflow was cancelled |
|
|
434
|
+
|
|
435
|
+
Use them in \`if:\` conditions:
|
|
436
|
+
|
|
437
|
+
\`\`\`typescript
|
|
438
|
+
import { Job, Step, failure, always } from "@intentius/chant-lexicon-github";
|
|
439
|
+
|
|
440
|
+
export const test = new Job({
|
|
441
|
+
"runs-on": "ubuntu-latest",
|
|
442
|
+
steps: [
|
|
443
|
+
new Step({ name: "Test", run: "npm test" }),
|
|
444
|
+
new Step({
|
|
445
|
+
name: "Upload coverage",
|
|
446
|
+
if: always(),
|
|
447
|
+
run: "npx codecov",
|
|
448
|
+
}),
|
|
449
|
+
new Step({
|
|
450
|
+
name: "Notify failure",
|
|
451
|
+
if: failure(),
|
|
452
|
+
run: "curl -X POST $SLACK_WEBHOOK",
|
|
453
|
+
}),
|
|
454
|
+
],
|
|
455
|
+
});
|
|
456
|
+
\`\`\`
|
|
457
|
+
|
|
458
|
+
## Function helpers
|
|
459
|
+
|
|
460
|
+
Utility functions that produce expression strings:
|
|
461
|
+
|
|
462
|
+
| Function | Example | Expression |
|
|
463
|
+
|----------|---------|-----------|
|
|
464
|
+
| \`contains(haystack, needle)\` | \`contains(github.event, "bug")\` | \`\${{ contains(github.event, 'bug') }}\` |
|
|
465
|
+
| \`startsWith(value, prefix)\` | \`startsWith(github.ref, "refs/tags/")\` | \`\${{ startsWith(github.ref, 'refs/tags/') }}\` |
|
|
466
|
+
| \`toJSON(value)\` | \`toJSON(github.event)\` | \`\${{ toJSON(github.event) }}\` |
|
|
467
|
+
| \`fromJSON(json)\` | \`fromJSON(steps("meta").outputs("matrix"))\` | \`\${{ fromJSON(steps.meta.outputs.matrix) }}\` |
|
|
468
|
+
| \`format(template, ...args)\` | \`format("v{0}.{1}", major, minor)\` | \`\${{ format('v{0}.{1}', ...) }}\` |
|
|
469
|
+
|
|
470
|
+
## Convenience helpers
|
|
471
|
+
|
|
472
|
+
Shorthand functions for common checks:
|
|
473
|
+
|
|
474
|
+
\`\`\`typescript
|
|
475
|
+
import { branch, tag } from "@intentius/chant-lexicon-github";
|
|
476
|
+
|
|
477
|
+
branch("main") // github.ref == 'refs/heads/main'
|
|
478
|
+
tag("v1") // startsWith(github.ref, 'refs/tags/v1')
|
|
479
|
+
\`\`\`
|
|
480
|
+
|
|
481
|
+
These are useful in job \`if:\` conditions:
|
|
482
|
+
|
|
483
|
+
\`\`\`typescript
|
|
484
|
+
import { Job, Step, branch } from "@intentius/chant-lexicon-github";
|
|
485
|
+
|
|
486
|
+
export const deploy = new Job({
|
|
487
|
+
"runs-on": "ubuntu-latest",
|
|
488
|
+
if: branch("main"),
|
|
489
|
+
steps: [
|
|
490
|
+
new Step({ name: "Deploy", run: "npm run deploy" }),
|
|
491
|
+
],
|
|
492
|
+
});
|
|
493
|
+
\`\`\``,
|
|
494
|
+
},
|
|
495
|
+
{
|
|
496
|
+
slug: "variables",
|
|
497
|
+
title: "Variables",
|
|
498
|
+
description: "GitHub and Runner context variable references for GitHub Actions workflows",
|
|
499
|
+
content: `The \`GitHub\` and \`Runner\` objects provide type-safe access to GitHub Actions context variables. These expand to \`\${{ github.* }}\` and \`\${{ runner.* }}\` expressions in the generated YAML.
|
|
500
|
+
|
|
501
|
+
{{file:docs-snippets/src/variables-usage.ts}}
|
|
502
|
+
|
|
503
|
+
## GitHub context
|
|
504
|
+
|
|
505
|
+
| Property | Expression | Description |
|
|
506
|
+
|----------|-----------|-------------|
|
|
507
|
+
| \`GitHub.Ref\` | \`\${{ github.ref }}\` | Full ref (e.g. \`refs/heads/main\`, \`refs/tags/v1.0\`) |
|
|
508
|
+
| \`GitHub.RefName\` | \`\${{ github.ref_name }}\` | Short ref name (e.g. \`main\`, \`v1.0\`) |
|
|
509
|
+
| \`GitHub.RefType\` | \`\${{ github.ref_type }}\` | Ref type: \`branch\` or \`tag\` |
|
|
510
|
+
| \`GitHub.Sha\` | \`\${{ github.sha }}\` | Full commit SHA |
|
|
511
|
+
| \`GitHub.Actor\` | \`\${{ github.actor }}\` | Username that triggered the workflow |
|
|
512
|
+
| \`GitHub.TriggeringActor\` | \`\${{ github.triggering_actor }}\` | Username that triggered the workflow run |
|
|
513
|
+
| \`GitHub.Repository\` | \`\${{ github.repository }}\` | Owner/repo (e.g. \`octocat/hello-world\`) |
|
|
514
|
+
| \`GitHub.RepositoryOwner\` | \`\${{ github.repository_owner }}\` | Repository owner (e.g. \`octocat\`) |
|
|
515
|
+
| \`GitHub.EventName\` | \`\${{ github.event_name }}\` | Triggering event name (\`push\`, \`pull_request\`, etc.) |
|
|
516
|
+
| \`GitHub.Event\` | \`\${{ github.event }}\` | Full event payload object |
|
|
517
|
+
| \`GitHub.RunId\` | \`\${{ github.run_id }}\` | Unique run ID |
|
|
518
|
+
| \`GitHub.RunNumber\` | \`\${{ github.run_number }}\` | Run number for this workflow |
|
|
519
|
+
| \`GitHub.RunAttempt\` | \`\${{ github.run_attempt }}\` | Attempt number for this run |
|
|
520
|
+
| \`GitHub.Workflow\` | \`\${{ github.workflow }}\` | Workflow name |
|
|
521
|
+
| \`GitHub.WorkflowRef\` | \`\${{ github.workflow_ref }}\` | Workflow ref path |
|
|
522
|
+
| \`GitHub.Workspace\` | \`\${{ github.workspace }}\` | Default working directory on the runner |
|
|
523
|
+
| \`GitHub.Token\` | \`\${{ github.token }}\` | Automatically-generated GITHUB_TOKEN |
|
|
524
|
+
| \`GitHub.Job\` | \`\${{ github.job }}\` | Current job ID |
|
|
525
|
+
| \`GitHub.HeadRef\` | \`\${{ github.head_ref }}\` | PR head branch (pull_request events only) |
|
|
526
|
+
| \`GitHub.BaseRef\` | \`\${{ github.base_ref }}\` | PR base branch (pull_request events only) |
|
|
527
|
+
| \`GitHub.ServerUrl\` | \`\${{ github.server_url }}\` | GitHub server URL |
|
|
528
|
+
| \`GitHub.ApiUrl\` | \`\${{ github.api_url }}\` | GitHub API URL |
|
|
529
|
+
| \`GitHub.GraphqlUrl\` | \`\${{ github.graphql_url }}\` | GitHub GraphQL API URL |
|
|
530
|
+
| \`GitHub.Action\` | \`\${{ github.action }}\` | Action name or step ID |
|
|
531
|
+
| \`GitHub.ActionPath\` | \`\${{ github.action_path }}\` | Path where the action is located |
|
|
532
|
+
|
|
533
|
+
## Runner context
|
|
534
|
+
|
|
535
|
+
| Property | Expression | Description |
|
|
536
|
+
|----------|-----------|-------------|
|
|
537
|
+
| \`Runner.Os\` | \`\${{ runner.os }}\` | Runner operating system (\`Linux\`, \`Windows\`, \`macOS\`) |
|
|
538
|
+
| \`Runner.Arch\` | \`\${{ runner.arch }}\` | Runner architecture (\`X86\`, \`X64\`, \`ARM\`, \`ARM64\`) |
|
|
539
|
+
| \`Runner.Name\` | \`\${{ runner.name }}\` | Runner name |
|
|
540
|
+
| \`Runner.Temp\` | \`\${{ runner.temp }}\` | Path to a temporary directory on the runner |
|
|
541
|
+
| \`Runner.ToolCache\` | \`\${{ runner.tool_cache }}\` | Path to the tool cache directory |
|
|
542
|
+
|
|
543
|
+
## Common patterns
|
|
544
|
+
|
|
545
|
+
### Branch checks
|
|
546
|
+
|
|
547
|
+
\`\`\`typescript
|
|
548
|
+
import { Job, Step, GitHub } from "@intentius/chant-lexicon-github";
|
|
549
|
+
import { branch } from "@intentius/chant-lexicon-github";
|
|
550
|
+
|
|
551
|
+
// Deploy only on main
|
|
552
|
+
export const deploy = new Job({
|
|
553
|
+
"runs-on": "ubuntu-latest",
|
|
554
|
+
if: branch("main"),
|
|
555
|
+
steps: [
|
|
556
|
+
new Step({ name: "Deploy", run: "npm run deploy" }),
|
|
557
|
+
],
|
|
558
|
+
});
|
|
559
|
+
\`\`\`
|
|
560
|
+
|
|
561
|
+
### Event filtering
|
|
562
|
+
|
|
563
|
+
\`\`\`typescript
|
|
564
|
+
import { Job, Step, GitHub } from "@intentius/chant-lexicon-github";
|
|
565
|
+
import { github } from "@intentius/chant-lexicon-github";
|
|
566
|
+
|
|
567
|
+
// Skip scheduled runs
|
|
568
|
+
export const test = new Job({
|
|
569
|
+
"runs-on": "ubuntu-latest",
|
|
570
|
+
if: github.eventName.ne("schedule"),
|
|
571
|
+
steps: [
|
|
572
|
+
new Step({ name: "Test", run: "npm test" }),
|
|
573
|
+
],
|
|
574
|
+
});
|
|
575
|
+
\`\`\`
|
|
576
|
+
|
|
577
|
+
### Runner-specific logic
|
|
578
|
+
|
|
579
|
+
\`\`\`typescript
|
|
580
|
+
import { Job, Step, runner } from "@intentius/chant-lexicon-github";
|
|
581
|
+
|
|
582
|
+
export const build = new Job({
|
|
583
|
+
"runs-on": "ubuntu-latest",
|
|
584
|
+
steps: [
|
|
585
|
+
new Step({
|
|
586
|
+
name: "Platform-specific setup",
|
|
587
|
+
if: runner.os.eq("Linux"),
|
|
588
|
+
run: "sudo apt-get update && sudo apt-get install -y jq",
|
|
589
|
+
}),
|
|
590
|
+
new Step({ name: "Build", run: "npm run build" }),
|
|
591
|
+
],
|
|
592
|
+
});
|
|
593
|
+
\`\`\``,
|
|
594
|
+
},
|
|
595
|
+
{
|
|
596
|
+
slug: "composites",
|
|
597
|
+
title: "Composites",
|
|
598
|
+
description: "Pre-built composites — action wrappers, CI pipelines, Docker builds, and deploy environments",
|
|
599
|
+
content: `Composites are pre-built abstractions that produce typed GitHub Actions resources. They range from single-action wrappers to full multi-job workflow pipelines.
|
|
600
|
+
|
|
601
|
+
{{file:docs-snippets/src/composites-usage.ts}}
|
|
602
|
+
|
|
603
|
+
## Checkout
|
|
604
|
+
|
|
605
|
+
Wraps \`actions/checkout@v4\`. Clones the repository.
|
|
606
|
+
|
|
607
|
+
\`\`\`typescript
|
|
608
|
+
import { Checkout } from "@intentius/chant-lexicon-github";
|
|
609
|
+
|
|
610
|
+
Checkout({}).step // Default checkout
|
|
611
|
+
Checkout({ fetchDepth: 0 }).step // Full history
|
|
612
|
+
Checkout({ ref: "develop" }).step // Specific branch
|
|
613
|
+
Checkout({ submodules: "recursive" }).step // With submodules
|
|
614
|
+
\`\`\`
|
|
615
|
+
|
|
616
|
+
**Props:** \`ref?\`, \`repository?\`, \`fetchDepth?\`, \`token?\`, \`submodules?\`, \`sshKey?\`
|
|
617
|
+
|
|
618
|
+
## SetupNode
|
|
619
|
+
|
|
620
|
+
Wraps \`actions/setup-node@v4\`. Installs Node.js with optional dependency caching.
|
|
621
|
+
|
|
622
|
+
\`\`\`typescript
|
|
623
|
+
import { SetupNode } from "@intentius/chant-lexicon-github";
|
|
624
|
+
|
|
625
|
+
SetupNode({ nodeVersion: "22" }).step // Node 22
|
|
626
|
+
SetupNode({ nodeVersion: "22", cache: "npm" }).step // With npm cache
|
|
627
|
+
SetupNode({ nodeVersion: "20", cache: "pnpm" }).step // pnpm cache
|
|
628
|
+
\`\`\`
|
|
629
|
+
|
|
630
|
+
**Props:** \`nodeVersion?\`, \`cache?\` (\`"npm"\` | \`"pnpm"\` | \`"yarn"\`), \`registryUrl?\`
|
|
631
|
+
|
|
632
|
+
## SetupGo
|
|
633
|
+
|
|
634
|
+
Wraps \`actions/setup-go@v5\`. Installs Go.
|
|
635
|
+
|
|
636
|
+
\`\`\`typescript
|
|
637
|
+
import { SetupGo } from "@intentius/chant-lexicon-github";
|
|
638
|
+
|
|
639
|
+
SetupGo({ goVersion: "1.22" }).step
|
|
640
|
+
SetupGo({ goVersion: "stable" }).step
|
|
641
|
+
\`\`\`
|
|
642
|
+
|
|
643
|
+
**Props:** \`goVersion?\`, \`cache?\`
|
|
644
|
+
|
|
645
|
+
## SetupPython
|
|
646
|
+
|
|
647
|
+
Wraps \`actions/setup-python@v5\`. Installs Python.
|
|
648
|
+
|
|
649
|
+
\`\`\`typescript
|
|
650
|
+
import { SetupPython } from "@intentius/chant-lexicon-github";
|
|
651
|
+
|
|
652
|
+
SetupPython({ pythonVersion: "3.12" }).step
|
|
653
|
+
SetupPython({ pythonVersion: "3.12", cache: "pip" }).step
|
|
654
|
+
\`\`\`
|
|
655
|
+
|
|
656
|
+
**Props:** \`pythonVersion?\`, \`cache?\` (\`"pip"\` | \`"pipenv"\` | \`"poetry"\`), \`architecture?\`
|
|
657
|
+
|
|
658
|
+
## CacheAction
|
|
659
|
+
|
|
660
|
+
Wraps \`actions/cache@v4\`. Caches files between workflow runs.
|
|
661
|
+
|
|
662
|
+
\`\`\`typescript
|
|
663
|
+
import { CacheAction } from "@intentius/chant-lexicon-github";
|
|
664
|
+
|
|
665
|
+
CacheAction({
|
|
666
|
+
path: "~/.npm",
|
|
667
|
+
key: "npm-\${{ runner.os }}-\${{ hashFiles('**/package-lock.json') }}",
|
|
668
|
+
restoreKeys: ["npm-\${{ runner.os }}-"],
|
|
669
|
+
}).step
|
|
670
|
+
\`\`\`
|
|
671
|
+
|
|
672
|
+
**Props:** \`path\`, \`key\`, \`restoreKeys?\`
|
|
673
|
+
|
|
674
|
+
## UploadArtifact
|
|
675
|
+
|
|
676
|
+
Wraps \`actions/upload-artifact@v4\`. Uploads files as workflow artifacts.
|
|
677
|
+
|
|
678
|
+
\`\`\`typescript
|
|
679
|
+
import { UploadArtifact } from "@intentius/chant-lexicon-github";
|
|
680
|
+
|
|
681
|
+
UploadArtifact({
|
|
682
|
+
name: "build-output",
|
|
683
|
+
path: "dist/",
|
|
684
|
+
retentionDays: 7,
|
|
685
|
+
}).step
|
|
686
|
+
\`\`\`
|
|
687
|
+
|
|
688
|
+
**Props:** \`name\`, \`path\`, \`retentionDays?\`, \`ifNoFilesFound?\`
|
|
689
|
+
|
|
690
|
+
## DownloadArtifact
|
|
691
|
+
|
|
692
|
+
Wraps \`actions/download-artifact@v4\`. Downloads previously uploaded artifacts.
|
|
693
|
+
|
|
694
|
+
\`\`\`typescript
|
|
695
|
+
import { DownloadArtifact } from "@intentius/chant-lexicon-github";
|
|
696
|
+
|
|
697
|
+
DownloadArtifact({
|
|
698
|
+
name: "build-output",
|
|
699
|
+
path: "dist/",
|
|
700
|
+
}).step
|
|
701
|
+
\`\`\`
|
|
702
|
+
|
|
703
|
+
**Props:** \`name\`, \`path?\`
|
|
704
|
+
|
|
705
|
+
## NodeCI
|
|
706
|
+
|
|
707
|
+
A batteries-included composite that produces a full CI workflow and job. Generates a \`Workflow\` (push + PR on main) and a \`Job\` with checkout, setup-node, install, build, and test steps.
|
|
708
|
+
|
|
709
|
+
\`\`\`typescript
|
|
710
|
+
import { NodeCI } from "@intentius/chant-lexicon-github";
|
|
711
|
+
|
|
712
|
+
// Default: Node 22, npm, "build" + "test" scripts
|
|
713
|
+
const { workflow, job } = NodeCI({});
|
|
714
|
+
|
|
715
|
+
// Customized
|
|
716
|
+
const { workflow: w, job: j } = NodeCI({
|
|
717
|
+
nodeVersion: "20",
|
|
718
|
+
packageManager: "pnpm",
|
|
719
|
+
buildScript: "compile",
|
|
720
|
+
testScript: "test:ci",
|
|
721
|
+
});
|
|
722
|
+
\`\`\`
|
|
723
|
+
|
|
724
|
+
**Props:** \`nodeVersion?\`, \`packageManager?\` (\`"npm"\` | \`"pnpm"\` | \`"yarn"\` | \`"bun"\`), \`buildScript?\`, \`testScript?\`, \`installCommand?\`
|
|
725
|
+
|
|
726
|
+
The returned \`workflow\` and \`job\` can be exported directly:
|
|
727
|
+
|
|
728
|
+
\`\`\`typescript
|
|
729
|
+
const ci = NodeCI({ nodeVersion: "22", packageManager: "npm" });
|
|
730
|
+
export const workflow = ci.workflow;
|
|
731
|
+
export const build = ci.job;
|
|
732
|
+
\`\`\`
|
|
733
|
+
|
|
734
|
+
## NodePipeline
|
|
735
|
+
|
|
736
|
+
A production-grade Node pipeline with separate build and test jobs connected by artifact passing. The build job uploads artifacts; the test job downloads them and runs tests with \`needs: ["build"]\`.
|
|
737
|
+
|
|
738
|
+
\`\`\`typescript
|
|
739
|
+
import { NodePipeline } from "@intentius/chant-lexicon-github";
|
|
740
|
+
|
|
741
|
+
const { workflow, buildJob, testJob } = NodePipeline({
|
|
742
|
+
nodeVersion: "22",
|
|
743
|
+
packageManager: "pnpm",
|
|
744
|
+
buildScript: "build",
|
|
745
|
+
testScript: "test:ci",
|
|
746
|
+
buildArtifactPaths: ["dist/", "lib/"],
|
|
747
|
+
});
|
|
748
|
+
\`\`\`
|
|
749
|
+
|
|
750
|
+
**Props:** \`nodeVersion?\`, \`packageManager?\` (\`"npm"\` | \`"pnpm"\` | \`"yarn"\` | \`"bun"\`), \`buildScript?\`, \`testScript?\`, \`installCommand?\`, \`buildArtifactPaths?\`, \`artifactName?\`, \`artifactRetentionDays?\`, \`runsOn?\`
|
|
751
|
+
|
|
752
|
+
### Presets
|
|
753
|
+
|
|
754
|
+
\`\`\`typescript
|
|
755
|
+
import { BunPipeline, PnpmPipeline, YarnPipeline } from "@intentius/chant-lexicon-github";
|
|
756
|
+
|
|
757
|
+
const bun = BunPipeline({}); // packageManager: "bun", uses oven-sh/setup-bun@v2
|
|
758
|
+
const pnpm = PnpmPipeline({}); // packageManager: "pnpm"
|
|
759
|
+
const yarn = YarnPipeline({}); // packageManager: "yarn"
|
|
760
|
+
\`\`\`
|
|
761
|
+
|
|
762
|
+
## PythonCI
|
|
763
|
+
|
|
764
|
+
Python CI with test and optional lint jobs. Supports pip and Poetry workflows.
|
|
765
|
+
|
|
766
|
+
\`\`\`typescript
|
|
767
|
+
import { PythonCI } from "@intentius/chant-lexicon-github";
|
|
768
|
+
|
|
769
|
+
const { workflow, testJob, lintJob } = PythonCI({
|
|
770
|
+
pythonVersion: "3.12",
|
|
771
|
+
testCommand: "pytest --junitxml=report.xml --cov",
|
|
772
|
+
lintCommand: "ruff check .",
|
|
773
|
+
});
|
|
774
|
+
|
|
775
|
+
// Omit lint job
|
|
776
|
+
const { workflow: w, testJob: t } = PythonCI({ lintCommand: null });
|
|
777
|
+
|
|
778
|
+
// Poetry mode
|
|
779
|
+
const poetry = PythonCI({ usePoetry: true });
|
|
780
|
+
\`\`\`
|
|
781
|
+
|
|
782
|
+
**Props:** \`pythonVersion?\`, \`testCommand?\`, \`lintCommand?\` (null to omit), \`requirementsFile?\`, \`usePoetry?\`, \`runsOn?\`
|
|
783
|
+
|
|
784
|
+
## DockerBuild
|
|
785
|
+
|
|
786
|
+
Docker build and push using official Docker actions (login, setup-buildx, metadata, build-push). Configured for GitHub Container Registry by default.
|
|
787
|
+
|
|
788
|
+
\`\`\`typescript
|
|
789
|
+
import { DockerBuild } from "@intentius/chant-lexicon-github";
|
|
790
|
+
|
|
791
|
+
const { workflow, job } = DockerBuild({
|
|
792
|
+
registry: "ghcr.io",
|
|
793
|
+
imageName: "ghcr.io/my-org/my-app",
|
|
794
|
+
dockerfile: "Dockerfile",
|
|
795
|
+
platforms: ["linux/amd64", "linux/arm64"],
|
|
796
|
+
});
|
|
797
|
+
\`\`\`
|
|
798
|
+
|
|
799
|
+
**Props:** \`tag?\`, \`dockerfile?\`, \`context?\`, \`registry?\`, \`imageName?\`, \`tagLatest?\`, \`buildArgs?\`, \`push?\`, \`platforms?\`, \`runsOn?\`
|
|
800
|
+
|
|
801
|
+
## DeployEnvironment
|
|
802
|
+
|
|
803
|
+
Deploy and cleanup job pair using GitHub Environments with concurrency control.
|
|
804
|
+
|
|
805
|
+
\`\`\`typescript
|
|
806
|
+
import { DeployEnvironment } from "@intentius/chant-lexicon-github";
|
|
807
|
+
|
|
808
|
+
const { deployJob, cleanupJob } = DeployEnvironment({
|
|
809
|
+
name: "staging",
|
|
810
|
+
deployScript: ["npm run build", "npm run deploy"],
|
|
811
|
+
cleanupScript: "npm run teardown",
|
|
812
|
+
url: "https://staging.example.com",
|
|
813
|
+
});
|
|
814
|
+
\`\`\`
|
|
815
|
+
|
|
816
|
+
**Props:** \`name\` (required), \`deployScript\` (required), \`cleanupScript?\`, \`url?\`, \`concurrencyGroup?\`, \`cancelInProgress?\`, \`runsOn?\`
|
|
817
|
+
|
|
818
|
+
## GoCI
|
|
819
|
+
|
|
820
|
+
Go CI with build, test, and optional lint jobs. Uses \`golangci-lint-action\` for linting.
|
|
821
|
+
|
|
822
|
+
\`\`\`typescript
|
|
823
|
+
import { GoCI } from "@intentius/chant-lexicon-github";
|
|
824
|
+
|
|
825
|
+
const { workflow, buildJob, testJob, lintJob } = GoCI({
|
|
826
|
+
goVersion: "1.22",
|
|
827
|
+
buildCommand: "go build ./...",
|
|
828
|
+
testCommand: "go test ./... -v -race",
|
|
829
|
+
});
|
|
830
|
+
|
|
831
|
+
// Without lint
|
|
832
|
+
const noLint = GoCI({ lintCommand: null });
|
|
833
|
+
\`\`\`
|
|
834
|
+
|
|
835
|
+
**Props:** \`goVersion?\`, \`testCommand?\`, \`buildCommand?\`, \`lintCommand?\` (null to omit), \`runsOn?\``,
|
|
836
|
+
},
|
|
837
|
+
{
|
|
838
|
+
slug: "lint-rules",
|
|
839
|
+
title: "Lint Rules",
|
|
840
|
+
description: "Built-in lint rules and post-synth checks for GitHub Actions workflows",
|
|
841
|
+
content: `The GitHub Actions lexicon ships lint rules that run during \`chant lint\` and post-synth checks that validate the serialized YAML after \`chant build\`.
|
|
842
|
+
|
|
843
|
+
## Lint rules
|
|
844
|
+
|
|
845
|
+
Lint rules analyze your TypeScript source code before build.
|
|
846
|
+
|
|
847
|
+
### GHA001 — Use typed action composites
|
|
848
|
+
|
|
849
|
+
**Severity:** warning | **Category:** style
|
|
850
|
+
|
|
851
|
+
Flags raw \`uses:\` strings when a typed composite wrapper is available (e.g. \`actions/checkout@v4\` → \`Checkout({})\`). Typed composites provide better IDE support and catch configuration errors at compile time.
|
|
852
|
+
|
|
853
|
+
### GHA002 — Use Expression helpers
|
|
854
|
+
|
|
855
|
+
**Severity:** warning | **Category:** style
|
|
856
|
+
|
|
857
|
+
Flags raw \`\${{ }}\` strings in \`if:\` conditions. Use the typed Expression helpers (\`github.ref.eq(...)\`, \`branch("main")\`, \`failure()\`) instead for type safety and lint coverage.
|
|
858
|
+
|
|
859
|
+
### GHA003 — No hardcoded secrets
|
|
860
|
+
|
|
861
|
+
**Severity:** error | **Category:** security
|
|
862
|
+
|
|
863
|
+
Flags hardcoded GitHub tokens, AWS keys, and other secret patterns in source code. Use \`secrets("...")\` expressions instead.
|
|
864
|
+
|
|
865
|
+
{{file:docs-snippets/src/lint-gha003.ts}}
|
|
866
|
+
|
|
867
|
+
### GHA004 — Extract inline matrix
|
|
868
|
+
|
|
869
|
+
**Severity:** info | **Category:** style
|
|
870
|
+
|
|
871
|
+
Flags inline matrix objects and suggests extracting them to named constants for readability.
|
|
872
|
+
|
|
873
|
+
### GHA005 — Extract deeply nested objects
|
|
874
|
+
|
|
875
|
+
**Severity:** info | **Category:** style
|
|
876
|
+
|
|
877
|
+
Flags deeply nested inline objects and suggests extracting them to named constants.
|
|
878
|
+
|
|
879
|
+
### GHA007 — Too many jobs per file
|
|
880
|
+
|
|
881
|
+
**Severity:** warning | **Category:** style
|
|
882
|
+
|
|
883
|
+
Flags files with more than 10 job exports. Split large workflows into separate files for maintainability.
|
|
884
|
+
|
|
885
|
+
### GHA008 — Avoid raw expression strings
|
|
886
|
+
|
|
887
|
+
**Severity:** info | **Category:** style
|
|
888
|
+
|
|
889
|
+
Flags raw \`\${{ }}\` expression strings outside of \`if:\` fields. Use the typed expression helpers (\`github.*\`, \`secrets()\`, \`matrix()\`) for better type safety.
|
|
890
|
+
|
|
891
|
+
### GHA010 — Setup action missing version
|
|
892
|
+
|
|
893
|
+
**Severity:** warning | **Category:** correctness
|
|
894
|
+
|
|
895
|
+
Flags setup action composites (SetupNode, SetupGo, SetupPython) without a version input. Pinning the version ensures reproducible builds.
|
|
896
|
+
|
|
897
|
+
### GHA012 — Deprecated action version
|
|
898
|
+
|
|
899
|
+
**Severity:** warning | **Category:** correctness
|
|
900
|
+
|
|
901
|
+
Flags action \`uses:\` references that point to deprecated versions. Upgrade to the recommended version.
|
|
902
|
+
|
|
903
|
+
### GHA014 — Missing timeout
|
|
904
|
+
|
|
905
|
+
**Severity:** warning | **Category:** correctness
|
|
906
|
+
|
|
907
|
+
Flags jobs without \`timeoutMinutes\`. Jobs without a timeout default to 360 minutes (6 hours), which can waste runner minutes if stuck.
|
|
908
|
+
|
|
909
|
+
### GHA015 — Setup without cache
|
|
910
|
+
|
|
911
|
+
**Severity:** warning | **Category:** performance
|
|
912
|
+
|
|
913
|
+
Flags setup action composites (SetupNode, SetupGo, SetupPython) without a paired \`CacheAction\` or built-in \`cache\` option. Caching dependencies significantly speeds up builds.
|
|
914
|
+
|
|
915
|
+
### GHA016 — Concurrency missing group
|
|
916
|
+
|
|
917
|
+
**Severity:** warning | **Category:** correctness
|
|
918
|
+
|
|
919
|
+
Flags \`concurrency\` with \`cancel-in-progress: true\` but no \`group\` specified. Without a group, all runs of the workflow share a single concurrency slot.
|
|
920
|
+
|
|
921
|
+
### GHA020 — Potential secret detected
|
|
922
|
+
|
|
923
|
+
**Severity:** error | **Category:** security
|
|
924
|
+
|
|
925
|
+
Flags string literals that match common secret patterns (API keys, tokens, passwords). Use \`secrets()\` or environment variables instead.
|
|
926
|
+
|
|
927
|
+
## Post-synth checks
|
|
928
|
+
|
|
929
|
+
Post-synth checks run against the serialized YAML after build. They catch issues only visible in the final output.
|
|
930
|
+
|
|
931
|
+
### GHA006 — Duplicate workflow names
|
|
932
|
+
|
|
933
|
+
**Severity:** error
|
|
934
|
+
|
|
935
|
+
Flags multiple workflows that share the same \`name:\` value. Duplicate names cause confusion in the GitHub Actions UI.
|
|
936
|
+
|
|
937
|
+
### GHA009 — Empty matrix dimension
|
|
938
|
+
|
|
939
|
+
**Severity:** error
|
|
940
|
+
|
|
941
|
+
Flags matrix strategy dimensions with an empty values array. An empty dimension causes the job to be skipped entirely.
|
|
942
|
+
|
|
943
|
+
### GHA011 — Invalid needs target
|
|
944
|
+
|
|
945
|
+
**Severity:** error
|
|
946
|
+
|
|
947
|
+
Flags jobs whose \`needs:\` entries reference a job not defined in the workflow. This causes a workflow validation error on GitHub.
|
|
948
|
+
|
|
949
|
+
### GHA017 — Missing permissions block
|
|
950
|
+
|
|
951
|
+
**Severity:** info
|
|
952
|
+
|
|
953
|
+
Flags workflows without an explicit \`permissions:\` block. Omitting permissions uses the repository default (often overly broad). Following least-privilege by declaring explicit permissions is a security best practice.
|
|
954
|
+
|
|
955
|
+
### GHA018 — pull_request_target with checkout
|
|
956
|
+
|
|
957
|
+
**Severity:** warning
|
|
958
|
+
|
|
959
|
+
Flags workflows triggered by \`pull_request_target\` that include \`actions/checkout\`. This combination can be a security risk because the workflow runs with write permissions in the context of the base branch while checking out potentially untrusted PR code.
|
|
960
|
+
|
|
961
|
+
### GHA019 — Circular needs chain
|
|
962
|
+
|
|
963
|
+
**Severity:** error
|
|
964
|
+
|
|
965
|
+
Detects cycles in the \`needs:\` dependency graph. If job A needs B and B needs A (directly or transitively), GitHub rejects the workflow. Reports the full cycle chain in the diagnostic message.
|
|
966
|
+
|
|
967
|
+
## Running lint
|
|
968
|
+
|
|
969
|
+
\`\`\`bash
|
|
970
|
+
# Lint your chant project
|
|
971
|
+
chant lint src/
|
|
972
|
+
|
|
973
|
+
# Lint with auto-fix where supported
|
|
974
|
+
chant lint --fix src/
|
|
975
|
+
\`\`\`
|
|
976
|
+
|
|
977
|
+
To suppress a rule on a specific line:
|
|
978
|
+
|
|
979
|
+
\`\`\`typescript
|
|
980
|
+
// chant-disable-next-line GHA001
|
|
981
|
+
new Step({ uses: "actions/checkout@v4" });
|
|
982
|
+
\`\`\`
|
|
983
|
+
|
|
984
|
+
To suppress globally in \`chant.config.ts\`:
|
|
985
|
+
|
|
986
|
+
\`\`\`typescript
|
|
987
|
+
export default {
|
|
988
|
+
lint: {
|
|
989
|
+
rules: {
|
|
990
|
+
GHA014: "off",
|
|
991
|
+
},
|
|
992
|
+
},
|
|
993
|
+
};
|
|
994
|
+
\`\`\``,
|
|
995
|
+
},
|
|
996
|
+
{
|
|
997
|
+
slug: "examples",
|
|
998
|
+
title: "Examples",
|
|
999
|
+
description: "Walkthrough of GitHub Actions examples — workflows, composites, and patterns",
|
|
1000
|
+
content: `Runnable examples live in the lexicon's \`examples/\` directory. Clone the repo and try them:
|
|
1001
|
+
|
|
1002
|
+
\`\`\`bash
|
|
1003
|
+
cd examples/getting-started
|
|
1004
|
+
bun install
|
|
1005
|
+
chant build # produces .github/workflows/ci.yml
|
|
1006
|
+
chant lint # runs lint rules
|
|
1007
|
+
bun test # runs the example's tests
|
|
1008
|
+
\`\`\`
|
|
1009
|
+
|
|
1010
|
+
## Getting Started
|
|
1011
|
+
|
|
1012
|
+
\`examples/getting-started/\` — a CI workflow with build and test steps for a Node.js project.
|
|
1013
|
+
|
|
1014
|
+
\`\`\`
|
|
1015
|
+
src/
|
|
1016
|
+
└── ci.ts # Workflow + Job definitions
|
|
1017
|
+
\`\`\`
|
|
1018
|
+
|
|
1019
|
+
### Source
|
|
1020
|
+
|
|
1021
|
+
{{file:getting-started/src/ci.ts}}
|
|
1022
|
+
|
|
1023
|
+
### Generated output
|
|
1024
|
+
|
|
1025
|
+
\`chant build\` produces \`.github/workflows/ci.yml\`:
|
|
1026
|
+
|
|
1027
|
+
\`\`\`yaml
|
|
1028
|
+
name: CI
|
|
1029
|
+
on:
|
|
1030
|
+
push:
|
|
1031
|
+
branches:
|
|
1032
|
+
- main
|
|
1033
|
+
pull_request:
|
|
1034
|
+
branches:
|
|
1035
|
+
- main
|
|
1036
|
+
permissions:
|
|
1037
|
+
contents: read
|
|
1038
|
+
jobs:
|
|
1039
|
+
build:
|
|
1040
|
+
runs-on: ubuntu-latest
|
|
1041
|
+
timeout-minutes: 15
|
|
1042
|
+
steps:
|
|
1043
|
+
- name: Checkout
|
|
1044
|
+
uses: actions/checkout@v4
|
|
1045
|
+
- name: Setup Node.js
|
|
1046
|
+
uses: actions/setup-node@v4
|
|
1047
|
+
with:
|
|
1048
|
+
node-version: '22'
|
|
1049
|
+
cache: npm
|
|
1050
|
+
- name: Install
|
|
1051
|
+
run: npm ci
|
|
1052
|
+
- name: Build
|
|
1053
|
+
run: npm run build
|
|
1054
|
+
- name: Test
|
|
1055
|
+
run: npm test
|
|
1056
|
+
\`\`\`
|
|
1057
|
+
|
|
1058
|
+
**Patterns demonstrated:**
|
|
1059
|
+
|
|
1060
|
+
1. **Typed composites** — \`Checkout({})\` and \`SetupNode({...})\` instead of raw \`uses:\` strings
|
|
1061
|
+
2. **Permissions** — explicit \`contents: read\` following least-privilege
|
|
1062
|
+
3. **Timeout** — \`timeoutMinutes: 15\` prevents runaway jobs
|
|
1063
|
+
4. **Trigger scoping** — push and PR on \`main\` only`,
|
|
1064
|
+
},
|
|
1065
|
+
{
|
|
1066
|
+
slug: "skills",
|
|
1067
|
+
title: "AI Skills",
|
|
1068
|
+
description: "AI agent skills bundled with the GitHub Actions lexicon",
|
|
1069
|
+
content: `The GitHub Actions lexicon ships AI skills that teach AI coding agents (like Claude Code) how to build, validate, and deploy GitHub Actions workflows from a chant project.
|
|
1070
|
+
|
|
1071
|
+
## What are skills?
|
|
1072
|
+
|
|
1073
|
+
Skills are structured markdown documents bundled with a lexicon. When an AI agent works in a chant project, it discovers and loads relevant skills automatically — giving it operational knowledge about the deployment workflow without requiring the user to explain each step.
|
|
1074
|
+
|
|
1075
|
+
## Installation
|
|
1076
|
+
|
|
1077
|
+
When you scaffold a new project with \`chant init --lexicon github\`, skills are installed to \`.claude/skills/\` for automatic discovery by Claude Code.
|
|
1078
|
+
|
|
1079
|
+
For existing projects, create the files manually:
|
|
1080
|
+
|
|
1081
|
+
\`\`\`
|
|
1082
|
+
.claude/
|
|
1083
|
+
skills/
|
|
1084
|
+
chant-github/
|
|
1085
|
+
SKILL.md # skill content
|
|
1086
|
+
\`\`\`
|
|
1087
|
+
|
|
1088
|
+
## Skill: chant-github
|
|
1089
|
+
|
|
1090
|
+
The inline \`chant-github\` skill covers the full workflow lifecycle:
|
|
1091
|
+
|
|
1092
|
+
- **Build** — \`chant build src/ --output .github/workflows/ci.yml\`
|
|
1093
|
+
- **Validate** — \`chant lint src/\`
|
|
1094
|
+
- **Deploy** — commit and push the generated YAML
|
|
1095
|
+
- **Status** — GitHub Actions UI or \`gh run list\`
|
|
1096
|
+
- **Troubleshooting** — lint rule codes (GHA001–GHA020), post-synth checks (GHA006–GHA019)
|
|
1097
|
+
|
|
1098
|
+
The skill is invocable as a slash command: \`/chant-github\`
|
|
1099
|
+
|
|
1100
|
+
## Skill: github-actions-patterns
|
|
1101
|
+
|
|
1102
|
+
A file-based skill loaded from \`src/skills/github-actions-patterns.md\`. It provides pattern knowledge for:
|
|
1103
|
+
|
|
1104
|
+
- **Workflow structure** — name, on, permissions, jobs
|
|
1105
|
+
- **Trigger patterns** — push, pull_request, schedule, workflow_dispatch
|
|
1106
|
+
- **Matrix strategy** — multi-OS, multi-version builds
|
|
1107
|
+
- **Caching** — SetupNode cache option, CacheAction composite
|
|
1108
|
+
- **Permissions** — least-privilege patterns
|
|
1109
|
+
- **Reusable workflows** — ReusableWorkflowCallJob
|
|
1110
|
+
- **Artifacts** — upload/download between jobs
|
|
1111
|
+
- **Concurrency** — group + cancel-in-progress
|
|
1112
|
+
|
|
1113
|
+
## MCP integration
|
|
1114
|
+
|
|
1115
|
+
The lexicon provides MCP (Model Context Protocol) tools and resources that AI agents can use programmatically:
|
|
1116
|
+
|
|
1117
|
+
| MCP tool | Description |
|
|
1118
|
+
|----------|-------------|
|
|
1119
|
+
| \`diff\` | Compare current build output against previous output |
|
|
1120
|
+
|
|
1121
|
+
| MCP resource | Description |
|
|
1122
|
+
|--------------|-------------|
|
|
1123
|
+
| \`resource-catalog\` | JSON list of all supported GitHub Actions entity types |
|
|
1124
|
+
| \`examples/basic-ci\` | Example CI workflow with TypeScript source |`,
|
|
1125
|
+
},
|
|
1126
|
+
],
|
|
1127
|
+
basePath: "/chant/lexicons/github/",
|
|
1128
|
+
};
|
|
1129
|
+
|
|
1130
|
+
const result = await docsPipeline(config);
|
|
1131
|
+
writeDocsSite(config, result);
|
|
1132
|
+
|
|
1133
|
+
if (opts?.verbose) {
|
|
1134
|
+
console.error(
|
|
1135
|
+
`Generated docs: ${result.stats.resources} resources, ${result.stats.properties} properties, ${result.stats.services} services, ${result.stats.rules} rules`,
|
|
1136
|
+
);
|
|
1137
|
+
}
|
|
1138
|
+
}
|