@synergenius/flowweaver-pack-gitlab-ci 0.1.1

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/LICENSE ADDED
@@ -0,0 +1,204 @@
1
+ Flow Weaver Library License
2
+
3
+ Version 2.0, February 2026
4
+
5
+ ## Quick Reference (non-binding summary)
6
+
7
+ This table is provided for convenience only. In case of any conflict between
8
+ this summary and the license terms below, the license terms control.
9
+
10
+ Permitted:
11
+
12
+ Use Who Notes
13
+ ---------------------------------------- ---------------- ----------------------------------
14
+ Install and run locally Anyone No restrictions on local use
15
+ Compile workflows Anyone CLI, programmatic, scripts
16
+ Use generated output (code, artifacts) Anyone Output is unrestricted
17
+ Run in CI/CD pipelines and build systems Anyone, any size Not considered "hosting"
18
+ Distribute copies with license notices Anyone Must include license, mark changes
19
+ Create derivative works Anyone Must retain license key checks
20
+ Host internally Orgs <= 15 All members count toward limit
21
+ Embed in internal toolchains Anyone No visual workflow authoring UI
22
+ Use inside a larger product Anyone If flow-weaver is not the primary value
23
+
24
+ Requires commercial license:
25
+
26
+ Use Notes
27
+ ---------------------------------------- ----------------------------------
28
+ Host internally Orgs > 15 people
29
+ Build visual workflow authoring tools Standalone products for workflow authoring
30
+ Offer as a hosted or managed service To third parties, at any scale
31
+ Sell products built on the software Where flow-weaver is the primary value
32
+
33
+ Never permitted:
34
+
35
+ Use Notes
36
+ ---------------------------------------- ----------------------------------
37
+ Remove or circumvent license keys Applies to software and derivatives
38
+ Remove licensing or copyright notices Must always be retained
39
+ Strip license key checks from forks Derivatives must retain protections
40
+
41
+ ---
42
+
43
+ ## Acceptance
44
+
45
+ By using the software, you agree to all of the terms and conditions below.
46
+
47
+ ## Copyright License
48
+
49
+ The licensor grants you a non-exclusive, royalty-free, worldwide,
50
+ non-sublicensable, non-transferable license to use, copy, distribute, make
51
+ available, and prepare derivative works of the software, in each case subject to
52
+ the limitations and conditions below.
53
+
54
+ ## Limitations
55
+
56
+ You may not provide the software to third parties as a hosted or managed
57
+ service, where the service provides users with access to any of the features or
58
+ functionality of the software.
59
+
60
+ You may not use the software to build, distribute, or offer any standalone
61
+ product or service whose primary purpose is providing a graphical or visual
62
+ interface for creating, editing, designing, or composing workflows. This
63
+ restriction applies whether the product is hosted, distributed, sold, or offered
64
+ free of charge. It does not apply to products that use the software internally
65
+ without exposing its workflow authoring capabilities to end users through a
66
+ graphical interface.
67
+
68
+ You may not sell the software or any product that provides, as its primary
69
+ function, capabilities supplied by the software (including workflow compilation,
70
+ parsing, validation, code generation, or diagram generation), without a separate
71
+ commercial license from the licensor. This does not restrict the sale of products
72
+ that merely incorporate the software as one component among many, where the
73
+ product's primary value comes from functionality independent of the software.
74
+
75
+ You may not move, change, disable, or circumvent the license key functionality
76
+ in the software, and you may not remove or obscure any functionality in the
77
+ software that is protected by the license key.
78
+
79
+ Derivative works must retain all license key functionality, license verification
80
+ mechanisms, and licensing notices present in the original software. Distributing
81
+ derivative works with license key protections removed, disabled, or bypassed
82
+ constitutes a violation of this license.
83
+
84
+ You may not alter, remove, or obscure any licensing, copyright, or other notices
85
+ of the licensor in the software. Any use of the licensor's trademarks is subject
86
+ to applicable law.
87
+
88
+ ## Patents
89
+
90
+ The licensor grants you a license, under any patent claims the licensor can
91
+ license, or becomes able to license, to make, have made, use, sell, offer for
92
+ sale, import and have imported the software, in each case subject to the
93
+ limitations and conditions in this license. This license does not cover any
94
+ patent claims that you cause to be infringed by modifications or additions to the
95
+ software. If you or your company make any written claim that the software
96
+ infringes or contributes to infringement of any patent, your patent license for
97
+ the software granted under these terms ends immediately. If your company makes
98
+ such a claim, your patent license ends immediately for work on behalf of your
99
+ company.
100
+
101
+ ## Notices
102
+
103
+ You must ensure that anyone who gets a copy of any part of the software from you
104
+ also gets a copy of these terms.
105
+
106
+ If you modify the software, you must include in any modified copies of the
107
+ software prominent notices stating that you have modified the software.
108
+
109
+ ## No Other Rights
110
+
111
+ These terms do not imply any licenses other than those expressly granted in
112
+ these terms.
113
+
114
+ ## Termination
115
+
116
+ If you use the software in violation of these terms, such use is not licensed,
117
+ and your licenses will automatically terminate. If the licensor provides you
118
+ with a notice of your violation, and you cease all violation of this license no
119
+ later than 30 days after you receive that notice, your licenses will be
120
+ reinstated retroactively. However, if you violate these terms after such
121
+ reinstatement, any additional violation of these terms will cause your licenses
122
+ to terminate immediately.
123
+
124
+ You may request a review of any termination by contacting the licensor in
125
+ writing within 15 days of termination. The licensor will respond within 30 days.
126
+
127
+ ## No Liability
128
+
129
+ As far as the law allows, the software comes as is, without any warranty or
130
+ condition, and the licensor will not be liable to you for any damages arising
131
+ out of these terms or the use or nature of the software, under any kind of
132
+ legal claim.
133
+
134
+ ## Governing Law
135
+
136
+ This license is governed by the laws of Portugal. Any disputes arising from or
137
+ related to this license will be submitted to the exclusive jurisdiction of the
138
+ courts of Lisbon, Portugal.
139
+
140
+ ## Definitions
141
+
142
+ The "licensor" is Ricardo Jose Horta Morais (Synergenius), and the "software"
143
+ is the software the licensor makes available under these terms.
144
+
145
+ "You" refers to the individual or entity agreeing to these terms. "Your company"
146
+ is any legal entity, sole proprietorship, or other kind of organization that you
147
+ work for, plus all organizations that have control over, are under the control
148
+ of, or are under common control with that organization. "Control" means
149
+ ownership of substantially all the assets of an entity, or the power to direct
150
+ its management and policies by vote, contract, or otherwise. Control can be
151
+ direct or indirect.
152
+
153
+ "Third parties" means any individual or entity that is not you or your company
154
+ as defined in these terms.
155
+
156
+ "Your licenses" are all the licenses granted to you for the software under these
157
+ terms. "Use" means anything you do with the software requiring one of your
158
+ licenses.
159
+
160
+ "Hosting the software" means making the software's functionality available to
161
+ users over a network as a service. Running the software in automated build
162
+ pipelines, continuous integration systems, command-line interfaces, or
163
+ development toolchains does not constitute hosting, regardless of organization
164
+ size.
165
+
166
+ ---
167
+
168
+ ADDITIONAL NOTICES
169
+
170
+ 1. Output of the Software
171
+
172
+ The output of the software, including but not limited to compiled workflows,
173
+ generated code, deployment artifacts, and any other files produced by the
174
+ software's compilation, code generation, or export features, is not considered
175
+ part of the software and may be used, copied, modified, distributed, and
176
+ sublicensed for any purpose without restriction under this license.
177
+
178
+ 2. Internal Hosting Threshold
179
+
180
+ Organizations with 15 or fewer individuals, including employees, contractors,
181
+ and affiliates, may host the software on internal infrastructure for use by
182
+ their members without restriction under this license. The count includes all
183
+ individuals in the organization, not only those who directly use the software.
184
+
185
+ Organizations with more than 15 individuals that wish to host the software,
186
+ whether on internal infrastructure or as a service, require a commercial
187
+ license.
188
+
189
+ 3. Unrestricted Use
190
+
191
+ Using the software locally, including installing, running, compiling workflows,
192
+ generating code, and producing deployment artifacts, is permitted for any
193
+ individual or organization regardless of size, subject to the Limitations above.
194
+
195
+ 4. Export Compliance
196
+
197
+ You are responsible for compliance with all applicable export and import laws
198
+ and regulations in your jurisdiction when using, distributing, or making the
199
+ software available.
200
+
201
+ 5. Commercial Licensing
202
+
203
+ For commercial licensing inquiries, partnership arrangements, or questions
204
+ about permitted use, contact support@synergenius.pt.
@@ -0,0 +1,65 @@
1
+ /**
2
+ * GitLab CI Export Target
3
+ *
4
+ * Generates .gitlab-ci.yml from a Flow Weaver CI/CD workflow.
5
+ * No FW runtime dependency — outputs native GitLab CI YAML.
6
+ *
7
+ * Key differences from GitHub Actions:
8
+ * - `stage:` instead of job `needs:` (generates `stages:` list)
9
+ * - `$CI_VARIABLE` instead of `${{ secrets.NAME }}`
10
+ * - `cache:` and `artifacts:` as native YAML keywords (no separate actions)
11
+ * - `services:` as native keyword
12
+ * - `rules:` for conditional execution
13
+ * - `environment:` as native keyword with `url:` and `when: manual` for approval
14
+ */
15
+ import { BaseCICDTarget } from '@synergenius/flow-weaver/deployment';
16
+ import type { ExportOptions, ExportArtifacts, DeployInstructions } from '@synergenius/flow-weaver/deployment';
17
+ export declare class GitLabCITarget extends BaseCICDTarget {
18
+ readonly name = "gitlab-ci";
19
+ readonly description = "GitLab CI/CD pipeline (.gitlab-ci.yml)";
20
+ readonly deploySchema: {
21
+ runner: {
22
+ type: "string";
23
+ description: string;
24
+ default: string;
25
+ };
26
+ };
27
+ readonly nodeTypeDeploySchema: {
28
+ script: {
29
+ type: "string[]";
30
+ description: string;
31
+ };
32
+ image: {
33
+ type: "string";
34
+ description: string;
35
+ };
36
+ label: {
37
+ type: "string";
38
+ description: string;
39
+ };
40
+ };
41
+ generate(options: ExportOptions): Promise<ExportArtifacts>;
42
+ getDeployInstructions(_artifacts: ExportArtifacts): DeployInstructions;
43
+ private renderPipelineYAML;
44
+ /**
45
+ * Derive stages from job dependency order.
46
+ * Jobs with no deps → stage 1, jobs depending on stage 1 → stage 2, etc.
47
+ */
48
+ private deriveStages;
49
+ /**
50
+ * Derive default image from @deploy annotations or built-in mappings.
51
+ */
52
+ private deriveDefaultImage;
53
+ /**
54
+ * Convert CI/CD triggers to GitLab CI workflow rules.
55
+ */
56
+ private renderWorkflowRules;
57
+ private renderJob;
58
+ private renderStepScript;
59
+ private renderCache;
60
+ /**
61
+ * Apply workflow-level options to jobs.
62
+ */
63
+ private applyWorkflowOptions;
64
+ }
65
+ export default GitLabCITarget;
package/dist/target.js ADDED
@@ -0,0 +1,374 @@
1
+ /**
2
+ * GitLab CI Export Target
3
+ *
4
+ * Generates .gitlab-ci.yml from a Flow Weaver CI/CD workflow.
5
+ * No FW runtime dependency — outputs native GitLab CI YAML.
6
+ *
7
+ * Key differences from GitHub Actions:
8
+ * - `stage:` instead of job `needs:` (generates `stages:` list)
9
+ * - `$CI_VARIABLE` instead of `${{ secrets.NAME }}`
10
+ * - `cache:` and `artifacts:` as native YAML keywords (no separate actions)
11
+ * - `services:` as native keyword
12
+ * - `rules:` for conditional execution
13
+ * - `environment:` as native keyword with `url:` and `when: manual` for approval
14
+ */
15
+ import { stringify as yamlStringify } from 'yaml';
16
+ import { isCICDWorkflow } from '@synergenius/flow-weaver/deployment';
17
+ import { BaseCICDTarget, } from '@synergenius/flow-weaver/deployment';
18
+ import { parseWorkflow } from '@synergenius/flow-weaver/api';
19
+ import * as path from 'path';
20
+ export class GitLabCITarget extends BaseCICDTarget {
21
+ name = 'gitlab-ci';
22
+ description = 'GitLab CI/CD pipeline (.gitlab-ci.yml)';
23
+ deploySchema = {
24
+ runner: { type: 'string', description: 'Default Docker image', default: 'ubuntu:latest' },
25
+ };
26
+ nodeTypeDeploySchema = {
27
+ script: { type: 'string[]', description: 'GitLab CI script commands' },
28
+ image: { type: 'string', description: 'Docker image override' },
29
+ label: { type: 'string', description: 'Step display name' },
30
+ };
31
+ async generate(options) {
32
+ const filePath = path.resolve(options.sourceFile);
33
+ const outputDir = path.resolve(options.outputDir);
34
+ // Parse the workflow file to get AST
35
+ const parseResult = await parseWorkflow(filePath, { nodeTypesOnly: false });
36
+ if (parseResult.errors.length > 0) {
37
+ throw new Error(`Parse errors: ${parseResult.errors.join('; ')}`);
38
+ }
39
+ const allWorkflows = parseResult.allWorkflows || [];
40
+ const targetWorkflows = options.workflowName
41
+ ? allWorkflows.filter((w) => w.name === options.workflowName || w.functionName === options.workflowName)
42
+ : allWorkflows.filter((w) => isCICDWorkflow(w));
43
+ if (targetWorkflows.length === 0) {
44
+ throw new Error('No CI/CD workflows found. Ensure workflow has CI/CD annotations (@secret, @runner, @trigger, [job:], etc.)');
45
+ }
46
+ const files = [];
47
+ for (const ast of targetWorkflows) {
48
+ // Build job graph
49
+ const jobs = this.buildJobGraph(ast);
50
+ // Resolve secrets
51
+ this.resolveJobSecrets(jobs, ast, (name) => `$${name}`);
52
+ // Inject artifacts
53
+ const artifacts = ast.options?.cicd?.artifacts || [];
54
+ this.injectArtifactSteps(jobs, artifacts);
55
+ // Apply workflow options
56
+ this.applyWorkflowOptions(jobs, ast);
57
+ // Generate YAML
58
+ const yamlContent = this.renderPipelineYAML(ast, jobs);
59
+ files.push(this.createFile(outputDir, '.gitlab-ci.yml', yamlContent, 'config'));
60
+ // Generate secrets doc if secrets exist
61
+ const secrets = ast.options?.cicd?.secrets || [];
62
+ if (secrets.length > 0) {
63
+ const secretsDoc = this.generateSecretsDoc(secrets, 'gitlab-ci');
64
+ files.push(this.createFile(outputDir, 'SECRETS_SETUP.md', secretsDoc, 'other'));
65
+ }
66
+ }
67
+ return {
68
+ files,
69
+ target: this.name,
70
+ workflowName: options.displayName || targetWorkflows[0].name,
71
+ entryPoint: files[0].relativePath,
72
+ };
73
+ }
74
+ getDeployInstructions(_artifacts) {
75
+ return {
76
+ title: 'Deploy GitLab CI Pipeline',
77
+ prerequisites: [
78
+ 'GitLab repository',
79
+ 'CI/CD variables configured (see SECRETS_SETUP.md)',
80
+ 'GitLab Runner available (shared or project-specific)',
81
+ ],
82
+ steps: [
83
+ 'Copy .gitlab-ci.yml to your repository root',
84
+ 'Configure required variables in GitLab (Settings > CI/CD > Variables)',
85
+ 'Push to trigger the pipeline',
86
+ ],
87
+ localTestSteps: [
88
+ 'Install gitlab-runner: brew install gitlab-runner',
89
+ 'Run locally: gitlab-runner exec docker <job-name>',
90
+ ],
91
+ links: [
92
+ { label: 'GitLab CI/CD Docs', url: 'https://docs.gitlab.com/ee/ci/' },
93
+ { label: 'GitLab CI Lint', url: 'https://docs.gitlab.com/ee/ci/lint.html' },
94
+ ],
95
+ };
96
+ }
97
+ // ---------------------------------------------------------------------------
98
+ // Private: YAML Rendering
99
+ // ---------------------------------------------------------------------------
100
+ renderPipelineYAML(ast, jobs) {
101
+ const doc = {};
102
+ // stages (derived from job dependency order)
103
+ const stages = this.deriveStages(jobs);
104
+ doc.stages = stages;
105
+ // Default image
106
+ const defaultImage = this.deriveDefaultImage(ast, jobs);
107
+ if (defaultImage) {
108
+ doc.default = { image: defaultImage };
109
+ }
110
+ // Workflow-level rules (from triggers)
111
+ const rules = this.renderWorkflowRules(ast.options?.cicd?.triggers || []);
112
+ if (rules.length > 0) {
113
+ doc.workflow = { rules };
114
+ }
115
+ // Job definitions
116
+ for (const job of jobs) {
117
+ doc[job.id] = this.renderJob(job, ast, stages);
118
+ }
119
+ return yamlStringify(doc, {
120
+ lineWidth: 120,
121
+ defaultStringType: 'PLAIN',
122
+ defaultKeyType: 'PLAIN',
123
+ });
124
+ }
125
+ /**
126
+ * Derive stages from job dependency order.
127
+ * Jobs with no deps → stage 1, jobs depending on stage 1 → stage 2, etc.
128
+ */
129
+ deriveStages(jobs) {
130
+ const stages = [];
131
+ const assigned = new Map();
132
+ // Assign stages based on dependency depth
133
+ function getStage(jobId, jobs) {
134
+ if (assigned.has(jobId))
135
+ return assigned.get(jobId);
136
+ const job = jobs.find((j) => j.id === jobId);
137
+ if (!job || job.needs.length === 0) {
138
+ assigned.set(jobId, jobId);
139
+ return jobId;
140
+ }
141
+ // Stage is one after the latest dependency
142
+ const depStages = job.needs.map((dep) => getStage(dep, jobs));
143
+ assigned.set(jobId, jobId);
144
+ return jobId;
145
+ }
146
+ // Simple: use job IDs as stage names, ordered by dependency
147
+ for (const job of jobs) {
148
+ getStage(job.id, jobs);
149
+ if (!stages.includes(job.id)) {
150
+ stages.push(job.id);
151
+ }
152
+ }
153
+ return stages;
154
+ }
155
+ /**
156
+ * Derive default image from @deploy annotations or built-in mappings.
157
+ */
158
+ deriveDefaultImage(_ast, jobs) {
159
+ // Check steps for @deploy gitlab-ci image or built-in mapping
160
+ for (const job of jobs) {
161
+ for (const step of job.steps) {
162
+ const mapping = this.resolveActionMapping(step, 'gitlab-ci');
163
+ if (mapping?.gitlabImage)
164
+ return mapping.gitlabImage;
165
+ }
166
+ }
167
+ return undefined;
168
+ }
169
+ /**
170
+ * Convert CI/CD triggers to GitLab CI workflow rules.
171
+ */
172
+ renderWorkflowRules(triggers) {
173
+ if (triggers.length === 0)
174
+ return [];
175
+ const rules = [];
176
+ for (const trigger of triggers) {
177
+ switch (trigger.type) {
178
+ case 'push':
179
+ if (trigger.branches) {
180
+ for (const branch of trigger.branches) {
181
+ rules.push({
182
+ if: `$CI_COMMIT_BRANCH == "${branch}"`,
183
+ when: 'always',
184
+ });
185
+ }
186
+ }
187
+ else {
188
+ rules.push({ if: '$CI_PIPELINE_SOURCE == "push"', when: 'always' });
189
+ }
190
+ break;
191
+ case 'pull_request':
192
+ rules.push({
193
+ if: '$CI_PIPELINE_SOURCE == "merge_request_event"',
194
+ when: 'always',
195
+ });
196
+ break;
197
+ case 'schedule':
198
+ rules.push({
199
+ if: '$CI_PIPELINE_SOURCE == "schedule"',
200
+ when: 'always',
201
+ });
202
+ break;
203
+ case 'dispatch':
204
+ rules.push({
205
+ if: '$CI_PIPELINE_SOURCE == "web" || $CI_PIPELINE_SOURCE == "api"',
206
+ when: 'always',
207
+ });
208
+ break;
209
+ case 'tag':
210
+ rules.push({ if: '$CI_COMMIT_TAG', when: 'always' });
211
+ break;
212
+ }
213
+ }
214
+ return rules;
215
+ }
216
+ renderJob(job, ast, stages) {
217
+ const jobObj = {};
218
+ // stage
219
+ jobObj.stage = job.id;
220
+ // image (from runner or default)
221
+ if (job.runner && job.runner !== 'ubuntu-latest') {
222
+ // GitLab uses Docker images, not runner labels
223
+ // Map common GitHub runners to Docker images
224
+ const imageMap = {
225
+ 'ubuntu-latest': 'ubuntu:latest',
226
+ 'ubuntu-22.04': 'ubuntu:22.04',
227
+ 'ubuntu-20.04': 'ubuntu:20.04',
228
+ };
229
+ const image = imageMap[job.runner] || job.runner;
230
+ jobObj.image = image;
231
+ }
232
+ // needs (for DAG mode instead of stage-based ordering)
233
+ if (job.needs.length > 0) {
234
+ jobObj.needs = job.needs;
235
+ }
236
+ // environment
237
+ if (job.environment) {
238
+ const envConfig = ast.options?.cicd?.environments?.find((e) => e.name === job.environment);
239
+ const envObj = { name: job.environment };
240
+ if (envConfig?.url)
241
+ envObj.url = envConfig.url;
242
+ if (envConfig?.reviewers)
243
+ envObj.deployment_tier = 'production';
244
+ jobObj.environment = envObj;
245
+ // Protected environments require manual approval in GitLab
246
+ if (envConfig?.reviewers) {
247
+ jobObj.when = 'manual';
248
+ }
249
+ }
250
+ // services
251
+ if (job.services && job.services.length > 0) {
252
+ jobObj.services = job.services.map((svc) => {
253
+ const svcObj = { name: svc.image };
254
+ if (svc.ports) {
255
+ // GitLab services expose the first port automatically
256
+ // Additional port mapping needs alias
257
+ }
258
+ return svcObj;
259
+ });
260
+ }
261
+ // variables (from secrets)
262
+ if (job.secrets.length > 0) {
263
+ // In GitLab, CI/CD variables are automatically available
264
+ // But we document them for clarity
265
+ const variables = {};
266
+ for (const secret of job.secrets) {
267
+ variables[secret] = `$${secret}`;
268
+ }
269
+ jobObj.variables = variables;
270
+ }
271
+ // cache
272
+ if (job.cache) {
273
+ jobObj.cache = this.renderCache(job.cache);
274
+ }
275
+ // artifacts (upload)
276
+ if (job.uploadArtifacts && job.uploadArtifacts.length > 0) {
277
+ const paths = job.uploadArtifacts.map((a) => a.path);
278
+ const expiry = job.uploadArtifacts[0].retention
279
+ ? `${job.uploadArtifacts[0].retention} days`
280
+ : '1 week';
281
+ jobObj.artifacts = {
282
+ paths,
283
+ expire_in: expiry,
284
+ };
285
+ }
286
+ // script (the actual steps)
287
+ const script = [];
288
+ // Download artifacts (GitLab handles this automatically via `needs:`)
289
+ // but we add a comment for clarity if explicit artifacts are expected
290
+ if (job.downloadArtifacts && job.downloadArtifacts.length > 0) {
291
+ script.push(`# Artifacts from: ${job.downloadArtifacts.join(', ')} (downloaded automatically via needs:)`);
292
+ }
293
+ // Step scripts
294
+ for (const step of job.steps) {
295
+ const stepScript = this.renderStepScript(step);
296
+ script.push(...stepScript);
297
+ }
298
+ jobObj.script = script;
299
+ return jobObj;
300
+ }
301
+ renderStepScript(step) {
302
+ const mapping = this.resolveActionMapping(step, 'gitlab-ci');
303
+ const lines = [];
304
+ // Add env vars as export statements if present
305
+ if (step.env) {
306
+ for (const [key, value] of Object.entries(step.env)) {
307
+ lines.push(`export ${key}="${value}"`);
308
+ }
309
+ }
310
+ if (mapping?.gitlabScript) {
311
+ lines.push(`# ${mapping.label || step.name}`);
312
+ lines.push(...mapping.gitlabScript);
313
+ }
314
+ else {
315
+ // Unknown node type — generate TODO
316
+ lines.push(`# TODO: Implement '${step.id}' (node type: ${step.nodeType})`);
317
+ lines.push(`echo "Step: ${step.name}"`);
318
+ }
319
+ return lines;
320
+ }
321
+ renderCache(cache) {
322
+ const cacheObj = {};
323
+ switch (cache.strategy) {
324
+ case 'npm':
325
+ cacheObj.key = {
326
+ files: [cache.key || 'package-lock.json'],
327
+ };
328
+ cacheObj.paths = [cache.path || 'node_modules/'];
329
+ break;
330
+ case 'pip':
331
+ cacheObj.key = {
332
+ files: [cache.key || 'requirements.txt'],
333
+ };
334
+ cacheObj.paths = [cache.path || '.pip-cache/'];
335
+ break;
336
+ default:
337
+ cacheObj.key = cache.key || '$CI_COMMIT_REF_SLUG';
338
+ cacheObj.paths = [cache.path || '.cache/'];
339
+ }
340
+ return cacheObj;
341
+ }
342
+ /**
343
+ * Apply workflow-level options to jobs.
344
+ */
345
+ applyWorkflowOptions(jobs, ast) {
346
+ const cicd = ast.options?.cicd;
347
+ if (!cicd)
348
+ return;
349
+ // Apply cache to all jobs
350
+ if (cicd.caches && cicd.caches.length > 0) {
351
+ for (const job of jobs) {
352
+ if (!job.cache) {
353
+ job.cache = cicd.caches[0];
354
+ }
355
+ }
356
+ }
357
+ // Apply services to all jobs
358
+ if (cicd.services && cicd.services.length > 0) {
359
+ for (const job of jobs) {
360
+ if (!job.services) {
361
+ job.services = cicd.services;
362
+ }
363
+ }
364
+ }
365
+ // Apply matrix (GitLab uses `parallel: matrix:`)
366
+ if (cicd.matrix) {
367
+ const rootJobs = jobs.filter((j) => j.needs.length === 0);
368
+ for (const job of rootJobs) {
369
+ job.matrix = cicd.matrix;
370
+ }
371
+ }
372
+ }
373
+ }
374
+ export default GitLabCITarget;
@@ -0,0 +1,15 @@
1
+ {
2
+ "manifestVersion": 1,
3
+ "name": "@synergenius/flowweaver-pack-gitlab-ci",
4
+ "version": "0.1.1",
5
+ "nodeTypes": [],
6
+ "workflows": [],
7
+ "patterns": [],
8
+ "exportTargets": [
9
+ {
10
+ "name": "gitlab-ci",
11
+ "description": "GitLab CI/CD pipeline generation",
12
+ "file": "dist/target.js"
13
+ }
14
+ ]
15
+ }
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@synergenius/flowweaver-pack-gitlab-ci",
3
+ "version": "0.1.1",
4
+ "description": "GitLab CI/CD export target for Flow Weaver",
5
+ "keywords": [
6
+ "flowweaver-marketplace-pack",
7
+ "flow-weaver",
8
+ "gitlab-ci",
9
+ "cicd"
10
+ ],
11
+ "flowWeaver": {
12
+ "type": "marketplace-pack",
13
+ "engineVersion": ">=0.14.0",
14
+ "categories": [
15
+ "deployment",
16
+ "cicd"
17
+ ]
18
+ },
19
+ "peerDependencies": {
20
+ "@synergenius/flow-weaver": ">=0.14.0"
21
+ },
22
+ "dependencies": {
23
+ "yaml": "^2.8.0"
24
+ },
25
+ "main": "./dist/target.js",
26
+ "types": "./dist/target.d.ts",
27
+ "type": "module",
28
+ "files": [
29
+ "dist",
30
+ "flowweaver.manifest.json",
31
+ "README.md"
32
+ ],
33
+ "scripts": {
34
+ "build": "tsc",
35
+ "prepublishOnly": "npm run build"
36
+ },
37
+ "devDependencies": {
38
+ "typescript": "^5.0.0",
39
+ "@synergenius/flow-weaver": "^0.14.2",
40
+ "@types/node": "^20.0.0"
41
+ },
42
+ "license": "SEE LICENSE IN LICENSE",
43
+ "repository": {
44
+ "type": "git",
45
+ "url": "https://github.com/synergenius-fw/flowweaver-pack-gitlab-ci.git"
46
+ }
47
+ }