gaji 0.2.7 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +340 -0
  2. package/package.json +6 -6
package/README.md ADDED
@@ -0,0 +1,340 @@
1
+ <div align="center">
2
+ <img src="logo.png" alt="gaji logo" width="200"/>
3
+ <h1>gaji</h1>
4
+ <p>Type-safe GitHub Actions workflows in TypeScript</p>
5
+ <p><em>GitHub Actions Justified Improvements</em></p>
6
+ <p>🍆 Named after the Korean word "가지" (gaji, eggplant) - a versatile ingredient that makes everything better!</p>
7
+ </div>
8
+
9
+ ## Overview
10
+
11
+ `gaji` is a CLI tool that allows developers to write GitHub Actions workflows in TypeScript with full type safety, then compile them to YAML. It automatically fetches `action.yml` definitions and generates typed wrappers, so you get autocomplete and type checking for every action input and output.
12
+
13
+ ## Features
14
+
15
+ - TypeScript-based workflow authoring with full type safety
16
+ - Automatic type generation from `action.yml` files
17
+ - Composite action and reusable workflow support
18
+ - File watching for development (`--watch`)
19
+ - Built-in QuickJS execution with `npx tsx` fallback
20
+ - GitHub Enterprise support
21
+ - Single binary distribution (Rust)
22
+
23
+ ## Installation
24
+
25
+ ### From npm
26
+
27
+ ```bash
28
+ npm install -D gaji
29
+ ```
30
+
31
+ ### From cargo
32
+
33
+ ```bash
34
+ cargo install gaji
35
+ ```
36
+
37
+ ## Quick Start
38
+
39
+ ```bash
40
+ # Initialize a new project (creates workflows/ and generated/ directories)
41
+ gaji init
42
+
43
+ # Add actions and generate types
44
+ gaji add actions/checkout@v5
45
+ gaji add actions/setup-node@v4
46
+
47
+ # Run a one-time dev scan to generate types
48
+ gaji dev
49
+
50
+ # Build workflows to YAML
51
+ gaji build
52
+ ```
53
+
54
+ ## Usage
55
+
56
+ ### Writing Workflows
57
+
58
+ Create TypeScript files in the `workflows/` directory:
59
+
60
+ ```typescript
61
+ import { getAction, Job, Workflow } from "../generated/index.js";
62
+
63
+ const checkout = getAction("actions/checkout@v5");
64
+ const setupNode = getAction("actions/setup-node@v4");
65
+
66
+ const build = new Job("ubuntu-latest")
67
+ .addStep(checkout({
68
+ name: "Checkout code",
69
+ with: { "fetch-depth": 1 },
70
+ }))
71
+ .addStep(setupNode({
72
+ with: { "node-version": "22" },
73
+ }))
74
+ .addStep({ name: "Install dependencies", run: "npm ci" })
75
+ .addStep({ name: "Run tests", run: "npm test" });
76
+
77
+ const workflow = new Workflow({
78
+ name: "CI",
79
+ on: {
80
+ push: { branches: ["main"] },
81
+ pull_request: { branches: ["main"] },
82
+ },
83
+ }).addJob("build", build);
84
+
85
+ workflow.build("ci");
86
+ ```
87
+
88
+ Run `gaji build` and it outputs `.github/workflows/ci.yml`.
89
+
90
+ ### Recommended Development Workflow
91
+
92
+ For the best experience, follow this workflow:
93
+
94
+ 1. **Start watch mode**:
95
+ ```bash
96
+ gaji dev --watch
97
+ ```
98
+ Leave this running in a terminal. It will automatically generate types when you add new actions.
99
+
100
+ 2. **Edit your TypeScript workflows** in `workflows/*.ts`:
101
+ - Add or modify steps
102
+ - Use `getAction()` with full type safety
103
+ - Types are automatically generated for new actions
104
+
105
+ 3. **Build to YAML**:
106
+ ```bash
107
+ gaji build
108
+ ```
109
+
110
+ 4. **Review the generated YAML** in `.github/workflows/`:
111
+ - Verify commands are correct
112
+ - Check that step order is as expected
113
+ - Ensure all required fields are present
114
+
115
+ 5. **Commit both TypeScript and YAML**:
116
+ ```bash
117
+ git add workflows/ .github/workflows/
118
+ git commit -m "Update workflows"
119
+ ```
120
+
121
+ #### Why Commit Both?
122
+
123
+ You should commit **both** the TypeScript source (`workflows/*.ts`) and the generated YAML (`.github/workflows/*.yml`):
124
+
125
+ - **TypeScript**: Source of truth for your workflows
126
+ - **YAML**: What GitHub Actions actually executes
127
+
128
+ #### ⚠️ Important: Auto-compilation in CI
129
+
130
+ While you can create a workflow that auto-compiles TypeScript to YAML on push, **this is NOT recommended**. Always compile and review workflows locally before committing.
131
+
132
+ If you're willing to handle the complexity of GitHub Actions triggers (e.g., filtering `paths`, managing PAT tokens, avoiding infinite loops), you can set up an auto-compilation workflow. See [`workflows/update-workflows.ts`](https://github.com/dodok8/gaji/blob/main/workflows/update-workflows.ts) for a working example.
133
+
134
+ ### Composite Actions
135
+
136
+ Define reusable composite actions and reference them in workflows:
137
+
138
+ ```typescript
139
+ import { CompositeAction, CallAction, Job, Workflow } from "../generated/index.js";
140
+
141
+ const action = new CompositeAction({
142
+ name: "Setup",
143
+ description: "Setup the project environment",
144
+ inputs: {
145
+ "node-version": { description: "Node.js version", required: false, default: "20" },
146
+ },
147
+ });
148
+ action.addStep({ name: "Install deps", run: "npm ci", shell: "bash" });
149
+ action.build("setup");
150
+
151
+ // Reference the composite action in a workflow
152
+ const job = new Job("ubuntu-latest")
153
+ .addStep(CallAction.from(action).toJSON());
154
+
155
+ const workflow = new Workflow({
156
+ name: "CI",
157
+ on: { push: {} },
158
+ }).addJob("build", job);
159
+
160
+ workflow.build("ci");
161
+ ```
162
+
163
+ ### Reusable Workflows
164
+
165
+ Call reusable workflows using `CallJob`:
166
+
167
+ ```typescript
168
+ import { CallJob, Workflow } from "../generated/index.js";
169
+
170
+ const deploy = new CallJob("./.github/workflows/deploy.yml")
171
+ .with({ environment: "production" })
172
+ .secrets("inherit")
173
+ .needs(["build"]);
174
+
175
+ const workflow = new Workflow({
176
+ name: "Release",
177
+ on: { push: { tags: ["v*"] } },
178
+ }).addJob("deploy", deploy);
179
+
180
+ workflow.build("release");
181
+ ```
182
+
183
+ ### Job Options
184
+
185
+ The `Job` constructor accepts an optional second argument for additional configuration:
186
+
187
+ ```typescript
188
+ const job = new Job("ubuntu-latest", {
189
+ needs: ["setup"],
190
+ env: { NODE_ENV: "test" },
191
+ "timeout-minutes": 30,
192
+ "continue-on-error": true,
193
+ permissions: { contents: "read" },
194
+ strategy: {
195
+ matrix: { node: ["18", "20", "22"] },
196
+ "fail-fast": false,
197
+ },
198
+ });
199
+ ```
200
+
201
+ Builder methods are also available:
202
+
203
+ ```typescript
204
+ const job = new Job("ubuntu-latest")
205
+ .addStep({ name: "Test", run: "npm test" })
206
+ .needs(["setup"])
207
+ .env({ CI: "true" })
208
+ .when("github.event_name == 'push'")
209
+ .permissions({ contents: "read" })
210
+ .outputs({ result: "${{ steps.test.outputs.result }}" })
211
+ .strategy({ matrix: { os: ["ubuntu-latest", "macos-latest"] } })
212
+ .continueOnError(true)
213
+ .timeoutMinutes(30);
214
+ ```
215
+
216
+ ## Commands
217
+
218
+ ### `gaji init`
219
+
220
+ Initialize a new gaji project. Detects the project state (empty, existing project, or has YAML workflows) and sets up accordingly.
221
+
222
+ ```
223
+ gaji init [OPTIONS]
224
+ ```
225
+
226
+ | Option | Description |
227
+ |---|---|
228
+ | `--force` | Overwrite existing files |
229
+ | `--skip-examples` | Skip example workflow creation |
230
+ | `--migrate` | Migrate existing YAML workflows to TypeScript |
231
+ | `-i, --interactive` | Interactive mode |
232
+
233
+ ### `gaji dev`
234
+
235
+ Start development mode. Scans workflow files for action references and generates types.
236
+
237
+ ```
238
+ gaji dev [OPTIONS]
239
+ ```
240
+
241
+ | Option | Description |
242
+ |---|---|
243
+ | `-d, --dir <DIR>` | Directory to scan (default: `workflows`) |
244
+ | `--watch` | Keep watching for changes after the initial scan |
245
+
246
+ ### `gaji build`
247
+
248
+ Build TypeScript workflows to YAML.
249
+
250
+ ```
251
+ gaji build [OPTIONS]
252
+ ```
253
+
254
+ | Option | Description |
255
+ |---|---|
256
+ | `-i, --input <DIR>` | Input directory containing TypeScript workflows (default: `workflows`) |
257
+ | `-o, --output <DIR>` | Output directory for YAML files (default: `.github`) |
258
+ | `--dry-run` | Preview YAML output without writing files |
259
+
260
+ Output files are placed in subdirectories based on type:
261
+ - Workflows: `.github/workflows/<id>.yml`
262
+ - Composite actions: `.github/actions/<id>/action.yml`
263
+
264
+ ### `gaji add <action>`
265
+
266
+ Add a new action and generate types.
267
+
268
+ ```bash
269
+ gaji add actions/checkout@v5
270
+ gaji add actions/setup-node@v4
271
+ ```
272
+
273
+ ### `gaji clean`
274
+
275
+ Clean generated files.
276
+
277
+ ```
278
+ gaji clean [OPTIONS]
279
+ ```
280
+
281
+ | Option | Description |
282
+ |---|---|
283
+ | `--cache` | Also clean cache |
284
+
285
+ ## Configuration
286
+
287
+ ### `.gaji.toml`
288
+
289
+ Project-level configuration file. Created automatically by `gaji init`.
290
+
291
+ ```toml
292
+ [project]
293
+ workflows_dir = "workflows" # TypeScript workflow source directory
294
+ output_dir = ".github" # Output directory for generated YAML
295
+ generated_dir = "generated" # Directory for generated type definitions
296
+
297
+ [watch]
298
+ debounce_ms = 300 # Debounce delay for file watcher
299
+ ignored_patterns = ["node_modules", ".git", "generated"]
300
+
301
+ [build]
302
+ validate = true # Validate workflow YAML (requires 'on' and 'jobs')
303
+ format = true # Format YAML output
304
+
305
+ [github]
306
+ token = "ghp_..." # GitHub token (prefer .gaji.local.toml for this)
307
+ api_url = "https://github.example.com" # GitHub Enterprise URL
308
+ ```
309
+
310
+ ### `.gaji.local.toml`
311
+
312
+ Local overrides for sensitive values. Add this to `.gitignore`.
313
+
314
+ ```toml
315
+ [github]
316
+ token = "ghp_your_token_here"
317
+ api_url = "https://github.example.com" # for GitHub Enterprise
318
+ ```
319
+
320
+ Token resolution priority: `GITHUB_TOKEN` env var > `.gaji.local.toml` > `.gaji.toml`
321
+
322
+ ## Documentation
323
+
324
+ 📚 **[Full Documentation](https://gaji.gaebalgom.work)** (English & 한국어)
325
+
326
+ - [Getting Started](https://gaji.gaebalgom.work/guide/getting-started)
327
+ - [Writing Workflows](https://gaji.gaebalgom.work/guide/writing-workflows)
328
+ - [CLI Reference](https://gaji.gaebalgom.work/reference/cli)
329
+ - [API Reference](https://gaji.gaebalgom.work/reference/api)
330
+ - [Examples](examples/)
331
+
332
+ ## Examples
333
+
334
+ Check out the [examples/](examples/) directory for complete working examples:
335
+
336
+ - **[ts-package](examples/ts-package/)** - TypeScript package with gaji CI workflow using pnpm
337
+
338
+ ## License
339
+
340
+ MIT License
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gaji",
3
- "version": "0.2.7",
3
+ "version": "0.3.0",
4
4
  "description": "Type-safe GitHub Actions workflows in TypeScript",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -33,11 +33,11 @@
33
33
  "provenance": true
34
34
  },
35
35
  "optionalDependencies": {
36
- "@gaji/linux-x64": "0.2.7",
37
- "@gaji/linux-arm64": "0.2.7",
38
- "@gaji/darwin-x64": "0.2.7",
39
- "@gaji/darwin-arm64": "0.2.7",
40
- "@gaji/win32-x64": "0.2.7"
36
+ "@gaji/linux-x64": "0.3.0",
37
+ "@gaji/linux-arm64": "0.3.0",
38
+ "@gaji/darwin-x64": "0.3.0",
39
+ "@gaji/darwin-arm64": "0.3.0",
40
+ "@gaji/win32-x64": "0.3.0"
41
41
  },
42
42
  "keywords": [
43
43
  "github-actions",