From 896b7e2a70172bf2365d13dc88e22c0a0e48be34 Mon Sep 17 00:00:00 2001 From: Ricardo Zanini Date: Tue, 17 Sep 2024 16:07:48 -0400 Subject: [PATCH] Fix #983 - Add CTK workflow features to CI/CD validation Signed-off-by: Ricardo Zanini --- .ci/validation/package-lock.json | 27 +++++++------ .ci/validation/src/ctk.test.ts | 66 ++++++++++++++++++++++++++++++++ ctk/features/branch.feature | 1 + ctk/features/call.feature | 5 +++ ctk/features/data-flow.feature | 3 ++ ctk/features/do.feature | 1 + ctk/features/emit.feature | 1 + ctk/features/flow.feature | 2 + ctk/features/for.feature | 1 + ctk/features/raise.feature | 1 + ctk/features/set.feature | 1 + ctk/features/switch.feature | 3 ++ ctk/features/try.feature | 2 + 13 files changed, 103 insertions(+), 11 deletions(-) create mode 100644 .ci/validation/src/ctk.test.ts diff --git a/.ci/validation/package-lock.json b/.ci/validation/package-lock.json index ad60031d..3976d2eb 100644 --- a/.ci/validation/package-lock.json +++ b/.ci/validation/package-lock.json @@ -1563,12 +1563,13 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -2046,10 +2047,11 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -2315,6 +2317,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -3257,12 +3260,13 @@ "peer": true }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -3895,6 +3899,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, diff --git a/.ci/validation/src/ctk.test.ts b/.ci/validation/src/ctk.test.ts new file mode 100644 index 00000000..364567de --- /dev/null +++ b/.ci/validation/src/ctk.test.ts @@ -0,0 +1,66 @@ +/* + * Copyright 2023-Present The Serverless Workflow Specification Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { SWSchemaValidator } from "./index"; +import fs from "node:fs"; +import path from "node:path"; + +SWSchemaValidator.prepareSchemas(); + +const ctkDir = path.join(__dirname, "..", "..", "..", "ctk", "features"); + +function extractYamlBlocks(content: string): string[] { + const yamlBlockRegex = /"""yaml\s([\s\S]*?)\s"""/gm; // Match YAML blocks + let match; + const yamlBlocks: string[] = []; + + while ((match = yamlBlockRegex.exec(content)) !== null) { + yamlBlocks.push(match[1]); + } + + return yamlBlocks; +} + +const workflows = fs.readdirSync(ctkDir) + .filter((file) => file.endsWith(".feature")) + .flatMap((file) => { + const filePath = path.join(ctkDir, file); + const fileContent = fs.readFileSync(filePath, SWSchemaValidator.defaultEncoding); + + const yamlBlocks = extractYamlBlocks(fileContent); + + return yamlBlocks + .map((yamlText) => SWSchemaValidator.yamlToJSON(yamlText)) + .filter((workflow) => typeof workflow === "object") + .filter((workflow) => "document" in workflow) + .filter((workflow) => "dsl" in workflow.document) + .map((workflow) => ({ workflow, file })); + }); + +describe(`Validate workflows from .feature files`, () => { + test.each(workflows)('$workflow.document.name (from $file)', ({ workflow, file }) => { + const results = SWSchemaValidator.validateSchema(workflow); + + if (results?.errors) { + console.warn( + `Schema validation failed for workflow "${workflow.document.name}" in file "${file}" with:`, + JSON.stringify(results.errors, null, 2) + ); + } + + expect(results?.valid).toBeTruthy(); + }); +}); diff --git a/ctk/features/branch.feature b/ctk/features/branch.feature index cbd6c0e7..3fa03df4 100644 --- a/ctk/features/branch.feature +++ b/ctk/features/branch.feature @@ -11,6 +11,7 @@ Feature: Composite Task dsl: '1.0.0' namespace: default name: fork + version: '1.0.0' do: - branchWithCompete: fork: diff --git a/ctk/features/call.feature b/ctk/features/call.feature index f69ba876..f5425918 100644 --- a/ctk/features/call.feature +++ b/ctk/features/call.feature @@ -14,6 +14,7 @@ Feature: Call Task dsl: '1.0.0' namespace: default name: http-call-with-content-output + version: '1.0.0' do: - findPet: call: http @@ -42,6 +43,7 @@ Feature: Call Task dsl: '1.0.0' namespace: default name: http-call-with-response-output + version: '1.0.0' do: - getPet: call: http @@ -69,6 +71,7 @@ Feature: Call Task dsl: '1.0.0' namespace: default name: http-call-with-basic-auth + version: '1.0.0' do: - login: call: http @@ -98,6 +101,7 @@ Feature: Call Task dsl: '1.0.0' namespace: default name: openapi-call-with-content-output + version: '1.0.0' do: - findPet: call: openapi @@ -126,6 +130,7 @@ Feature: Call Task dsl: '1.0.0' namespace: default name: openapi-call-with-response-output + version: '1.0.0' do: - getPet: call: openapi diff --git a/ctk/features/data-flow.feature b/ctk/features/data-flow.feature index 289160e5..01faa9eb 100644 --- a/ctk/features/data-flow.feature +++ b/ctk/features/data-flow.feature @@ -11,6 +11,7 @@ Feature: Data Flow dsl: '1.0.0' namespace: default name: output-filtering + version: '1.0.0' do: - setPlayerId: input: @@ -38,6 +39,7 @@ Feature: Data Flow dsl: '1.0.0' namespace: default name: output-filtering + version: '1.0.0' do: - getPet: call: http @@ -66,6 +68,7 @@ Feature: Data Flow dsl: '1.0.0' namespace: default name: non-object-output + version: '1.0.0' do: - getPetById1: call: http diff --git a/ctk/features/do.feature b/ctk/features/do.feature index 8668b23e..3831e3a0 100644 --- a/ctk/features/do.feature +++ b/ctk/features/do.feature @@ -11,6 +11,7 @@ Feature: Composite Task dsl: '1.0.0' namespace: default name: do + version: '1.0.0' do: - compositeExample: do: diff --git a/ctk/features/emit.feature b/ctk/features/emit.feature index 0ec2046f..ef3a7815 100644 --- a/ctk/features/emit.feature +++ b/ctk/features/emit.feature @@ -11,6 +11,7 @@ Feature: Emit Task dsl: '1.0.0' namespace: default name: emit + version: '1.0.0' do: - emitEvent: emit: diff --git a/ctk/features/flow.feature b/ctk/features/flow.feature index d7fb90d4..b27d15a4 100644 --- a/ctk/features/flow.feature +++ b/ctk/features/flow.feature @@ -10,6 +10,7 @@ Feature: Flow Directive dsl: '1.0.0' namespace: default name: implicit-sequence + version: '1.0.0' do: - setRed: set: @@ -37,6 +38,7 @@ Feature: Flow Directive dsl: '1.0.0' namespace: default name: explicit-sequence + version: '1.0.0' do: - setRed: set: diff --git a/ctk/features/for.feature b/ctk/features/for.feature index 6ebb0d07..92cc94df 100644 --- a/ctk/features/for.feature +++ b/ctk/features/for.feature @@ -13,6 +13,7 @@ Feature: For Task dsl: '1.0.0' namespace: default name: for + version: '1.0.0' do: - loopColors: for: diff --git a/ctk/features/raise.feature b/ctk/features/raise.feature index d7bbc82e..b1ecf179 100644 --- a/ctk/features/raise.feature +++ b/ctk/features/raise.feature @@ -10,6 +10,7 @@ Feature: Raise Task dsl: '1.0.0' namespace: default name: raise-custom-error + version: '1.0.0' do: - raiseError: raise: diff --git a/ctk/features/set.feature b/ctk/features/set.feature index 1b5c9d96..56d71fd7 100644 --- a/ctk/features/set.feature +++ b/ctk/features/set.feature @@ -11,6 +11,7 @@ Feature: Set Task dsl: '1.0.0' namespace: default name: set + version: '1.0.0' do: - setShape: set: diff --git a/ctk/features/switch.feature b/ctk/features/switch.feature index 86b797a1..567398e1 100644 --- a/ctk/features/switch.feature +++ b/ctk/features/switch.feature @@ -10,6 +10,7 @@ Feature: Switch Task dsl: '1.0.0' namespace: default name: switch-match + version: '1.0.0' do: - switchColor: switch: @@ -54,6 +55,7 @@ Feature: Switch Task dsl: '1.0.0' namespace: default name: switch-default-implicit + version: '1.0.0' do: - switchColor: switch: @@ -96,6 +98,7 @@ Feature: Switch Task dsl: '1.0.0' namespace: default name: switch-default-implicit + version: '1.0.0' do: - switchColor: switch: diff --git a/ctk/features/try.feature b/ctk/features/try.feature index c28ac5c5..6ac7800c 100644 --- a/ctk/features/try.feature +++ b/ctk/features/try.feature @@ -14,6 +14,7 @@ Feature: Try Task dsl: '1.0.0' namespace: default name: try-catch-404 + version: '1.0.0' do: - tryGetPet: try: @@ -57,6 +58,7 @@ Feature: Try Task dsl: '1.0.0' namespace: default name: try-catch-503 + version: '1.0.0' do: - tryGetPet: try: