@savvy-web/github-action-builder 0.7.3 → 0.7.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,302 @@
1
+ import { BuildResultSchema, BuildService } from "./services/build.js";
2
+ import { defineConfig } from "./schemas/config.js";
3
+ import { ConfigService } from "./services/config.js";
4
+ import { PersistLocalResultSchema, PersistLocalService } from "./services/persist-local.js";
5
+ import { ValidationResultSchema, ValidationService } from "./services/validation.js";
6
+ import { AppLayer } from "./layers/app.js";
7
+ import { Effect, ManagedRuntime, Schema } from "effect";
8
+
9
+ //#region src/github-action.ts
10
+ /**
11
+ * Result of a GitHubAction build operation.
12
+ *
13
+ * @remarks
14
+ * The result contains detailed information about both validation and build steps.
15
+ * Check the `success` property first, then examine `error`, `validation`, or `build`
16
+ * for details.
17
+ *
18
+ * @internal
19
+ */
20
+ const GitHubActionBuildResultSchema = Schema.Struct({
21
+ /** Whether the build completed successfully. */
22
+ success: Schema.Boolean,
23
+ /** Build result details if the build step ran. */
24
+ build: Schema.optional(BuildResultSchema),
25
+ /** Validation result if validation was performed. */
26
+ validation: Schema.optional(ValidationResultSchema),
27
+ /** Persist-local result if persist was performed. */
28
+ persistLocal: Schema.optional(PersistLocalResultSchema),
29
+ /** Error message if the build or validation failed. */
30
+ error: Schema.optional(Schema.String),
31
+ /** Raw error object for programmatic inspection. */
32
+ cause: Schema.optional(Schema.Unknown)
33
+ });
34
+ /**
35
+ * Main API class for building GitHub Actions.
36
+ *
37
+ * @remarks
38
+ * This class provides a Promise-based interface wrapping Effect services.
39
+ * It handles configuration loading, validation, and bundling in a single workflow.
40
+ *
41
+ * For Effect consumers, use the services directly:
42
+ * - {@link ConfigService} for configuration
43
+ * - {@link ValidationService} for validation
44
+ * - {@link BuildService} for building
45
+ *
46
+ * @example Complete build workflow
47
+ * ```typescript
48
+ * import { GitHubAction } from "@savvy-web/github-action-builder";
49
+ *
50
+ * async function buildAction(): Promise<void> {
51
+ * const action = GitHubAction.create();
52
+ * const result = await action.build();
53
+ *
54
+ * if (result.success) {
55
+ * console.log(`Built ${result.build?.entries.length} entry points`);
56
+ * } else {
57
+ * console.error(`Build failed: ${result.error}`);
58
+ * process.exit(1);
59
+ * }
60
+ * }
61
+ *
62
+ * buildAction();
63
+ * ```
64
+ *
65
+ * @example With custom configuration
66
+ * ```typescript
67
+ * import { GitHubAction } from "@savvy-web/github-action-builder";
68
+ *
69
+ * async function main(): Promise<void> {
70
+ * const action = GitHubAction.create({
71
+ * config: {
72
+ * entries: { main: "src/action.ts" },
73
+ * build: { minify: true },
74
+ * },
75
+ * cwd: "/path/to/project",
76
+ * });
77
+ *
78
+ * const result = await action.build();
79
+ * console.log(result.success ? "Success" : result.error);
80
+ * }
81
+ *
82
+ * main();
83
+ * ```
84
+ *
85
+ * @public
86
+ */
87
+ var GitHubAction = class GitHubAction {
88
+ /**
89
+ * Managed runtime for running Effects.
90
+ * @internal
91
+ */
92
+ runtime;
93
+ /**
94
+ * Cached configuration after first load.
95
+ * @internal
96
+ */
97
+ config = null;
98
+ /**
99
+ * Resolved options.
100
+ * @internal
101
+ */
102
+ cwd;
103
+ configSource;
104
+ skipValidation;
105
+ clean;
106
+ constructor(options = {}) {
107
+ const layer = options.layer ?? AppLayer;
108
+ this.runtime = ManagedRuntime.make(layer);
109
+ this.configSource = options.config;
110
+ this.cwd = options.cwd ?? process.cwd();
111
+ this.skipValidation = options.skipValidation ?? false;
112
+ this.clean = options.clean ?? true;
113
+ }
114
+ /**
115
+ * Create a new GitHubAction builder instance.
116
+ *
117
+ * @param options - Builder options
118
+ * @returns A new GitHubAction instance
119
+ *
120
+ * @example
121
+ * ```typescript
122
+ * import { GitHubAction } from "@savvy-web/github-action-builder";
123
+ *
124
+ * // Auto-detect configuration
125
+ * const action = GitHubAction.create();
126
+ *
127
+ * // With inline config
128
+ * const action2 = GitHubAction.create({
129
+ * config: { build: { minify: false } },
130
+ * });
131
+ *
132
+ * // With config file path
133
+ * const action3 = GitHubAction.create({
134
+ * config: "./custom.config.ts",
135
+ * });
136
+ * ```
137
+ */
138
+ static create(options = {}) {
139
+ return new GitHubAction(options);
140
+ }
141
+ /**
142
+ * Load and resolve configuration.
143
+ *
144
+ * @remarks
145
+ * Configuration is cached after the first load. Subsequent calls
146
+ * return the cached configuration.
147
+ *
148
+ * @returns Resolved configuration with all defaults applied
149
+ * @throws Error if configuration file cannot be loaded or is invalid
150
+ */
151
+ async loadConfig() {
152
+ if (this.config) return this.config;
153
+ const configSource = this.configSource;
154
+ const cwd = this.cwd;
155
+ const program = Effect.gen(function* () {
156
+ const configService = yield* ConfigService;
157
+ /* v8 ignore next 6 - requires config file path string */
158
+ if (typeof configSource === "string") return (yield* configService.load({
159
+ cwd,
160
+ configPath: configSource
161
+ })).config;
162
+ if (configSource) return defineConfig(configSource);
163
+ return (yield* configService.load({ cwd })).config;
164
+ });
165
+ const config = await this.runtime.runPromise(program);
166
+ this.config = config;
167
+ return config;
168
+ }
169
+ /**
170
+ * Validate the action configuration and action.yml.
171
+ *
172
+ * @remarks
173
+ * Validation checks:
174
+ * - Entry point files exist
175
+ * - Output directory is writable
176
+ * - action.yml exists and is valid (if required)
177
+ *
178
+ * In CI environments, warnings are treated as errors by default.
179
+ *
180
+ * @param options - Validation options
181
+ * @returns Validation result with errors and warnings
182
+ */
183
+ async validate(options = {}) {
184
+ const config = await this.loadConfig();
185
+ const cwd = this.cwd;
186
+ const program = Effect.gen(function* () {
187
+ return yield* (yield* ValidationService).validate(config, {
188
+ cwd,
189
+ ...options
190
+ });
191
+ });
192
+ return this.runtime.runPromise(program);
193
+ }
194
+ /**
195
+ * Build the GitHub Action.
196
+ *
197
+ * @remarks
198
+ * The build process:
199
+ * 1. Loads configuration (if not already loaded)
200
+ * 2. Validates the project (unless `skipValidation` is set)
201
+ * 3. Bundles each entry point with rsbuild
202
+ * 4. Writes output to the `dist/` directory
203
+ *
204
+ * @returns Build result with success status and details
205
+ *
206
+ * @example
207
+ * ```typescript
208
+ * import { GitHubAction } from "@savvy-web/github-action-builder";
209
+ *
210
+ * async function main(): Promise<void> {
211
+ * const action = GitHubAction.create();
212
+ * const result = await action.build();
213
+ *
214
+ * if (result.success && result.build) {
215
+ * console.log(`Built ${result.build.entries.length} entries`);
216
+ * } else {
217
+ * console.error(result.error);
218
+ * }
219
+ * }
220
+ *
221
+ * main();
222
+ * ```
223
+ */
224
+ /* v8 ignore start - build execution requires actual rsbuild bundling */
225
+ async build() {
226
+ try {
227
+ const config = await this.loadConfig();
228
+ let validationResult;
229
+ if (!this.skipValidation) {
230
+ validationResult = await this.validate();
231
+ if (!validationResult.valid) return {
232
+ success: false,
233
+ validation: validationResult,
234
+ error: "Validation failed"
235
+ };
236
+ }
237
+ const cwd = this.cwd;
238
+ const clean = this.clean;
239
+ const program = Effect.gen(function* () {
240
+ const buildService = yield* BuildService;
241
+ const buildOptions = {
242
+ cwd,
243
+ clean
244
+ };
245
+ return yield* buildService.build(config, buildOptions);
246
+ });
247
+ const buildResult = await this.runtime.runPromise(program);
248
+ if (!buildResult.success) {
249
+ if (validationResult) return {
250
+ success: false,
251
+ build: buildResult,
252
+ validation: validationResult,
253
+ error: buildResult.error ?? "Build failed"
254
+ };
255
+ return {
256
+ success: false,
257
+ build: buildResult,
258
+ error: buildResult.error ?? "Build failed"
259
+ };
260
+ }
261
+ let persistLocalResult;
262
+ if (config.persistLocal.enabled) {
263
+ const persistProgram = Effect.gen(function* () {
264
+ return yield* (yield* PersistLocalService).persist(config, { cwd });
265
+ });
266
+ persistLocalResult = await this.runtime.runPromise(persistProgram);
267
+ }
268
+ if (validationResult) return {
269
+ success: true,
270
+ build: buildResult,
271
+ validation: validationResult,
272
+ persistLocal: persistLocalResult
273
+ };
274
+ return {
275
+ success: true,
276
+ build: buildResult,
277
+ persistLocal: persistLocalResult
278
+ };
279
+ } catch (error) {
280
+ return {
281
+ success: false,
282
+ error: error instanceof Error ? error.message : "Unknown error",
283
+ cause: error
284
+ };
285
+ }
286
+ }
287
+ /* v8 ignore stop */
288
+ /**
289
+ * Dispose the runtime and release resources.
290
+ *
291
+ * @remarks
292
+ * Call this when you're done using the GitHubAction instance
293
+ * to clean up any resources held by the Effect runtime.
294
+ */
295
+ /* v8 ignore next 3 - cleanup method */
296
+ async dispose() {
297
+ await this.runtime.dispose();
298
+ }
299
+ };
300
+
301
+ //#endregion
302
+ export { GitHubAction, GitHubActionBuildResultSchema };