@synergenius/flow-weaver 0.17.7 → 0.17.8
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/api/parse.d.ts +5 -0
- package/dist/api/parse.js +4 -0
- package/dist/ast/types.d.ts +2 -0
- package/dist/cli/commands/compile.js +2 -1
- package/dist/cli/commands/init.js +15 -9
- package/dist/cli/commands/validate.js +1 -1
- package/dist/cli/exports.d.ts +17 -0
- package/dist/cli/exports.js +23 -0
- package/dist/cli/flow-weaver.mjs +59021 -62127
- package/dist/cli/templates/index.js +8 -1
- package/dist/extensions/index.d.ts +10 -6
- package/dist/extensions/index.js +11 -6
- package/dist/generated-version.d.ts +1 -1
- package/dist/generated-version.js +1 -1
- package/dist/generator/index.d.ts +11 -0
- package/dist/generator/index.js +11 -0
- package/dist/parser.d.ts +7 -0
- package/dist/parser.js +29 -0
- package/package.json +11 -7
- package/dist/extensions/cicd/base-target.d.ts +0 -110
- package/dist/extensions/cicd/base-target.js +0 -397
- package/dist/extensions/cicd/detection.d.ts +0 -33
- package/dist/extensions/cicd/detection.js +0 -88
- package/dist/extensions/cicd/docs/cicd.md +0 -395
- package/dist/extensions/cicd/index.d.ts +0 -15
- package/dist/extensions/cicd/index.js +0 -15
- package/dist/extensions/cicd/register.d.ts +0 -11
- package/dist/extensions/cicd/register.js +0 -62
- package/dist/extensions/cicd/rules.d.ts +0 -30
- package/dist/extensions/cicd/rules.js +0 -288
- package/dist/extensions/cicd/tag-handler.d.ts +0 -14
- package/dist/extensions/cicd/tag-handler.js +0 -504
- package/dist/extensions/cicd/templates/cicd-docker.d.ts +0 -9
- package/dist/extensions/cicd/templates/cicd-docker.js +0 -110
- package/dist/extensions/cicd/templates/cicd-matrix.d.ts +0 -9
- package/dist/extensions/cicd/templates/cicd-matrix.js +0 -112
- package/dist/extensions/cicd/templates/cicd-multi-env.d.ts +0 -9
- package/dist/extensions/cicd/templates/cicd-multi-env.js +0 -126
- package/dist/extensions/cicd/templates/cicd-test-deploy.d.ts +0 -11
- package/dist/extensions/cicd/templates/cicd-test-deploy.js +0 -156
- package/dist/extensions/inngest/dev-mode.d.ts +0 -9
- package/dist/extensions/inngest/dev-mode.js +0 -213
- package/dist/extensions/inngest/generator.d.ts +0 -53
- package/dist/extensions/inngest/generator.js +0 -1176
- package/dist/extensions/inngest/index.d.ts +0 -2
- package/dist/extensions/inngest/index.js +0 -2
- package/dist/extensions/inngest/register.d.ts +0 -6
- package/dist/extensions/inngest/register.js +0 -23
- package/dist/extensions/inngest/templates/ai-agent-durable.d.ts +0 -8
- package/dist/extensions/inngest/templates/ai-agent-durable.js +0 -334
- package/dist/extensions/inngest/templates/ai-pipeline-durable.d.ts +0 -8
- package/dist/extensions/inngest/templates/ai-pipeline-durable.js +0 -326
|
@@ -1,397 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Base CI/CD Export Target
|
|
3
|
-
*
|
|
4
|
-
* Shared logic for generating CI/CD pipeline files (GitHub Actions, GitLab CI).
|
|
5
|
-
* Unlike serverless targets, CI/CD targets produce native YAML that runs without
|
|
6
|
-
* any FW runtime dependency.
|
|
7
|
-
*
|
|
8
|
-
* Key responsibilities:
|
|
9
|
-
* - Build job graph from AST (group nodes by @job, compute dependencies)
|
|
10
|
-
* - Resolve secret wiring (secret: pseudo-node connections -> job env vars)
|
|
11
|
-
* - Inject artifact upload/download steps between jobs
|
|
12
|
-
* - Generate SECRETS_SETUP.md documentation
|
|
13
|
-
*/
|
|
14
|
-
import { BaseExportTarget, } from '../../deployment/targets/base.js';
|
|
15
|
-
export const NODE_ACTION_MAP = {
|
|
16
|
-
checkout: {
|
|
17
|
-
githubAction: 'actions/checkout@v4',
|
|
18
|
-
gitlabScript: ['echo "Checkout handled by GitLab CI runner"'],
|
|
19
|
-
label: 'Checkout code',
|
|
20
|
-
},
|
|
21
|
-
'setup-node': {
|
|
22
|
-
githubAction: 'actions/setup-node@v4',
|
|
23
|
-
githubWith: { 'node-version': '20' },
|
|
24
|
-
gitlabImage: 'node:20',
|
|
25
|
-
label: 'Setup Node.js',
|
|
26
|
-
},
|
|
27
|
-
'setup-python': {
|
|
28
|
-
githubAction: 'actions/setup-python@v5',
|
|
29
|
-
githubWith: { 'python-version': '3.12' },
|
|
30
|
-
gitlabImage: 'python:3.12',
|
|
31
|
-
label: 'Setup Python',
|
|
32
|
-
},
|
|
33
|
-
'npm-install': {
|
|
34
|
-
githubAction: undefined,
|
|
35
|
-
gitlabScript: ['npm ci'],
|
|
36
|
-
label: 'Install dependencies',
|
|
37
|
-
},
|
|
38
|
-
'npm-test': {
|
|
39
|
-
githubAction: undefined,
|
|
40
|
-
gitlabScript: ['npm test'],
|
|
41
|
-
label: 'Run tests',
|
|
42
|
-
},
|
|
43
|
-
'npm-build': {
|
|
44
|
-
githubAction: undefined,
|
|
45
|
-
gitlabScript: ['npm run build'],
|
|
46
|
-
label: 'Build',
|
|
47
|
-
},
|
|
48
|
-
'docker-build': {
|
|
49
|
-
githubAction: 'docker/build-push-action@v6',
|
|
50
|
-
githubWith: { push: 'false' },
|
|
51
|
-
gitlabScript: ['docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .'],
|
|
52
|
-
label: 'Build Docker image',
|
|
53
|
-
},
|
|
54
|
-
'docker-push': {
|
|
55
|
-
githubAction: 'docker/build-push-action@v6',
|
|
56
|
-
githubWith: { push: 'true' },
|
|
57
|
-
gitlabScript: ['docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA'],
|
|
58
|
-
label: 'Push Docker image',
|
|
59
|
-
},
|
|
60
|
-
'docker-login': {
|
|
61
|
-
githubAction: 'docker/login-action@v3',
|
|
62
|
-
gitlabScript: ['echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY'],
|
|
63
|
-
label: 'Docker login',
|
|
64
|
-
},
|
|
65
|
-
'shell-command': {
|
|
66
|
-
githubAction: undefined,
|
|
67
|
-
gitlabScript: ['echo "TODO: Add shell command"'],
|
|
68
|
-
label: 'Run command',
|
|
69
|
-
},
|
|
70
|
-
'deploy-ssh': {
|
|
71
|
-
githubAction: undefined,
|
|
72
|
-
gitlabScript: ['echo "TODO: Configure SSH deployment"'],
|
|
73
|
-
label: 'Deploy via SSH',
|
|
74
|
-
},
|
|
75
|
-
'deploy-s3': {
|
|
76
|
-
githubAction: 'aws-actions/configure-aws-credentials@v4',
|
|
77
|
-
gitlabScript: ['aws s3 sync dist/ s3://$S3_BUCKET/'],
|
|
78
|
-
label: 'Deploy to S3',
|
|
79
|
-
},
|
|
80
|
-
'slack-notify': {
|
|
81
|
-
githubAction: 'slackapi/slack-github-action@v1',
|
|
82
|
-
gitlabScript: ["curl -X POST -H 'Content-type: application/json' --data '{\"text\":\"Pipeline complete\"}' $SLACK_WEBHOOK_URL"],
|
|
83
|
-
label: 'Send Slack notification',
|
|
84
|
-
},
|
|
85
|
-
'health-check': {
|
|
86
|
-
githubAction: undefined,
|
|
87
|
-
gitlabScript: ['curl --retry 10 --retry-delay 5 --retry-all-errors $HEALTH_CHECK_URL'],
|
|
88
|
-
label: 'Health check',
|
|
89
|
-
},
|
|
90
|
-
'wait-for-url': {
|
|
91
|
-
githubAction: undefined,
|
|
92
|
-
gitlabScript: ['for i in $(seq 1 30); do curl -sf $WAIT_URL && exit 0; sleep 10; done; exit 1'],
|
|
93
|
-
label: 'Wait for URL',
|
|
94
|
-
},
|
|
95
|
-
};
|
|
96
|
-
// ---------------------------------------------------------------------------
|
|
97
|
-
// Base CI/CD Target
|
|
98
|
-
// ---------------------------------------------------------------------------
|
|
99
|
-
export class BaseCICDTarget extends BaseExportTarget {
|
|
100
|
-
async generateMultiWorkflow(_workflows, _options) {
|
|
101
|
-
throw new Error('CI/CD targets use generate() with AST, not generateMultiWorkflow()');
|
|
102
|
-
}
|
|
103
|
-
async generateNodeTypeService(_nodeTypes, _options) {
|
|
104
|
-
throw new Error('CI/CD targets do not export node types as services');
|
|
105
|
-
}
|
|
106
|
-
async generateBundle(_workflows, _nodeTypes, _options) {
|
|
107
|
-
throw new Error('CI/CD targets use generate() with AST, not generateBundle()');
|
|
108
|
-
}
|
|
109
|
-
// ---------------------------------------------------------------------------
|
|
110
|
-
// Shared CI/CD Logic
|
|
111
|
-
// ---------------------------------------------------------------------------
|
|
112
|
-
resolveActionMapping(step, targetName) {
|
|
113
|
-
const deployConfig = step.nodeTypeDeploy?.[targetName];
|
|
114
|
-
if (deployConfig) {
|
|
115
|
-
return {
|
|
116
|
-
githubAction: deployConfig.action,
|
|
117
|
-
githubWith: deployConfig.with
|
|
118
|
-
? (typeof deployConfig.with === 'string'
|
|
119
|
-
? JSON.parse(deployConfig.with)
|
|
120
|
-
: deployConfig.with)
|
|
121
|
-
: undefined,
|
|
122
|
-
gitlabScript: deployConfig.script
|
|
123
|
-
? (Array.isArray(deployConfig.script)
|
|
124
|
-
? deployConfig.script
|
|
125
|
-
: deployConfig.script.split('\n'))
|
|
126
|
-
: undefined,
|
|
127
|
-
gitlabImage: deployConfig.image,
|
|
128
|
-
label: deployConfig.label || step.name,
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
return NODE_ACTION_MAP[step.nodeType]
|
|
132
|
-
|| NODE_ACTION_MAP[step.nodeType.replace(/([A-Z])/g, '-$1').toLowerCase()];
|
|
133
|
-
}
|
|
134
|
-
buildJobGraph(ast) {
|
|
135
|
-
const nodeTypeLookup = new Map();
|
|
136
|
-
for (const nt of ast.nodeTypes) {
|
|
137
|
-
nodeTypeLookup.set(nt.name, nt);
|
|
138
|
-
if (nt.functionName !== nt.name)
|
|
139
|
-
nodeTypeLookup.set(nt.functionName, nt);
|
|
140
|
-
}
|
|
141
|
-
const jobMap = new Map();
|
|
142
|
-
const defaultRunner = ast.options?.cicd?.runner;
|
|
143
|
-
for (const inst of ast.instances) {
|
|
144
|
-
const jobName = inst.job || 'default';
|
|
145
|
-
if (!jobMap.has(jobName))
|
|
146
|
-
jobMap.set(jobName, []);
|
|
147
|
-
jobMap.get(jobName).push(inst);
|
|
148
|
-
}
|
|
149
|
-
const nodeJob = new Map();
|
|
150
|
-
for (const inst of ast.instances) {
|
|
151
|
-
nodeJob.set(inst.id, inst.job || 'default');
|
|
152
|
-
}
|
|
153
|
-
const jobDeps = new Map();
|
|
154
|
-
for (const conn of ast.connections) {
|
|
155
|
-
if (conn.from.node.startsWith('secret:'))
|
|
156
|
-
continue;
|
|
157
|
-
if (conn.from.node === 'Start' || conn.to.node === 'Exit')
|
|
158
|
-
continue;
|
|
159
|
-
const fromJob = nodeJob.get(conn.from.node);
|
|
160
|
-
const toJob = nodeJob.get(conn.to.node);
|
|
161
|
-
if (fromJob && toJob && fromJob !== toJob) {
|
|
162
|
-
if (!jobDeps.has(toJob))
|
|
163
|
-
jobDeps.set(toJob, new Set());
|
|
164
|
-
jobDeps.get(toJob).add(fromJob);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
const jobs = [];
|
|
168
|
-
for (const [jobId, instances] of jobMap) {
|
|
169
|
-
const environment = instances.find((i) => i.environment)?.environment;
|
|
170
|
-
const steps = instances.map((inst) => {
|
|
171
|
-
const nt = nodeTypeLookup.get(inst.nodeType);
|
|
172
|
-
return {
|
|
173
|
-
id: inst.id,
|
|
174
|
-
name: inst.config?.label || inst.id,
|
|
175
|
-
nodeType: inst.nodeType,
|
|
176
|
-
...(nt?.deploy && { nodeTypeDeploy: nt.deploy }),
|
|
177
|
-
};
|
|
178
|
-
});
|
|
179
|
-
const needs = jobDeps.get(jobId)
|
|
180
|
-
? Array.from(jobDeps.get(jobId))
|
|
181
|
-
: [];
|
|
182
|
-
jobs.push({
|
|
183
|
-
id: jobId,
|
|
184
|
-
name: jobId,
|
|
185
|
-
runner: defaultRunner,
|
|
186
|
-
needs,
|
|
187
|
-
steps,
|
|
188
|
-
environment,
|
|
189
|
-
secrets: [],
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
// Apply @job configs
|
|
193
|
-
const jobConfigs = ast.options?.cicd?.jobs;
|
|
194
|
-
if (jobConfigs) {
|
|
195
|
-
for (const jc of jobConfigs) {
|
|
196
|
-
const job = jobs.find(j => j.id === jc.id);
|
|
197
|
-
if (!job)
|
|
198
|
-
continue;
|
|
199
|
-
if (jc.retry !== undefined)
|
|
200
|
-
job.retry = jc.retry;
|
|
201
|
-
if (jc.allowFailure !== undefined)
|
|
202
|
-
job.allowFailure = jc.allowFailure;
|
|
203
|
-
if (jc.timeout)
|
|
204
|
-
job.timeout = jc.timeout;
|
|
205
|
-
if (jc.variables)
|
|
206
|
-
job.variables = { ...job.variables, ...jc.variables };
|
|
207
|
-
if (jc.tags)
|
|
208
|
-
job.tags = jc.tags;
|
|
209
|
-
if (jc.beforeScript)
|
|
210
|
-
job.beforeScript = jc.beforeScript;
|
|
211
|
-
if (jc.rules)
|
|
212
|
-
job.rules = jc.rules;
|
|
213
|
-
if (jc.coverage)
|
|
214
|
-
job.coverage = jc.coverage;
|
|
215
|
-
if (jc.reports)
|
|
216
|
-
job.reports = jc.reports;
|
|
217
|
-
if (jc.runner)
|
|
218
|
-
job.runner = jc.runner;
|
|
219
|
-
if (jc.extends)
|
|
220
|
-
job.extends = jc.extends;
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
// Apply @stage assignments
|
|
224
|
-
const stages = ast.options?.cicd?.stages;
|
|
225
|
-
if (stages && stages.length > 0) {
|
|
226
|
-
const depthMap = this.computeJobDepths(jobs);
|
|
227
|
-
// Match ALL jobs by name prefix to stages, not just configured ones
|
|
228
|
-
for (const job of jobs) {
|
|
229
|
-
if (!job.stage) {
|
|
230
|
-
for (const s of stages) {
|
|
231
|
-
if (job.id === s.name || job.id.startsWith(s.name + '-') || job.id.startsWith(s.name + '_')) {
|
|
232
|
-
job.stage = s.name;
|
|
233
|
-
break;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
for (const job of jobs) {
|
|
239
|
-
if (!job.stage) {
|
|
240
|
-
const depth = depthMap.get(job.id) || 0;
|
|
241
|
-
job.stage = stages[Math.min(depth, stages.length - 1)].name;
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
// Apply workflow-level defaults
|
|
246
|
-
const cicd = ast.options?.cicd;
|
|
247
|
-
if (cicd) {
|
|
248
|
-
for (const job of jobs) {
|
|
249
|
-
if (cicd.variables && !job.variables) {
|
|
250
|
-
job.variables = { ...cicd.variables };
|
|
251
|
-
}
|
|
252
|
-
if (cicd.beforeScript && !job.beforeScript) {
|
|
253
|
-
job.beforeScript = [...cicd.beforeScript];
|
|
254
|
-
}
|
|
255
|
-
if (cicd.tags && !job.tags) {
|
|
256
|
-
job.tags = [...cicd.tags];
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
return this.topoSortJobs(jobs);
|
|
261
|
-
}
|
|
262
|
-
topoSortJobs(jobs) {
|
|
263
|
-
const jobMap = new Map(jobs.map((j) => [j.id, j]));
|
|
264
|
-
const visited = new Set();
|
|
265
|
-
const sorted = [];
|
|
266
|
-
function visit(id) {
|
|
267
|
-
if (visited.has(id))
|
|
268
|
-
return;
|
|
269
|
-
visited.add(id);
|
|
270
|
-
const job = jobMap.get(id);
|
|
271
|
-
if (!job)
|
|
272
|
-
return;
|
|
273
|
-
for (const dep of job.needs) {
|
|
274
|
-
visit(dep);
|
|
275
|
-
}
|
|
276
|
-
sorted.push(job);
|
|
277
|
-
}
|
|
278
|
-
for (const job of jobs) {
|
|
279
|
-
visit(job.id);
|
|
280
|
-
}
|
|
281
|
-
return sorted;
|
|
282
|
-
}
|
|
283
|
-
computeJobDepths(jobs) {
|
|
284
|
-
const depths = new Map();
|
|
285
|
-
function depth(jobId, visited) {
|
|
286
|
-
if (depths.has(jobId))
|
|
287
|
-
return depths.get(jobId);
|
|
288
|
-
if (visited.has(jobId))
|
|
289
|
-
return 0;
|
|
290
|
-
visited.add(jobId);
|
|
291
|
-
const job = jobs.find(j => j.id === jobId);
|
|
292
|
-
if (!job || job.needs.length === 0) {
|
|
293
|
-
depths.set(jobId, 0);
|
|
294
|
-
return 0;
|
|
295
|
-
}
|
|
296
|
-
const maxDep = Math.max(...job.needs.map(n => depth(n, visited)));
|
|
297
|
-
const d = maxDep + 1;
|
|
298
|
-
depths.set(jobId, d);
|
|
299
|
-
return d;
|
|
300
|
-
}
|
|
301
|
-
for (const job of jobs) {
|
|
302
|
-
depth(job.id, new Set());
|
|
303
|
-
}
|
|
304
|
-
return depths;
|
|
305
|
-
}
|
|
306
|
-
resolveJobSecrets(jobs, ast, renderSecretRef) {
|
|
307
|
-
const nodeJob = new Map();
|
|
308
|
-
for (const inst of ast.instances) {
|
|
309
|
-
nodeJob.set(inst.id, inst.job || 'default');
|
|
310
|
-
}
|
|
311
|
-
const stepMap = new Map();
|
|
312
|
-
for (const job of jobs) {
|
|
313
|
-
for (const step of job.steps) {
|
|
314
|
-
stepMap.set(step.id, step);
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
for (const conn of ast.connections) {
|
|
318
|
-
if (!conn.from.node.startsWith('secret:'))
|
|
319
|
-
continue;
|
|
320
|
-
const secretName = conn.from.node.substring(7);
|
|
321
|
-
const targetNode = conn.to.node;
|
|
322
|
-
const targetPort = conn.to.port;
|
|
323
|
-
const jobId = nodeJob.get(targetNode);
|
|
324
|
-
if (!jobId)
|
|
325
|
-
continue;
|
|
326
|
-
const job = jobs.find((j) => j.id === jobId);
|
|
327
|
-
if (!job)
|
|
328
|
-
continue;
|
|
329
|
-
if (!job.secrets.includes(secretName)) {
|
|
330
|
-
job.secrets.push(secretName);
|
|
331
|
-
}
|
|
332
|
-
const step = stepMap.get(targetNode);
|
|
333
|
-
if (step) {
|
|
334
|
-
step.env = step.env || {};
|
|
335
|
-
step.env[targetPort.replace(/([A-Z])/g, '_$1').toUpperCase().replace(/^_/, '')] =
|
|
336
|
-
renderSecretRef(secretName);
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
injectArtifactSteps(jobs, artifacts) {
|
|
341
|
-
if (artifacts.length === 0)
|
|
342
|
-
return;
|
|
343
|
-
for (const job of jobs) {
|
|
344
|
-
if (job.needs.length === 0)
|
|
345
|
-
continue;
|
|
346
|
-
const neededJobs = jobs.filter((j) => job.needs.includes(j.id));
|
|
347
|
-
for (const needed of neededJobs) {
|
|
348
|
-
const jobArtifacts = artifacts.filter((a) => !a.name || needed.steps.some((s) => s.nodeType === a.name));
|
|
349
|
-
if (jobArtifacts.length > 0) {
|
|
350
|
-
needed.uploadArtifacts = (needed.uploadArtifacts || []).concat(jobArtifacts);
|
|
351
|
-
job.downloadArtifacts = (job.downloadArtifacts || []).concat(jobArtifacts.map((a) => a.name));
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
generateSecretsDoc(secrets, platform) {
|
|
357
|
-
if (secrets.length === 0)
|
|
358
|
-
return '';
|
|
359
|
-
const lines = [
|
|
360
|
-
'# Secrets Setup Guide',
|
|
361
|
-
'',
|
|
362
|
-
`This workflow requires ${secrets.length} secret(s) to be configured.`,
|
|
363
|
-
'',
|
|
364
|
-
];
|
|
365
|
-
for (const secret of secrets) {
|
|
366
|
-
lines.push(`## ${secret.name}`);
|
|
367
|
-
if (secret.description) {
|
|
368
|
-
lines.push(`> ${secret.description}`);
|
|
369
|
-
}
|
|
370
|
-
lines.push('');
|
|
371
|
-
if (platform === 'github-actions' || secret.platform === 'all' || secret.platform === 'github' || !secret.platform) {
|
|
372
|
-
lines.push('**GitHub Actions:**');
|
|
373
|
-
lines.push('1. Go to your repository on GitHub');
|
|
374
|
-
lines.push('2. Navigate to Settings > Secrets and variables > Actions');
|
|
375
|
-
lines.push('3. Click "New repository secret"');
|
|
376
|
-
lines.push(`4. Name: \`${secret.name}\``);
|
|
377
|
-
lines.push('5. Paste your secret value and click "Add secret"');
|
|
378
|
-
lines.push('');
|
|
379
|
-
}
|
|
380
|
-
if (platform === 'gitlab-ci' || secret.platform === 'all' || secret.platform === 'gitlab' || !secret.platform) {
|
|
381
|
-
lines.push('**GitLab CI:**');
|
|
382
|
-
lines.push('1. Go to your project on GitLab');
|
|
383
|
-
lines.push('2. Navigate to Settings > CI/CD > Variables');
|
|
384
|
-
lines.push('3. Click "Add variable"');
|
|
385
|
-
lines.push(`4. Key: \`${secret.name}\``);
|
|
386
|
-
lines.push('5. Paste your secret value');
|
|
387
|
-
lines.push('6. Check "Mask variable" and optionally "Protect variable"');
|
|
388
|
-
lines.push('7. Click "Add variable"');
|
|
389
|
-
lines.push('');
|
|
390
|
-
}
|
|
391
|
-
lines.push('---');
|
|
392
|
-
lines.push('');
|
|
393
|
-
}
|
|
394
|
-
return lines.join('\n');
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
//# sourceMappingURL=base-target.js.map
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CI/CD Workflow Detection
|
|
3
|
-
*
|
|
4
|
-
* Determines whether a workflow is a CI/CD pipeline based on annotations.
|
|
5
|
-
* A workflow is CI/CD if it has any CI/CD-specific annotations:
|
|
6
|
-
* @secret, @runner, @cache, @artifact, @environment, @matrix, @service,
|
|
7
|
-
* @concurrency, [job: "..."], or CI/CD trigger types (push, pull_request, etc.)
|
|
8
|
-
*/
|
|
9
|
-
import type { TWorkflowAST } from '../../ast/types.js';
|
|
10
|
-
/**
|
|
11
|
-
* Check if a workflow is a CI/CD pipeline.
|
|
12
|
-
*
|
|
13
|
-
* Detection signals (any one is sufficient):
|
|
14
|
-
* 1. Workflow options contain CI/CD fields (secrets, runner, caches, etc.)
|
|
15
|
-
* 2. Any node instance has a `job` attribute
|
|
16
|
-
* 3. Workflow has cicdTriggers
|
|
17
|
-
*/
|
|
18
|
-
export declare function isCICDWorkflow(ast: TWorkflowAST): boolean;
|
|
19
|
-
/**
|
|
20
|
-
* Get all unique job names from a CI/CD workflow.
|
|
21
|
-
* Returns empty array if no jobs are defined.
|
|
22
|
-
*/
|
|
23
|
-
export declare function getJobNames(ast: TWorkflowAST): string[];
|
|
24
|
-
/**
|
|
25
|
-
* Get all declared secret names from a CI/CD workflow.
|
|
26
|
-
*/
|
|
27
|
-
export declare function getDeclaredSecrets(ast: TWorkflowAST): string[];
|
|
28
|
-
/**
|
|
29
|
-
* Get all secret:NAME references from connections.
|
|
30
|
-
* Returns array of secret names that are wired via @connect.
|
|
31
|
-
*/
|
|
32
|
-
export declare function getReferencedSecrets(ast: TWorkflowAST): string[];
|
|
33
|
-
//# sourceMappingURL=detection.d.ts.map
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CI/CD Workflow Detection
|
|
3
|
-
*
|
|
4
|
-
* Determines whether a workflow is a CI/CD pipeline based on annotations.
|
|
5
|
-
* A workflow is CI/CD if it has any CI/CD-specific annotations:
|
|
6
|
-
* @secret, @runner, @cache, @artifact, @environment, @matrix, @service,
|
|
7
|
-
* @concurrency, [job: "..."], or CI/CD trigger types (push, pull_request, etc.)
|
|
8
|
-
*/
|
|
9
|
-
/**
|
|
10
|
-
* Check if a workflow is a CI/CD pipeline.
|
|
11
|
-
*
|
|
12
|
-
* Detection signals (any one is sufficient):
|
|
13
|
-
* 1. Workflow options contain CI/CD fields (secrets, runner, caches, etc.)
|
|
14
|
-
* 2. Any node instance has a `job` attribute
|
|
15
|
-
* 3. Workflow has cicdTriggers
|
|
16
|
-
*/
|
|
17
|
-
export function isCICDWorkflow(ast) {
|
|
18
|
-
// Check CI/CD domain annotations
|
|
19
|
-
const cicd = ast.options?.cicd;
|
|
20
|
-
if (cicd) {
|
|
21
|
-
if (cicd.secrets && cicd.secrets.length > 0)
|
|
22
|
-
return true;
|
|
23
|
-
if (cicd.runner)
|
|
24
|
-
return true;
|
|
25
|
-
if (cicd.caches && cicd.caches.length > 0)
|
|
26
|
-
return true;
|
|
27
|
-
if (cicd.artifacts && cicd.artifacts.length > 0)
|
|
28
|
-
return true;
|
|
29
|
-
if (cicd.environments && cicd.environments.length > 0)
|
|
30
|
-
return true;
|
|
31
|
-
if (cicd.matrix)
|
|
32
|
-
return true;
|
|
33
|
-
if (cicd.services && cicd.services.length > 0)
|
|
34
|
-
return true;
|
|
35
|
-
if (cicd.concurrency)
|
|
36
|
-
return true;
|
|
37
|
-
if (cicd.triggers && cicd.triggers.length > 0)
|
|
38
|
-
return true;
|
|
39
|
-
if (cicd.jobs && cicd.jobs.length > 0)
|
|
40
|
-
return true;
|
|
41
|
-
if (cicd.variables && Object.keys(cicd.variables).length > 0)
|
|
42
|
-
return true;
|
|
43
|
-
if (cicd.beforeScript && cicd.beforeScript.length > 0)
|
|
44
|
-
return true;
|
|
45
|
-
if (cicd.tags && cicd.tags.length > 0)
|
|
46
|
-
return true;
|
|
47
|
-
if (cicd.includes && cicd.includes.length > 0)
|
|
48
|
-
return true;
|
|
49
|
-
if (cicd.stages && cicd.stages.length > 0)
|
|
50
|
-
return true;
|
|
51
|
-
}
|
|
52
|
-
// Check node-level CI/CD annotations
|
|
53
|
-
if (ast.instances.some((inst) => inst.job))
|
|
54
|
-
return true;
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Get all unique job names from a CI/CD workflow.
|
|
59
|
-
* Returns empty array if no jobs are defined.
|
|
60
|
-
*/
|
|
61
|
-
export function getJobNames(ast) {
|
|
62
|
-
const jobs = new Set();
|
|
63
|
-
for (const inst of ast.instances) {
|
|
64
|
-
if (inst.job)
|
|
65
|
-
jobs.add(inst.job);
|
|
66
|
-
}
|
|
67
|
-
return Array.from(jobs);
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Get all declared secret names from a CI/CD workflow.
|
|
71
|
-
*/
|
|
72
|
-
export function getDeclaredSecrets(ast) {
|
|
73
|
-
return (ast.options?.cicd?.secrets || []).map((s) => s.name);
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Get all secret:NAME references from connections.
|
|
77
|
-
* Returns array of secret names that are wired via @connect.
|
|
78
|
-
*/
|
|
79
|
-
export function getReferencedSecrets(ast) {
|
|
80
|
-
const secrets = new Set();
|
|
81
|
-
for (const conn of ast.connections) {
|
|
82
|
-
if (conn.from.node.startsWith('secret:')) {
|
|
83
|
-
secrets.add(conn.from.node.substring(7)); // strip "secret:" prefix
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
return Array.from(secrets);
|
|
87
|
-
}
|
|
88
|
-
//# sourceMappingURL=detection.js.map
|