@synergenius/flowweaver-pack-github-actions 0.1.2 → 0.1.4
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/target.d.ts +10 -0
- package/dist/target.js +133 -2
- package/package.json +4 -4
package/dist/target.d.ts
CHANGED
|
@@ -18,6 +18,8 @@ import type { ExportOptions, ExportArtifacts, DeployInstructions } from '@synerg
|
|
|
18
18
|
export declare class GitHubActionsTarget extends BaseCICDTarget {
|
|
19
19
|
readonly name = "github-actions";
|
|
20
20
|
readonly description = "GitHub Actions workflow YAML (.github/workflows/)";
|
|
21
|
+
/** Accumulated warnings for the current export run */
|
|
22
|
+
private _warnings;
|
|
21
23
|
readonly deploySchema: {
|
|
22
24
|
runner: {
|
|
23
25
|
type: "string";
|
|
@@ -44,6 +46,14 @@ export declare class GitHubActionsTarget extends BaseCICDTarget {
|
|
|
44
46
|
private renderWorkflowYAML;
|
|
45
47
|
private renderTriggers;
|
|
46
48
|
private renderJob;
|
|
49
|
+
/**
|
|
50
|
+
* Parse a timeout string like "30m", "1h", "1h30m" into minutes.
|
|
51
|
+
*/
|
|
52
|
+
private parseTimeoutMinutes;
|
|
53
|
+
/**
|
|
54
|
+
* Translate GitLab-style CI variable conditions to GitHub Actions expressions.
|
|
55
|
+
*/
|
|
56
|
+
private translateCondition;
|
|
47
57
|
private renderStep;
|
|
48
58
|
private renderCacheStep;
|
|
49
59
|
/**
|
package/dist/target.js
CHANGED
|
@@ -21,6 +21,8 @@ import * as path from 'path';
|
|
|
21
21
|
export class GitHubActionsTarget extends BaseCICDTarget {
|
|
22
22
|
name = 'github-actions';
|
|
23
23
|
description = 'GitHub Actions workflow YAML (.github/workflows/)';
|
|
24
|
+
/** Accumulated warnings for the current export run */
|
|
25
|
+
_warnings = [];
|
|
24
26
|
deploySchema = {
|
|
25
27
|
runner: { type: 'string', description: 'GitHub runner label', default: 'ubuntu-latest' },
|
|
26
28
|
};
|
|
@@ -30,6 +32,7 @@ export class GitHubActionsTarget extends BaseCICDTarget {
|
|
|
30
32
|
label: { type: 'string', description: 'Step display name' },
|
|
31
33
|
};
|
|
32
34
|
async generate(options) {
|
|
35
|
+
this._warnings = [];
|
|
33
36
|
const filePath = path.resolve(options.sourceFile);
|
|
34
37
|
const outputDir = path.resolve(options.outputDir);
|
|
35
38
|
// Parse the workflow file to get AST
|
|
@@ -72,6 +75,7 @@ export class GitHubActionsTarget extends BaseCICDTarget {
|
|
|
72
75
|
target: this.name,
|
|
73
76
|
workflowName: options.displayName || targetWorkflows[0].name,
|
|
74
77
|
entryPoint: files[0].relativePath,
|
|
78
|
+
warnings: this._warnings.length > 0 ? this._warnings : undefined,
|
|
75
79
|
};
|
|
76
80
|
}
|
|
77
81
|
getDeployInstructions(_artifacts) {
|
|
@@ -105,6 +109,18 @@ export class GitHubActionsTarget extends BaseCICDTarget {
|
|
|
105
109
|
doc.name = ast.name;
|
|
106
110
|
// on: triggers
|
|
107
111
|
doc.on = this.renderTriggers(ast.options?.cicd?.triggers || []);
|
|
112
|
+
// env (workflow-level, from @variables)
|
|
113
|
+
if (ast.options?.cicd?.variables && Object.keys(ast.options.cicd.variables).length > 0) {
|
|
114
|
+
doc.env = { ...ast.options.cicd.variables };
|
|
115
|
+
}
|
|
116
|
+
// Warn about @includes (GitLab CI only)
|
|
117
|
+
if (ast.options?.cicd?.includes && ast.options.cicd.includes.length > 0) {
|
|
118
|
+
this._warnings.push(`@includes: GitHub Actions has no equivalent to GitLab CI includes. Use reusable workflows (workflow_call) or composite actions instead.`);
|
|
119
|
+
}
|
|
120
|
+
// Warn about @before_script at workflow level (no GH Actions equivalent)
|
|
121
|
+
if (ast.options?.cicd?.beforeScript && ast.options.cicd.beforeScript.length > 0) {
|
|
122
|
+
this._warnings.push(`Workflow-level @before_script: GitHub Actions has no global before_script. It has been applied per-job instead.`);
|
|
123
|
+
}
|
|
108
124
|
// concurrency
|
|
109
125
|
if (ast.options?.cicd?.concurrency) {
|
|
110
126
|
doc.concurrency = {
|
|
@@ -182,12 +198,63 @@ export class GitHubActionsTarget extends BaseCICDTarget {
|
|
|
182
198
|
}
|
|
183
199
|
renderJob(job, ast) {
|
|
184
200
|
const jobObj = {};
|
|
185
|
-
// runs-on
|
|
186
|
-
|
|
201
|
+
// runs-on (tags override: self-hosted + tag labels)
|
|
202
|
+
if (job.tags && job.tags.length > 0) {
|
|
203
|
+
jobObj['runs-on'] = ['self-hosted', ...job.tags];
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
jobObj['runs-on'] = job.runner || 'ubuntu-latest';
|
|
207
|
+
}
|
|
187
208
|
// needs
|
|
188
209
|
if (job.needs.length > 0) {
|
|
189
210
|
jobObj.needs = job.needs;
|
|
190
211
|
}
|
|
212
|
+
// continue-on-error (from @job allow_failure)
|
|
213
|
+
if (job.allowFailure) {
|
|
214
|
+
jobObj['continue-on-error'] = true;
|
|
215
|
+
}
|
|
216
|
+
// timeout-minutes (from @job timeout, parse "30m" → 30, "1h" → 60)
|
|
217
|
+
if (job.timeout) {
|
|
218
|
+
jobObj['timeout-minutes'] = this.parseTimeoutMinutes(job.timeout);
|
|
219
|
+
}
|
|
220
|
+
// retry: no native equivalent in GitHub Actions
|
|
221
|
+
if (job.retry !== undefined && job.retry > 0) {
|
|
222
|
+
this._warnings.push(`@job ${job.id} retry=${job.retry}: GitHub Actions has no native job-level retry. Use "Re-run failed jobs" in the UI or the nick-fields/retry action for step-level retry.`);
|
|
223
|
+
}
|
|
224
|
+
// coverage: no native equivalent in GitHub Actions
|
|
225
|
+
if (job.coverage) {
|
|
226
|
+
this._warnings.push(`@job ${job.id} coverage: GitHub Actions has no native coverage regex. Use a coverage action (e.g. codecov/codecov-action) instead.`);
|
|
227
|
+
}
|
|
228
|
+
// extends: no native equivalent in GitHub Actions (GitLab CI only)
|
|
229
|
+
if (job.extends) {
|
|
230
|
+
this._warnings.push(`@job ${job.id} extends="${job.extends}": GitHub Actions has no native extends. Use reusable workflows or composite actions instead.`);
|
|
231
|
+
}
|
|
232
|
+
// if: conditional (from @job rules)
|
|
233
|
+
if (job.rules && job.rules.length > 0) {
|
|
234
|
+
// Combine all rule conditions with || (GitHub Actions only supports a single `if:`)
|
|
235
|
+
const conditions = job.rules
|
|
236
|
+
.filter(r => r.if)
|
|
237
|
+
.map(r => this.translateCondition(r.if));
|
|
238
|
+
if (conditions.length === 1) {
|
|
239
|
+
jobObj.if = conditions[0];
|
|
240
|
+
}
|
|
241
|
+
else if (conditions.length > 1) {
|
|
242
|
+
jobObj.if = conditions.map(c => `(${c})`).join(' || ');
|
|
243
|
+
}
|
|
244
|
+
// Warn about rule properties that don't translate to GitHub Actions
|
|
245
|
+
const hasWhen = job.rules.some(r => r.when);
|
|
246
|
+
const hasChanges = job.rules.some(r => r.changes && r.changes.length > 0);
|
|
247
|
+
if (hasWhen) {
|
|
248
|
+
this._warnings.push(`@job ${job.id} rules when=: GitHub Actions has no native when (manual/delayed/always). Use workflow_dispatch for manual triggers.`);
|
|
249
|
+
}
|
|
250
|
+
if (hasChanges) {
|
|
251
|
+
this._warnings.push(`@job ${job.id} rules changes=: GitHub Actions handles path filtering via on.push.paths, not per-job. Use dorny/paths-filter for per-job path filtering.`);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
// env (from @job variables or @variables)
|
|
255
|
+
if (job.variables && Object.keys(job.variables).length > 0) {
|
|
256
|
+
jobObj.env = { ...job.variables };
|
|
257
|
+
}
|
|
191
258
|
// environment
|
|
192
259
|
if (job.environment) {
|
|
193
260
|
const envConfig = ast.options?.cicd?.environments?.find((e) => e.name === job.environment);
|
|
@@ -246,6 +313,13 @@ export class GitHubActionsTarget extends BaseCICDTarget {
|
|
|
246
313
|
if (job.cache) {
|
|
247
314
|
steps.push(this.renderCacheStep(job.cache));
|
|
248
315
|
}
|
|
316
|
+
// before_script as a setup step
|
|
317
|
+
if (job.beforeScript && job.beforeScript.length > 0) {
|
|
318
|
+
steps.push({
|
|
319
|
+
name: 'Setup',
|
|
320
|
+
run: job.beforeScript.join('\n'),
|
|
321
|
+
});
|
|
322
|
+
}
|
|
249
323
|
// Node steps
|
|
250
324
|
for (const step of job.steps) {
|
|
251
325
|
steps.push(this.renderStep(step));
|
|
@@ -266,9 +340,66 @@ export class GitHubActionsTarget extends BaseCICDTarget {
|
|
|
266
340
|
steps.push(uploadStep);
|
|
267
341
|
}
|
|
268
342
|
}
|
|
343
|
+
// reports: junit → test-reporter, coverage → codecov
|
|
344
|
+
if (job.reports && job.reports.length > 0) {
|
|
345
|
+
for (const report of job.reports) {
|
|
346
|
+
if (report.type === 'junit') {
|
|
347
|
+
steps.push({
|
|
348
|
+
name: 'Test Report',
|
|
349
|
+
uses: 'dorny/test-reporter@v1',
|
|
350
|
+
if: 'always()',
|
|
351
|
+
with: {
|
|
352
|
+
name: 'Test Results',
|
|
353
|
+
path: report.path,
|
|
354
|
+
reporter: 'java-junit',
|
|
355
|
+
},
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
else if (report.type === 'cobertura' || report.type === 'coverage') {
|
|
359
|
+
steps.push({
|
|
360
|
+
name: 'Upload Coverage',
|
|
361
|
+
uses: 'codecov/codecov-action@v4',
|
|
362
|
+
with: { files: report.path },
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
steps.push({
|
|
367
|
+
name: `Upload ${report.type} report`,
|
|
368
|
+
uses: 'actions/upload-artifact@v4',
|
|
369
|
+
with: {
|
|
370
|
+
name: `${report.type}-report`,
|
|
371
|
+
path: report.path,
|
|
372
|
+
},
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
269
377
|
jobObj.steps = steps;
|
|
270
378
|
return jobObj;
|
|
271
379
|
}
|
|
380
|
+
/**
|
|
381
|
+
* Parse a timeout string like "30m", "1h", "1h30m" into minutes.
|
|
382
|
+
*/
|
|
383
|
+
parseTimeoutMinutes(timeout) {
|
|
384
|
+
let minutes = 0;
|
|
385
|
+
const hourMatch = timeout.match(/(\d+)h/);
|
|
386
|
+
const minMatch = timeout.match(/(\d+)m/);
|
|
387
|
+
if (hourMatch)
|
|
388
|
+
minutes += parseInt(hourMatch[1], 10) * 60;
|
|
389
|
+
if (minMatch)
|
|
390
|
+
minutes += parseInt(minMatch[1], 10);
|
|
391
|
+
return minutes || 60; // default 60 if unparseable
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Translate GitLab-style CI variable conditions to GitHub Actions expressions.
|
|
395
|
+
*/
|
|
396
|
+
translateCondition(condition) {
|
|
397
|
+
return condition
|
|
398
|
+
.replace(/\$CI_COMMIT_BRANCH/g, "github.ref_name")
|
|
399
|
+
.replace(/\$CI_COMMIT_TAG/g, "startsWith(github.ref, 'refs/tags/')")
|
|
400
|
+
.replace(/\$CI_PIPELINE_SOURCE/g, "github.event_name")
|
|
401
|
+
.replace(/==/g, '==');
|
|
402
|
+
}
|
|
272
403
|
renderStep(step) {
|
|
273
404
|
const mapping = this.resolveActionMapping(step, 'github-actions');
|
|
274
405
|
if (mapping?.githubAction) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synergenius/flowweaver-pack-github-actions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "GitHub Actions CI/CD export target for Flow Weaver",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"flowweaver-marketplace-pack",
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
"prepublishOnly": "npm run build"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"
|
|
39
|
-
"@
|
|
40
|
-
"
|
|
38
|
+
"@synergenius/flow-weaver": "^0.17.4",
|
|
39
|
+
"@types/node": "^20.0.0",
|
|
40
|
+
"typescript": "^5.0.0"
|
|
41
41
|
},
|
|
42
42
|
"license": "SEE LICENSE IN LICENSE",
|
|
43
43
|
"repository": {
|