This is an automated email from the ASF dual-hosted git repository.

treblereel pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-tools.git


The following commit(s) were added to refs/heads/main by this push:
     new b3d25948766 kie-issues#2718: [kn-plugin-workflow] Minify the openAPI 
spec files to trim components/schemas (#2749)
b3d25948766 is described below

commit b3d259487660d3604ad238b3fe1c4fa7077d0f00
Author: Dmitrii Tikhomirov <trebler...@users.noreply.github.com>
AuthorDate: Wed Jan 8 09:39:36 2025 -0800

    kie-issues#2718: [kn-plugin-workflow] Minify the openAPI spec files to trim 
components/schemas (#2749)
    
    Co-authored-by: Dmitrii Tikhomirov <treblereel@Dmitriis-MacBook-Pro.local>
---
 .../pkg/specs/openapi_minifier.go                  |  78 ++++-
 .../pkg/specs/openapi_minifier_test.go             | 226 ++++++++++++---
 .../kn-plugin-workflow/pkg/specs/ref_collector.go  | 190 ++++++++++++
 .../pkg/specs/testdata/refs/emptyworkflow.sw.yaml  |  29 ++
 .../testdata/refs/openapi-subflow34.expected.yaml  | 115 ++++++++
 .../pkg/specs/testdata/refs/openapi.expected.yaml  | 186 ++++++++++++
 .../pkg/specs/testdata/refs/openapi.yaml           | 320 +++++++++++++++++++++
 .../pkg/specs/testdata/refs/openapi1.expected.yaml |  42 +++
 .../pkg/specs/testdata/refs/openapi1.yaml          |  75 +++++
 .../pkg/specs/testdata/refs/openapi2.expected.yaml |  36 +++
 .../pkg/specs/testdata/refs/openapi2.yaml          |  64 +++++
 .../pkg/specs/testdata/refs/subflow1.sw.yaml       |  21 ++
 .../pkg/specs/testdata/refs/subflow2.sw.yaml       |  21 ++
 .../pkg/specs/testdata/refs/subflow3.sw.yaml       |  21 ++
 .../pkg/specs/testdata/refs/subflow4.sw.yaml       |  21 ++
 .../pkg/specs/testdata/refs/workflow.sw.yaml       |  38 +++
 .../pkg/specs/testdata/refs/workflow1.sw.yaml      |  34 +++
 17 files changed, 1456 insertions(+), 61 deletions(-)

diff --git a/packages/kn-plugin-workflow/pkg/specs/openapi_minifier.go 
b/packages/kn-plugin-workflow/pkg/specs/openapi_minifier.go
index 4fe7ef0747c..0d3f1a6e0e2 100644
--- a/packages/kn-plugin-workflow/pkg/specs/openapi_minifier.go
+++ b/packages/kn-plugin-workflow/pkg/specs/openapi_minifier.go
@@ -27,6 +27,7 @@ import (
        "os"
        "path"
        "path/filepath"
+       "reflect"
        "strings"
 
        
"github.com/apache/incubator-kie-tools/packages/kn-plugin-workflow/pkg/common"
@@ -158,22 +159,9 @@ func (m *OpenApiMinifier) minifySpecsFile(specFileName 
string, operations sets.S
                return "", fmt.Errorf("❌ ERROR: failed to read OpenAPI 
document: %w", err)
        }
 
-       doc, err := openapi3.NewLoader().LoadFromData(data)
+       doc, err := m.removeUnusedNodes(data, specFile, operations)
        if err != nil {
-               return "", fmt.Errorf("❌ ERROR: failed to load OpenAPI 
document: %w", err)
-       }
-       if doc.Paths == nil {
-               return "", fmt.Errorf("OpenAPI document %s has no paths", 
specFileName)
-       }
-       for key, value := range doc.Paths.Map() {
-               for method, operation := range value.Operations() {
-                       if !operations.Has(operation.OperationID) {
-                               value.SetOperation(method, nil)
-                       }
-               }
-               if isPathItemEmpty(value) {
-                       doc.Paths.Delete(key)
-               }
+               return "", err
        }
 
        minifiedFile, err := m.writeMinifiedFileToDisk(specFile, doc)
@@ -194,6 +182,66 @@ func (m *OpenApiMinifier) minifySpecsFile(specFileName 
string, operations sets.S
        return minifiedFile, nil
 }
 
+func (m *OpenApiMinifier) removeUnusedNodes(data []byte, specFileName string, 
operations sets.Set[string]) (*openapi3.T, error) {
+       doc, err := openapi3.NewLoader().LoadFromData(data)
+
+       collector, err := newCollector(specFileName)
+       if err != nil {
+               return nil, err
+       }
+
+       keep, err := collector.collect(operations)
+       if err != nil {
+               return nil, err
+       }
+
+       if err != nil {
+               return nil, fmt.Errorf("❌ ERROR: failed to load OpenAPI 
document: %w", err)
+       }
+       if doc.Paths == nil {
+               return nil, fmt.Errorf("OpenAPI document %s has no paths", 
specFileName)
+       }
+       for key, value := range doc.Paths.Map() {
+               for method, operation := range value.Operations() {
+                       if !operations.Has(operation.OperationID) {
+                               value.SetOperation(method, nil)
+                       }
+               }
+               if isPathItemEmpty(value) {
+                       doc.Paths.Delete(key)
+               }
+       }
+
+       if doc.Components != nil {
+               // note we have to skip securitySchemes, because it aren't 
referenced by operation directly via $ref
+               components := map[string]interface{}{
+                       "schemas":       doc.Components.Schemas,
+                       "headers":       doc.Components.Headers,
+                       "parameters":    doc.Components.Parameters,
+                       "responses":     doc.Components.Responses,
+                       "requestBodies": doc.Components.RequestBodies,
+                       "examples":      doc.Components.Examples,
+                       "links":         doc.Components.Links,
+                       "callbacks":     doc.Components.Callbacks,
+               }
+
+               for key, componentMap := range components {
+                       if componentMap == nil {
+                               continue
+                       }
+
+                       componentValue := reflect.ValueOf(componentMap)
+                       for _, name := range componentValue.MapKeys() {
+                               nameStr := name.String()
+                               if !keep["components"][key].Has(nameStr) {
+                                       componentValue.SetMapIndex(name, 
reflect.Value{})
+                               }
+                       }
+               }
+       }
+       return doc, nil
+}
+
 func (m *OpenApiMinifier) findWorkflowFile() error {
        file, err := common.FindSonataFlowFile(workflowExtensionsType)
        if err != nil {
diff --git a/packages/kn-plugin-workflow/pkg/specs/openapi_minifier_test.go 
b/packages/kn-plugin-workflow/pkg/specs/openapi_minifier_test.go
index b3be4bfc93e..05ba5d7335b 100644
--- a/packages/kn-plugin-workflow/pkg/specs/openapi_minifier_test.go
+++ b/packages/kn-plugin-workflow/pkg/specs/openapi_minifier_test.go
@@ -24,6 +24,7 @@ import (
        "io"
        "os"
        "path"
+       "reflect"
        "strings"
        "testing"
 
@@ -36,6 +37,7 @@ import (
 
 type spec struct {
        file     string
+       expected string
        initial  int
        minified int
 }
@@ -51,30 +53,30 @@ type minifyTest struct {
 func TestOpenAPIMinify(t *testing.T) {
        tests := []minifyTest{
                {
-                       workflowFile:     "testdata/workflow.sw.yaml",          
         // 4 functions, 2 of them are ref to the same openapi spec
-                       openapiSpecFiles: 
[]spec{{"testdata/flink-openapi.yaml", 5, 3}}, // 5 operations, 3 must left
+                       workflowFile:     "testdata/workflow.sw.yaml",          
                                  // 4 functions, 2 of them are ref to the same 
openapi spec
+                       openapiSpecFiles: []spec{{file: 
"testdata/flink-openapi.yaml", initial: 5, minified: 3}}, // 5 operations, 3 
must left
                        specsDir:         "specs",
                        subflowsDir:      "subflows",
                },
                {
-                       workflowFile:     "testdata/workflow.sw.json",          
         // 4 functions, 2 of them are ref to the same openapi spec
-                       openapiSpecFiles: 
[]spec{{"testdata/flink-openapi.yaml", 5, 3}}, // 5 operations, 3 must left
+                       workflowFile:     "testdata/workflow.sw.json",          
                                  // 4 functions, 2 of them are ref to the same 
openapi spec
+                       openapiSpecFiles: []spec{{file: 
"testdata/flink-openapi.yaml", initial: 5, minified: 3}}, // 5 operations, 3 
must left
                        specsDir:         "specs",
                        subflowsDir:      "subflows",
                },
                {
-                       workflowFile:     
"testdata/workflow-json-openapi.sw.json",           // 4 functions, 2 of them 
are ref to the same openapi spec
-                       openapiSpecFiles: 
[]spec{{"testdata/flink-openapi-json.json", 5, 3}}, // 5 operations, 3 must left
+                       workflowFile:     
"testdata/workflow-json-openapi.sw.json",                                    // 
4 functions, 2 of them are ref to the same openapi spec
+                       openapiSpecFiles: []spec{{file: 
"testdata/flink-openapi-json.json", initial: 5, minified: 3}}, // 5 operations, 
3 must left
                        specsDir:         "specs",
                        subflowsDir:      "subflows",
                },
                {
                        workflowFile: "testdata/workflow2.sw.yaml", // 4 
functions, 1 per openapi spec file
                        openapiSpecFiles: []spec{
-                               {"testdata/flink1-openapi.yaml", 3, 1},
-                               {"testdata/flink2-openapi.yaml", 3, 1},
-                               {"testdata/flink3-openapi.yaml", 3, 1},
-                               {"testdata/flink4-openapi.yaml", 3, 1}},
+                               {file: "testdata/flink1-openapi.yaml", initial: 
3, minified: 1},
+                               {file: "testdata/flink2-openapi.yaml", initial: 
3, minified: 1},
+                               {file: "testdata/flink3-openapi.yaml", initial: 
3, minified: 1},
+                               {file: "testdata/flink4-openapi.yaml", initial: 
3, minified: 1}},
                        specsDir:    "specs",
                        subflowsDir: "subflows",
                },
@@ -86,26 +88,26 @@ func TestOpenAPIMinify(t *testing.T) {
                },
                {
                        workflowFile:     "testdata/workflow-empty.sw.yaml", // 
check all operations are removed
-                       openapiSpecFiles: 
[]spec{{"testdata/flink-openapi.yaml", 5, 0}},
+                       openapiSpecFiles: []spec{{file: 
"testdata/flink-openapi.yaml", initial: 5, minified: 0}},
                        specsDir:         "specs",
                        subflowsDir:      "subflows",
                },
                {
                        workflowFile:     
"testdata/workflow-mySpecsDir.sw.yaml", // check all operations are removed, 
with different specs dir
-                       openapiSpecFiles: 
[]spec{{"testdata/flink-openapi.yaml", 5, 3}},
+                       openapiSpecFiles: []spec{{file: 
"testdata/flink-openapi.yaml", initial: 5, minified: 3}},
                        specsDir:         "mySpecsDir",
                        subflowsDir:      "subflows",
                },
                {
                        workflowFile:     
"testdata/workflow-mySpecsDir-one-finction.sw.yaml", // check all operations 
are removed, with different specs dir
-                       openapiSpecFiles: 
[]spec{{"testdata/flink-openapi.yaml", 5, 2}},
+                       openapiSpecFiles: []spec{{file: 
"testdata/flink-openapi.yaml", initial: 5, minified: 2}},
                        specsDir:         "mySpecsDir",
                        subflowsDir:      "subflows",
                        subflows:         
[]string{"testdata/subflow-mySpecsDir.sw.yaml"},
                },
                {
                        workflowFile:     "testdata/workflow-empty.sw.yaml", // 
check all operations are removed, with different subflow dir
-                       openapiSpecFiles: 
[]spec{{"testdata/flink-openapi.yaml", 5, 0}},
+                       openapiSpecFiles: []spec{{file: 
"testdata/flink-openapi.yaml", initial: 5, minified: 0}},
                        specsDir:         "mySpecsDir",
                        subflowsDir:      "subflows",
                },
@@ -117,35 +119,35 @@ func TestOpenAPIMinify(t *testing.T) {
                },
                {
                        workflowFile:     "testdata/workflow-empty2.sw.yaml", 
// check functions is on subflow
-                       openapiSpecFiles: 
[]spec{{"testdata/flink-openapi.yaml", 5, 2}},
+                       openapiSpecFiles: []spec{{file: 
"testdata/flink-openapi.yaml", initial: 5, minified: 2}},
                        specsDir:         "specs",
                        subflowsDir:      "subflows",
                        subflows:         []string{"testdata/subflow.sw.yaml"},
                },
                {
                        workflowFile:     "testdata/workflow-empty2.sw.yaml", 
// check functions is on subflow, with different subflow and specs dirs
-                       openapiSpecFiles: 
[]spec{{"testdata/flink-openapi.yaml", 5, 2}},
+                       openapiSpecFiles: []spec{{file: 
"testdata/flink-openapi.yaml", initial: 5, minified: 2}},
                        specsDir:         "mySpecsDir",
                        subflowsDir:      "mySubFlowDir",
                        subflows:         
[]string{"testdata/subflow-mySpecsDir.sw.yaml"},
                },
                {
-                       workflowFile:     "testdata/workflow-greeting.sw.yaml", 
// check we can process subflows with the same file name but different 
extensions
-                       openapiSpecFiles: []spec{{"testdata/greetingAPI.yaml", 
3, 1}},
+                       workflowFile:     "testdata/workflow-greeting.sw.yaml", 
// check we can process subflows with the same file name but different 
extensions
+                       openapiSpecFiles: []spec{{file: 
"testdata/greetingAPI.yaml", initial: 3, minified: 1}},
                        specsDir:         "specs",
                        subflowsDir:      "custom_subflows",
                        subflows:         []string{"testdata/hello.sw.json", 
"testdata/hello.sw.yaml"}, // 2 subflows, 1 of them has a function that uses 
the greetingAPI.yaml
                },
                {
-                       workflowFile:     "testdata/workflow-greeting.sw.yaml", 
// check we can process subflows with the same file name but different 
extensions
-                       openapiSpecFiles: 
[]spec{{"testdata/flink-openapi.yaml", 5, 2}},
+                       workflowFile:     "testdata/workflow-greeting.sw.yaml", 
// check we can process subflows with the same file name but different 
extensions
+                       openapiSpecFiles: []spec{{file: 
"testdata/flink-openapi.yaml", initial: 5, minified: 2}},
                        specsDir:         "custom_specs",
                        subflowsDir:      "custom_subflows",
                        subflows:         
[]string{"testdata/subflow-custom.sw.json", "testdata/subflow-custom.sw.yaml"}, 
// 2 subflows, each one has a function that uses the flink-openapi.yaml
                },
                {
-                       workflowFile:     
"testdata/workflow-subflow-custom.sw.yaml", // workflow with a function that 
uses a subflow with a function that uses the flink-openapi.yaml
-                       openapiSpecFiles: 
[]spec{{"testdata/flink-openapi.yaml", 5, 3}},
+                       workflowFile:     
"testdata/workflow-subflow-custom.sw.yaml", // workflow with a function that 
uses a subflow with a function that uses the flink-openapi.yaml
+                       openapiSpecFiles: []spec{{file: 
"testdata/flink-openapi.yaml", initial: 5, minified: 3}},
                        specsDir:         "custom_specs",
                        subflowsDir:      "custom_subflows",
                        subflows:         
[]string{"testdata/subflow-custom.sw.json", "testdata/subflow-custom.sw.yaml"}, 
// 2 subflows, each one has a function that uses the flink-openapi.yaml
@@ -159,30 +161,8 @@ func TestOpenAPIMinify(t *testing.T) {
 
        for _, test := range tests {
                t.Run(test.workflowFile, func(t *testing.T) {
-                       if err := os.Mkdir(test.specsDir, 0755); err != nil {
-                               t.Fatalf("Error creating specs directory: %v", 
err)
-                       }
-                       defer os.RemoveAll(test.specsDir)
-                       if err := copyFile(test.workflowFile, 
path.Base(test.workflowFile)); err != nil {
-                               t.Fatalf("Error copying workflow file: %v", err)
-                       }
-                       defer os.Remove(path.Base(test.workflowFile))
-                       if len(test.subflows) > 0 {
-                               if err := os.Mkdir(test.subflowsDir, 0755); err 
!= nil {
-                                       t.Fatalf("Error creating subflows 
directory: %v", err)
-                               }
-                               defer os.RemoveAll(test.subflowsDir)
-                               for _, subflow := range test.subflows {
-                                       if err := copyFile(subflow, 
path.Join(test.subflowsDir, path.Base(subflow))); err != nil {
-                                               t.Fatalf("Error copying subflow 
file: %v", err)
-                                       }
-                               }
-                       }
-                       for _, openapiSpecFile := range test.openapiSpecFiles {
-                               if err := copyFile(openapiSpecFile.file, 
path.Join(test.specsDir, path.Base(openapiSpecFile.file))); err != nil {
-                                       t.Fatalf("Error copying openapi spec 
file: %v", err)
-                               }
-                       }
+                       prepareStructure(t, test)
+                       defer cleanUp(t, test)
 
                        minifiedfiles, err := NewMinifier(&OpenApiMinifierOpts{
                                SpecsDir:    path.Join(current, test.specsDir),
@@ -197,6 +177,160 @@ func TestOpenAPIMinify(t *testing.T) {
        }
 }
 
+// These tests contain openapi specs with $ref to other specs
+func TestOpenAPIMinifyRefs(t *testing.T) {
+       tests := []minifyTest{
+               {
+                       workflowFile:     "testdata/refs/workflow.sw.yaml",
+                       openapiSpecFiles: []spec{{file: 
"testdata/refs/openapi.yaml", expected: "testdata/refs/openapi.expected.yaml", 
initial: 5, minified: 3}},
+                       specsDir:         "specs",
+                       subflowsDir:      "subflows",
+               },
+               {
+                       workflowFile:     "testdata/refs/workflow.sw.yaml",
+                       openapiSpecFiles: []spec{{file: 
"testdata/refs/openapi.yaml", expected: "testdata/refs/openapi.expected.yaml", 
initial: 5, minified: 3}},
+                       specsDir:         "my_specs",
+                       subflowsDir:      "subflows",
+               },
+               {
+                       workflowFile:     "testdata/refs/emptyworkflow.sw.yaml",
+                       openapiSpecFiles: []spec{{file: 
"testdata/refs/openapi1.yaml", expected: 
"testdata/refs/openapi1.expected.yaml", initial: 1, minified: 1},
+                                                    {file: 
"testdata/refs/openapi2.yaml", expected: 
"testdata/refs/openapi2.expected.yaml", initial: 1, minified: 1}},
+                       specsDir:         "specs",
+                       subflowsDir:      "subflows",
+               },
+               {
+                       workflowFile:     "testdata/refs/emptyworkflow.sw.yaml",
+                       openapiSpecFiles: []spec{{file: 
"testdata/refs/openapi1.yaml", expected: 
"testdata/refs/openapi1.expected.yaml", initial: 1, minified: 1},
+                                                    {file: 
"testdata/refs/openapi2.yaml", expected: 
"testdata/refs/openapi2.expected.yaml", initial: 1, minified: 1}},
+                       specsDir:         "my_specs",
+                       subflowsDir:      "subflows",
+               },
+               {
+                       workflowFile:     "testdata/refs/emptyworkflow.sw.yaml",
+                       openapiSpecFiles: []spec{{file: 
"testdata/refs/openapi1.yaml", expected: 
"testdata/refs/openapi1.expected.yaml", initial: 1, minified: 1},
+                                                    {file: 
"testdata/refs/openapi2.yaml", expected: 
"testdata/refs/openapi2.expected.yaml", initial: 1, minified: 1}},
+                       specsDir:         "my_specs",
+                       subflowsDir:      "custom_specs",
+                       subflows:         
[]string{"testdata/refs//subflow2.sw.yaml", "testdata/refs/subflow2.sw.yaml"}, 
// 2 subflows, each one has a function that uses the flink-openapi.yaml
+               },
+               {
+                       workflowFile:     "testdata/refs/emptyworkflow.sw.yaml",
+                       openapiSpecFiles: []spec{{file: 
"testdata/refs/openapi.yaml", expected: 
"testdata/refs/openapi-subflow34.expected.yaml", initial: 5, minified: 2}},
+                       specsDir:         "specs",
+                       subflowsDir:      "custom_specs",
+                       subflows:         
[]string{"testdata/refs//subflow3.sw.yaml", "testdata/refs/subflow4.sw.yaml"}, 
// 2 subflows, each one has a function that uses the flink-openapi.yaml
+               },
+       }
+
+       current, err := os.Getwd()
+       if err != nil {
+               t.Fatalf("Error getting current directory: %v", err)
+       }
+
+       for _, test := range tests {
+               t.Run(test.workflowFile, func(t *testing.T) {
+                       prepareStructure(t, test)
+                       defer cleanUp(t, test)
+
+                       minifiedfiles, err := NewMinifier(&OpenApiMinifierOpts{
+                               SpecsDir:    path.Join(current, test.specsDir),
+                               SubflowsDir: path.Join(current, 
test.subflowsDir),
+                       }).Minify()
+
+                       if err != nil {
+                               t.Fatalf("Error minifying openapi specs: %v", 
err)
+                       }
+                       testFiles := map[string]spec{}
+
+                       for _, spec := range test.openapiSpecFiles {
+                               testFiles[path.Base(spec.file)] = spec
+                       }
+
+                       for k, v := range minifiedfiles {
+                               expected := testFiles[k].expected
+                               assert.Nil(t, validateOpenAPISpec(v), "Minified 
file %s is not a valid OpenAPI spec", v)
+                               assert.True(t, compareYAMLFiles(t, v, 
expected), "Minified file %s is not equal to the expected file %s", v, expected)
+                       }
+               })
+       }
+}
+
+func validateOpenAPISpec(filePath string) error {
+       loader := openapi3.NewLoader()
+       doc, err := loader.LoadFromFile(filePath)
+       if err != nil {
+               return fmt.Errorf("failed to load OpenAPI spec from file: %v", 
err)
+       }
+
+       if err := doc.Validate(loader.Context); err != nil {
+               return fmt.Errorf("OpenAPI spec is invalid: %v", err)
+       }
+       return nil
+}
+
+func compareYAMLFiles(t *testing.T, file1Path, file2Path string) bool {
+       data1, err := os.ReadFile(file1Path)
+       if err != nil {
+               t.Fatalf("failed to read file %s: %v", file1Path, err)
+       }
+
+       data2, err := os.ReadFile(file2Path)
+       if err != nil {
+               t.Fatalf("failed to read file %s: %v", file2Path, err)
+       }
+
+       var obj1, obj2 interface{}
+       if err := yaml.Unmarshal(data1, &obj1); err != nil {
+               t.Fatalf("failed to unmarshal file %s: %v", file1Path, err)
+       }
+       if err := yaml.Unmarshal(data2, &obj2); err != nil {
+               t.Fatalf("failed to unmarshal file %s: %v", file2Path, err)
+       }
+
+       return reflect.DeepEqual(obj1, obj2)
+}
+
+func prepareStructure(t *testing.T, test minifyTest) {
+       if err := os.Mkdir(test.specsDir, 0755); err != nil {
+               t.Fatalf("Error creating specs directory: %v", err)
+       }
+       if err := copyFile(test.workflowFile, path.Base(test.workflowFile)); 
err != nil {
+               t.Fatalf("Error copying workflow file: %v", err)
+       }
+       if len(test.subflows) > 0 {
+               if err := os.Mkdir(test.subflowsDir, 0755); err != nil {
+                       t.Fatalf("Error creating subflows directory: %v", err)
+               }
+               for _, subflow := range test.subflows {
+                       if err := copyFile(subflow, path.Join(test.subflowsDir, 
path.Base(subflow))); err != nil {
+                               t.Fatalf("Error copying subflow file: %v", err)
+                       }
+               }
+       }
+       for _, openapiSpecFile := range test.openapiSpecFiles {
+               if err := copyFile(openapiSpecFile.file, 
path.Join(test.specsDir, path.Base(openapiSpecFile.file))); err != nil {
+                       t.Fatalf("Error copying openapi spec file: %v", err)
+               }
+       }
+}
+
+func cleanUp(t *testing.T, test minifyTest) {
+       err := os.Remove(path.Base(test.workflowFile))
+       if err != nil {
+               t.Fatalf("Error removing workflow file: %v", err)
+       }
+       err = os.RemoveAll(test.specsDir)
+       if err != nil {
+               t.Fatalf("Error removing specs directory: %v", err)
+       }
+       err = os.RemoveAll(test.subflowsDir)
+       if err != nil {
+               t.Fatalf("Error removing subflows directory: %v", err)
+       }
+
+}
+
 // checkInitial checks the initial number of operations in the openapi specs
 func checkInitial(t *testing.T, test minifyTest) {
        for _, spec := range test.openapiSpecFiles {
diff --git a/packages/kn-plugin-workflow/pkg/specs/ref_collector.go 
b/packages/kn-plugin-workflow/pkg/specs/ref_collector.go
new file mode 100644
index 00000000000..90011103c2b
--- /dev/null
+++ b/packages/kn-plugin-workflow/pkg/specs/ref_collector.go
@@ -0,0 +1,190 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+package specs
+
+import (
+       "fmt"
+       "gopkg.in/yaml.v3"
+       "k8s.io/apimachinery/pkg/util/sets"
+       "os"
+       "strings"
+)
+
+type collector struct {
+       filename string
+       refs     sets.Set[string]
+       doc      map[string]any
+}
+
+type node struct {
+       section    string
+       subsection string
+       object     string
+}
+
+func newCollector(file string) (*collector, error) {
+       data, err := os.ReadFile(file)
+       if err != nil {
+               return nil, fmt.Errorf("❌ ERROR: failed to read OpenAPI spec 
file %s: %w", file, err)
+       }
+
+       m := make(map[string]any)
+       err = yaml.Unmarshal(data, &m)
+       if err != nil {
+               return nil, fmt.Errorf("❌ ERROR: failed to unmarshal OpenAPI 
spec file %s: %w", file, err)
+       }
+
+       return &collector{filename: file, doc: m, refs: sets.Set[string]{}}, nil
+}
+
+func (c *collector) collect(operations sets.Set[string]) 
(map[string]map[string]sets.Set[string], error) {
+       for operation := range operations {
+               operationNode, err := c.findByOperationId(operation, c.doc)
+               if err != nil {
+                       return nil, err
+               }
+               mapEntry(operationNode.(map[string]interface{}), c.refs)
+       }
+       visited, err := c.collectDependentRefs()
+       if err != nil {
+               return nil, fmt.Errorf("❌ ERROR: failed to collect dependent 
refs in OpenAPI spec file %s: %w", c.filename, err)
+       }
+
+       preserve := map[string]map[string]sets.Set[string]{}
+       for ref := range visited {
+               node, err := c.parseRef(ref)
+               if err != nil {
+                       return nil, fmt.Errorf("❌ ERROR: failed to parse ref at 
OpenAPI spec file %s: %w", c.filename, err)
+               }
+               if preserve[node.section] == nil {
+                       preserve[node.section] = map[string]sets.Set[string]{}
+               }
+               if preserve[node.section][node.subsection] == nil {
+                       preserve[node.section][node.subsection] = 
sets.Set[string]{}
+               }
+               preserve[node.section][node.subsection].Insert(node.object)
+       }
+       return preserve, nil
+}
+
+func (c *collector) collectDependentRefs() (sets.Set[string], error) {
+       var visited = sets.Set[string]{}
+       for c.refs.Len() > 0 {
+               operation, _ := c.refs.PopAny()
+               if !visited.Has(operation) {
+                       visited.Insert(operation)
+                       var current = sets.Set[string]{}
+                       node, err := c.findByRefObject(operation, c.doc)
+                       if err != nil {
+                               return nil, err
+                       }
+                       mapEntry(node, current)
+                       for current.Len() > 0 {
+                               operation, _ := current.PopAny()
+                               if !visited.Has(operation) {
+                                       c.refs.Insert(operation)
+                               }
+                       }
+               }
+       }
+       return visited, nil
+}
+
+func (c *collector) parseRef(ref string) (node, error) {
+       if !strings.HasPrefix(ref, "#/") {
+               return node{}, fmt.Errorf("invalid $ref: %s, must start with #/ 
at OpenAPI spec file %s", ref, c.filename)
+       }
+       parts := strings.Split(ref, "/")
+       if len(parts) < 4 {
+               return node{}, fmt.Errorf("invalid $ref %s at OpenAPI spec file 
%s", ref, c.filename)
+       }
+       return node{section: parts[1], subsection: parts[2], object: parts[3]}, 
nil
+}
+
+func (c *collector) findByRefObject(ref string, m map[string]interface{}) 
(map[string]interface{}, error) {
+       parsedRef, err := c.parseRef(ref)
+       if err != nil {
+               return nil, err
+       }
+       section, ok := m[parsedRef.section].(map[string]interface{})
+       if !ok {
+               return nil, fmt.Errorf("OpenAPI spec file %s has no such 
section: %s", c.filename, ref)
+       }
+       subsection, ok := section[parsedRef.subsection].(map[string]interface{})
+       if !ok {
+               return nil, fmt.Errorf("OpenAPI spec file %s has no such 
subsection: %s", c.filename, ref)
+       }
+       object, ok := subsection[parsedRef.object].(map[string]interface{})
+       if !ok {
+               return nil, fmt.Errorf("OpenAPI spec file %s has no such 
object: %s", c.filename, ref)
+       }
+
+       return object, nil
+}
+
+func (c *collector) findByOperationId(operationId string, m 
map[string]interface{}) (any, error) {
+       paths, ok := m["paths"].(map[string]interface{})
+       if !ok {
+               return nil, fmt.Errorf("OpenAPI spec file %s has no paths", 
c.filename)
+       }
+       for _, pathItem := range paths {
+               operations, ok := pathItem.(map[string]interface{})
+               if !ok {
+                       continue
+               }
+               for _, operationDetails := range operations {
+                       operation, ok := 
operationDetails.(map[string]interface{})
+                       if !ok {
+                               continue
+                       }
+                       if operation["operationId"] == operationId {
+                               return operation, nil
+                       }
+               }
+       }
+       return nil, fmt.Errorf("operationId %s not found at OpenAPI spec file 
%s", operationId, c.filename)
+}
+
+func entry(e any, refs sets.Set[string]) {
+       switch v := e.(type) {
+       case map[string]interface{}:
+               mapEntry(v, refs)
+       case []interface{}:
+               sliceEntry(v, refs)
+       default:
+               return
+       }
+}
+
+func sliceEntry(s []interface{}, refs sets.Set[string]) {
+       for _, v := range s {
+               entry(v, refs)
+       }
+}
+
+func mapEntry(m map[string]interface{}, refs sets.Set[string]) {
+       for k, v := range m {
+               if k == "$ref" {
+                       refs.Insert(v.(string))
+                       continue
+               }
+               entry(v, refs)
+       }
+}
diff --git 
a/packages/kn-plugin-workflow/pkg/specs/testdata/refs/emptyworkflow.sw.yaml 
b/packages/kn-plugin-workflow/pkg/specs/testdata/refs/emptyworkflow.sw.yaml
new file mode 100644
index 00000000000..bd4c84d6c89
--- /dev/null
+++ b/packages/kn-plugin-workflow/pkg/specs/testdata/refs/emptyworkflow.sw.yaml
@@ -0,0 +1,29 @@
+id: flink-workflow
+version: "1.0"
+specVersion: "0.8"
+name: flink workflow
+description: Create a starter flink job management
+start: Get Flink Jars
+states:
+  - name: Get Flink Jars
+    type: operation
+    actionMode: sequential
+    actions:
+      - name: Get Flink Jars
+        functionRef:
+          refName: getJars
+    transition: Run Flink Job
+  - name: Run Flink Job
+    type: operation
+    actionMode: sequential
+    actions:
+      - actionDataFilter:
+          useResults: true
+        name: Run Flink Job
+        functionRef:
+          refName: runFlinkJob
+          arguments:
+            jarid: 72ecfc25-43ca-4f53-a4ee-1aaf93ac709a_flink-streaming-1.0.jar
+            entry-class: com.demo.flink.streaming.StreamingJob
+    end:
+      terminate: true
diff --git 
a/packages/kn-plugin-workflow/pkg/specs/testdata/refs/openapi-subflow34.expected.yaml
 
b/packages/kn-plugin-workflow/pkg/specs/testdata/refs/openapi-subflow34.expected.yaml
new file mode 100644
index 00000000000..2e9cf85ce25
--- /dev/null
+++ 
b/packages/kn-plugin-workflow/pkg/specs/testdata/refs/openapi-subflow34.expected.yaml
@@ -0,0 +1,115 @@
+info:
+  title: Example API
+  version: 1.0.0
+openapi: 3.0.3
+paths:
+  /items:
+    get:
+      operationId: getItems
+      parameters:
+        - in: query
+          name: filter
+          schema:
+            $ref: "#/components/schemas/FilterSchema"
+      responses:
+        "200":
+          content:
+            application/json:
+              schema:
+                items:
+                  $ref: "#/components/schemas/Item"
+                type: array
+          description: Successful response
+        "201":
+          description: Created
+          links:
+            GetItemById:
+              $ref: "#/components/links/GetItemById"
+      summary: Get a list of items
+      tags:
+        - items
+  /orders:
+    get:
+      operationId: getOrders
+      parameters:
+        - $ref: "#/components/parameters/OrderId"
+        - $ref: "#/components/parameters/Limit"
+      responses:
+        "200":
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/OrdersList"
+          description: List of orders
+          headers:
+            X-Rate-Limit-Remaining:
+              $ref: "#/components/headers/RateLimitHeader"
+      summary: Get a list of orders
+components:
+  parameters:
+    Limit:
+      description: Record limit
+      in: query
+      name: limit
+      schema:
+        type: integer
+    OrderId:
+      description: Order identifier
+      in: query
+      name: orderId
+      required: true
+      schema:
+        type: string
+  schemas:
+    FilterSchema:
+      properties:
+        category:
+          type: string
+        status:
+          type: string
+      type: object
+    Item:
+      properties:
+        id:
+          type: string
+        name:
+          type: string
+      type: object
+    Order:
+      type: object
+      properties:
+        id:
+          type: string
+        status:
+          type: string
+    OrdersList:
+      type: array
+      items:
+        $ref: "#/components/schemas/Order"
+  links:
+    GetItemById:
+      operationId: getItem
+      parameters:
+        itemId: $response.body#/id
+  headers:
+    RateLimitHeader:
+      description: Remaining request limit
+      schema:
+        type: integer
+  securitySchemes:
+    ApiKeyAuth:
+      type: apiKey
+      in: header
+      name: X-API-Key
+    OAuth2Security:
+      type: oauth2
+      flows:
+        authorizationCode:
+          authorizationUrl: https://example.com/oauth/authorize
+          tokenUrl: https://example.com/oauth/token
+          scopes:
+            read: Read access
+            write: Write access
+tags:
+  - description: Item operations
+    name: items
diff --git 
a/packages/kn-plugin-workflow/pkg/specs/testdata/refs/openapi.expected.yaml 
b/packages/kn-plugin-workflow/pkg/specs/testdata/refs/openapi.expected.yaml
new file mode 100644
index 00000000000..83ff5bd3835
--- /dev/null
+++ b/packages/kn-plugin-workflow/pkg/specs/testdata/refs/openapi.expected.yaml
@@ -0,0 +1,186 @@
+info:
+  title: Example API
+  version: 1.0.0
+openapi: 3.0.3
+paths:
+  /items:
+    get:
+      operationId: getItems
+      parameters:
+        - in: query
+          name: filter
+          schema:
+            $ref: "#/components/schemas/FilterSchema"
+      responses:
+        "200":
+          content:
+            application/json:
+              schema:
+                items:
+                  $ref: "#/components/schemas/Item"
+                type: array
+          description: Successful response
+        "201":
+          description: Created
+          links:
+            GetItemById:
+              $ref: "#/components/links/GetItemById"
+      summary: Get a list of items
+      tags:
+        - items
+  /orders:
+    get:
+      operationId: getOrders
+      parameters:
+        - $ref: "#/components/parameters/OrderId"
+        - $ref: "#/components/parameters/Limit"
+      responses:
+        "200":
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/OrdersList"
+          description: List of orders
+          headers:
+            X-Rate-Limit-Remaining:
+              $ref: "#/components/headers/RateLimitHeader"
+      summary: Get a list of orders
+    post:
+      operationId: createOrder
+      requestBody:
+        $ref: "#/components/requestBodies/CreateOrderRequest"
+      responses:
+        "201":
+          $ref: "#/components/responses/OrderCreatedResponse"
+      summary: Create a new order
+  /orders/{orderId}:
+    get:
+      operationId: getOrder
+      parameters:
+        - in: path
+          name: orderId
+          required: true
+          schema:
+            type: string
+      responses:
+        "200":
+          $ref: "#/components/responses/OrderResponse"
+        "404":
+          $ref: "#/components/responses/NotFoundResponse"
+      summary: Get order information
+components:
+  examples:
+    OrderExample:
+      summary: Order example
+      value:
+        id: "12345"
+        status: processing
+  headers:
+    RateLimitHeader:
+      description: Remaining request limit
+      schema:
+        type: integer
+  links:
+    GetItemById:
+      operationId: getItem
+      parameters:
+        itemId: $response.body#/id
+  parameters:
+    Limit:
+      description: Record limit
+      in: query
+      name: limit
+      schema:
+        type: integer
+    OrderId:
+      description: Order identifier
+      in: query
+      name: orderId
+      required: true
+      schema:
+        type: string
+  requestBodies:
+    CreateOrderRequest:
+      content:
+        application/json:
+          schema:
+            $ref: "#/components/schemas/CreateOrderSchema"
+      description: Data to create a new order
+  responses:
+    NotFoundResponse:
+      content:
+        application/json:
+          schema:
+            properties:
+              error:
+                type: string
+            type: object
+      description: Resource not found
+    OrderCreatedResponse:
+      content:
+        application/json:
+          schema:
+            properties:
+              id:
+                type: string
+            type: object
+      description: Order created
+    OrderResponse:
+      content:
+        application/json:
+          examples:
+            orderExample:
+              $ref: "#/components/examples/OrderExample"
+          schema:
+            $ref: "#/components/schemas/Order"
+      description: Order information
+  schemas:
+    CreateOrderSchema:
+      properties:
+        productId:
+          type: string
+        quantity:
+          type: integer
+      type: object
+    FilterSchema:
+      properties:
+        category:
+          type: string
+        status:
+          type: string
+      type: object
+    Item:
+      properties:
+        id:
+          type: string
+        name:
+          type: string
+      type: object
+    Order:
+      properties:
+        id:
+          type: string
+        status:
+          type: string
+      type: object
+    OrdersList:
+      items:
+        $ref: "#/components/schemas/Order"
+      type: array
+  securitySchemes:
+    ApiKeyAuth:
+      in: header
+      name: X-API-Key
+      type: apiKey
+    OAuth2Security:
+      flows:
+        authorizationCode:
+          authorizationUrl: https://example.com/oauth/authorize
+          scopes:
+            read: Read access
+            write: Write access
+          tokenUrl: https://example.com/oauth/token
+      type: oauth2
+tags:
+  - description: Item operations
+    name: items
diff --git a/packages/kn-plugin-workflow/pkg/specs/testdata/refs/openapi.yaml 
b/packages/kn-plugin-workflow/pkg/specs/testdata/refs/openapi.yaml
new file mode 100644
index 00000000000..a8370ccf447
--- /dev/null
+++ b/packages/kn-plugin-workflow/pkg/specs/testdata/refs/openapi.yaml
@@ -0,0 +1,320 @@
+openapi: 3.0.3
+info:
+  title: Example API
+  version: 1.0.0
+
+paths:
+  # 1. $ref within a parameter using a schema
+  /items:
+    get:
+      summary: Get a list of items
+      operationId: getItems
+      tags:
+        - items
+      parameters:
+        - name: filter
+          in: query
+          schema:
+            $ref: "#/components/schemas/FilterSchema"
+      responses:
+        "200":
+          description: Successful response
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/Item"
+        "201":
+          description: Created
+          links:
+            GetItemById:
+              $ref: "#/components/links/GetItemById"
+
+  # 2. $ref within response headers
+  /orders:
+    get:
+      summary: Get a list of orders
+      operationId: getOrders
+      parameters:
+        - $ref: "#/components/parameters/OrderId"
+        - $ref: "#/components/parameters/Limit"
+      responses:
+        "200":
+          description: List of orders
+          headers:
+            X-Rate-Limit-Remaining:
+              $ref: "#/components/headers/RateLimitHeader"
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/OrdersList"
+    post:
+      summary: Create a new order
+      operationId: createOrder
+      requestBody:
+        $ref: "#/components/requestBodies/CreateOrderRequest"
+      responses:
+        "201":
+          $ref: "#/components/responses/OrderCreatedResponse"
+
+  # 3. $ref within the request body schema
+  /orders/{orderId}:
+    get:
+      summary: Get order information
+      operationId: getOrder
+      parameters:
+        - name: orderId
+          in: path
+          required: true
+          schema:
+            type: string
+      responses:
+        "200":
+          $ref: "#/components/responses/OrderResponse"
+        "404":
+          $ref: "#/components/responses/NotFoundResponse"
+
+    # 4. $ref for examples in responses
+    put:
+      summary: Update an order
+      operationId: updateOrder
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/UpdateOrder"
+            examples:
+              updateExample:
+                $ref: "#/components/examples/UpdateOrderExample"
+      responses:
+        "200":
+          $ref: "#/components/responses/OrderResponse"
+
+  # 5. $ref within callbacks
+  /webhooks:
+    post:
+      summary: Set a webhook
+      operationId: setWebhook
+      requestBody:
+        $ref: "#/components/requestBodies/WebhookRequest"
+      responses:
+        "201":
+          description: Webhook set
+      callbacks:
+        onEvent:
+          $ref: "#/components/callbacks/EventCallback"
+
+  # 7. Using security schemes
+  /secure-data:
+    get:
+      summary: Get secure data
+      operationId: getSecureData
+      security:
+        - ApiKeyAuth: []
+        - OAuth2Security: ["read", "write"]
+      responses:
+        "200":
+          description: Successful response
+          content:
+            application/json:
+              schema:
+                type: object
+                properties:
+                  data:
+                    type: string
+
+components:
+  # 1. Schemas used in parameters and request bodies
+  schemas:
+    FilterSchema:
+      type: object
+      properties:
+        status:
+          type: string
+        category:
+          type: string
+    Item:
+      type: object
+      properties:
+        id:
+          type: string
+        name:
+          type: string
+    CreateOrderSchema:
+      type: object
+      properties:
+        productId:
+          type: string
+        quantity:
+          type: integer
+    UpdateOrder:
+      type: object
+      properties:
+        status:
+          type: string
+    Order:
+      type: object
+      properties:
+        id:
+          type: string
+        status:
+          type: string
+    OrdersList:
+      type: array
+      items:
+        $ref: "#/components/schemas/Order"
+    Event:
+      type: object
+      properties:
+        event:
+          type: string
+
+  # 2. Parameters
+  parameters:
+    OrderId:
+      name: orderId
+      in: query
+      description: Order identifier
+      required: true
+      schema:
+        type: string
+    Limit:
+      name: limit
+      in: query
+      description: Record limit
+      required: false
+      schema:
+        type: integer
+
+  # 3. Headers
+  headers:
+    RateLimitHeader:
+      description: Remaining request limit
+      schema:
+        type: integer
+
+  # 4. Request bodies
+  requestBodies:
+    CreateOrderRequest:
+      description: Data to create a new order
+      content:
+        application/json:
+          schema:
+            $ref: "#/components/schemas/CreateOrderSchema"
+    WebhookRequest:
+      description: Data to set a webhook
+      content:
+        application/json:
+          schema:
+            type: object
+            properties:
+              url:
+                type: string
+
+  # 6. Responses
+  responses:
+    OrderCreatedResponse:
+      description: Order created
+      content:
+        application/json:
+          schema:
+            type: object
+            properties:
+              id:
+                type: string
+    OrderCreatedResponseWithLink:
+      description: Order created
+      content:
+        application/json:
+          schema:
+            type: object
+            properties:
+              id:
+                type: string
+      links:
+        GetOrderById:
+          $ref: "#/components/links/GetOrderById"
+    OrdersResponse:
+      description: List of orders
+      headers:
+        X-Rate-Limit-Remaining:
+          $ref: "#/components/headers/RateLimitHeader"
+      content:
+        application/json:
+          schema:
+            $ref: "#/components/schemas/OrdersList"
+    OrderResponse:
+      description: Order information
+      content:
+        application/json:
+          schema:
+            $ref: "#/components/schemas/Order"
+          examples:
+            orderExample:
+              $ref: "#/components/examples/OrderExample"
+    NotFoundResponse:
+      description: Resource not found
+      content:
+        application/json:
+          schema:
+            type: object
+            properties:
+              error:
+                type: string
+
+  # 7. Examples for responses
+  examples:
+    OrderExample:
+      summary: Order example
+      value:
+        id: "12345"
+        status: "processing"
+    UpdateOrderExample:
+      summary: Order update example
+      value:
+        status: "shipped"
+
+  # 8. Callbacks
+  callbacks:
+    EventCallback:
+      "{$request.body#/callbackUrl}":
+        post:
+          summary: Event received
+          requestBody:
+            content:
+              application/json:
+                schema:
+                  $ref: "#/components/schemas/Event"
+          responses:
+            "200":
+              description: Event processed
+
+  # 9. Links
+  links:
+    GetOrderById:
+      operationId: getOrder
+      parameters:
+        orderId: "$response.body#/id"
+    GetItemById:
+      operationId: getItem
+      parameters:
+        itemId: "$response.body#/id"
+  # 10. Security schemes
+  securitySchemes:
+    ApiKeyAuth:
+      type: apiKey
+      in: header
+      name: X-API-Key
+    OAuth2Security:
+      type: oauth2
+      flows:
+        authorizationCode:
+          authorizationUrl: https://example.com/oauth/authorize
+          tokenUrl: https://example.com/oauth/token
+          scopes:
+            read: Read access
+            write: Write access
+tags:
+  - name: items
+    description: Item operations
diff --git 
a/packages/kn-plugin-workflow/pkg/specs/testdata/refs/openapi1.expected.yaml 
b/packages/kn-plugin-workflow/pkg/specs/testdata/refs/openapi1.expected.yaml
new file mode 100644
index 00000000000..7d5905f2cc9
--- /dev/null
+++ b/packages/kn-plugin-workflow/pkg/specs/testdata/refs/openapi1.expected.yaml
@@ -0,0 +1,42 @@
+openapi: 3.0.3
+info:
+  title: Example API
+  version: 1.0.0
+
+paths:
+  /items:
+    get:
+      summary: Get a list of items
+      operationId: getItems
+      tags:
+        - items
+      parameters:
+        - name: filter
+          in: query
+          schema:
+            $ref: "#/components/schemas/FilterSchema"
+      responses:
+        "200":
+          description: Successful response
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/Item"
+components:
+  schemas:
+    Item:
+      type: object
+      properties:
+        id:
+          type: integer
+        name:
+          type: string
+    FilterSchema:
+      type: object
+      properties:
+        type:
+          type: string
+        description:
+          type: string
diff --git a/packages/kn-plugin-workflow/pkg/specs/testdata/refs/openapi1.yaml 
b/packages/kn-plugin-workflow/pkg/specs/testdata/refs/openapi1.yaml
new file mode 100644
index 00000000000..3f87553a10c
--- /dev/null
+++ b/packages/kn-plugin-workflow/pkg/specs/testdata/refs/openapi1.yaml
@@ -0,0 +1,75 @@
+openapi: 3.0.3
+info:
+  title: Example API
+  version: 1.0.0
+
+paths:
+  /items:
+    get:
+      summary: Get a list of items
+      operationId: getItems
+      tags:
+        - items
+      parameters:
+        - name: filter
+          in: query
+          schema:
+            $ref: "#/components/schemas/FilterSchema"
+      responses:
+        "200":
+          description: Successful response
+          content:
+            application/json:
+              schema:
+                type: array
+                items:
+                  $ref: "#/components/schemas/Item"
+components:
+  schemas:
+    Item:
+      type: object
+      properties:
+        id:
+          type: integer
+        name:
+          type: string
+    FilterSchema:
+      type: object
+      properties:
+        type:
+          type: string
+        description:
+          type: string
+    OrdersList:
+      type: object
+      properties:
+        orders:
+          type: array
+          items:
+            $ref: "#/components/schemas/Order"
+    Order:
+      type: object
+      properties:
+        id:
+          type: integer
+
+    Jars:
+      type: object
+      properties:
+        jarid:
+          type: string
+        jarname:
+          type: string
+        jarversion:
+          type: string
+    Message:
+      type: object
+      properties:
+        message:
+          type: string
+  requestBodies:
+    HelloWorld:
+      content:
+        application/json:
+          schema:
+            $ref: "#/components/schemas/Message"
diff --git 
a/packages/kn-plugin-workflow/pkg/specs/testdata/refs/openapi2.expected.yaml 
b/packages/kn-plugin-workflow/pkg/specs/testdata/refs/openapi2.expected.yaml
new file mode 100644
index 00000000000..2d2ba09440b
--- /dev/null
+++ b/packages/kn-plugin-workflow/pkg/specs/testdata/refs/openapi2.expected.yaml
@@ -0,0 +1,36 @@
+openapi: 3.0.3
+info:
+  title: Example API
+  version: 1.0.0
+
+paths:
+  /orders:
+    get:
+      summary: Get a list of items
+      operationId: getOrders
+      responses:
+        "200":
+          description: List of orders
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/OrdersList"
+components:
+  schemas:
+    OrdersList:
+      type: object
+      properties:
+        orders:
+          type: array
+          items:
+            $ref: "#/components/schemas/Order"
+    Order:
+      type: object
+      properties:
+        id:
+          type: integer
+  securitySchemes:
+    ApiKeyAuth:
+      type: apiKey
+      in: header
+      name: X-API-Key
diff --git a/packages/kn-plugin-workflow/pkg/specs/testdata/refs/openapi2.yaml 
b/packages/kn-plugin-workflow/pkg/specs/testdata/refs/openapi2.yaml
new file mode 100644
index 00000000000..9365ac5ad22
--- /dev/null
+++ b/packages/kn-plugin-workflow/pkg/specs/testdata/refs/openapi2.yaml
@@ -0,0 +1,64 @@
+openapi: 3.0.3
+info:
+  title: Example API
+  version: 1.0.0
+
+paths:
+  /orders:
+    get:
+      summary: Get a list of items
+      operationId: getOrders
+      responses:
+        "200":
+          description: List of orders
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/OrdersList"
+
+components:
+  schemas:
+    OrdersList:
+      type: object
+      properties:
+        orders:
+          type: array
+          items:
+            $ref: "#/components/schemas/Order"
+    Order:
+      type: object
+      properties:
+        id:
+          type: integer
+  parameters:
+    OrderId:
+      name: orderId
+      in: path
+      required: true
+      schema:
+        type: integer
+    Limit:
+      name: limit
+      in: query
+      required: false
+      schema:
+        type: integer
+  links:
+    GetItemById:
+      operationId: getItemById
+  securitySchemes:
+    ApiKeyAuth:
+      type: apiKey
+      in: header
+      name: X-API-Key
+  requestBodies:
+    CreateOrderRequest:
+      content:
+        application/json:
+          schema:
+            $ref: "#/components/schemas/Order"
+  headers:
+    RateLimitHeader:
+      description: Rate limit remaining
+      schema:
+        type: integer
diff --git 
a/packages/kn-plugin-workflow/pkg/specs/testdata/refs/subflow1.sw.yaml 
b/packages/kn-plugin-workflow/pkg/specs/testdata/refs/subflow1.sw.yaml
new file mode 100644
index 00000000000..3a034500437
--- /dev/null
+++ b/packages/kn-plugin-workflow/pkg/specs/testdata/refs/subflow1.sw.yaml
@@ -0,0 +1,21 @@
+---
+id: "helloworldyaml1"
+version: "1.0"
+specVersion: "0.8"
+name: "Hello World Workflow"
+description: "JSON based hello world workflow"
+start: "Inject Hello World SubFlow"
+functions:
+  - name: getItems
+    operation: custom_specs/openapi1.yaml#getItems
+states:
+  - name: "Inject Hello World SubFlow"
+    type: "inject"
+    data:
+      greeting-subflow: "Hello World SubFlow"
+    transition: "Inject Mantra SubFlow"
+  - name: "Inject Mantra SubFlow"
+    type: "inject"
+    data:
+      mantra-subflow: "SubFlow Serverless Workflow is awesome!"
+    end: true
diff --git 
a/packages/kn-plugin-workflow/pkg/specs/testdata/refs/subflow2.sw.yaml 
b/packages/kn-plugin-workflow/pkg/specs/testdata/refs/subflow2.sw.yaml
new file mode 100644
index 00000000000..4131ae2ea1f
--- /dev/null
+++ b/packages/kn-plugin-workflow/pkg/specs/testdata/refs/subflow2.sw.yaml
@@ -0,0 +1,21 @@
+---
+id: "helloworldyaml1"
+version: "1.0"
+specVersion: "0.8"
+name: "Hello World Workflow"
+description: "JSON based hello world workflow"
+start: "Inject Hello World SubFlow"
+functions:
+  - name: getOrders
+    operation: custom_specs/openapi2.yaml#getOrders
+states:
+  - name: "Inject Hello World SubFlow"
+    type: "inject"
+    data:
+      greeting-subflow: "Hello World SubFlow"
+    transition: "Inject Mantra SubFlow"
+  - name: "Inject Mantra SubFlow"
+    type: "inject"
+    data:
+      mantra-subflow: "SubFlow Serverless Workflow is awesome!"
+    end: true
diff --git 
a/packages/kn-plugin-workflow/pkg/specs/testdata/refs/subflow3.sw.yaml 
b/packages/kn-plugin-workflow/pkg/specs/testdata/refs/subflow3.sw.yaml
new file mode 100644
index 00000000000..107c96a3951
--- /dev/null
+++ b/packages/kn-plugin-workflow/pkg/specs/testdata/refs/subflow3.sw.yaml
@@ -0,0 +1,21 @@
+---
+id: "helloworldyaml1"
+version: "1.0"
+specVersion: "0.8"
+name: "Hello World Workflow"
+description: "JSON based hello world workflow"
+start: "Inject Hello World SubFlow"
+functions:
+  - name: getItems
+    operation: specs/openapi.yaml#getItems
+states:
+  - name: "Inject Hello World SubFlow"
+    type: "inject"
+    data:
+      greeting-subflow: "Hello World SubFlow"
+    transition: "Inject Mantra SubFlow"
+  - name: "Inject Mantra SubFlow"
+    type: "inject"
+    data:
+      mantra-subflow: "SubFlow Serverless Workflow is awesome!"
+    end: true
diff --git 
a/packages/kn-plugin-workflow/pkg/specs/testdata/refs/subflow4.sw.yaml 
b/packages/kn-plugin-workflow/pkg/specs/testdata/refs/subflow4.sw.yaml
new file mode 100644
index 00000000000..7c854e30afe
--- /dev/null
+++ b/packages/kn-plugin-workflow/pkg/specs/testdata/refs/subflow4.sw.yaml
@@ -0,0 +1,21 @@
+---
+id: "helloworldyaml1"
+version: "1.0"
+specVersion: "0.8"
+name: "Hello World Workflow"
+description: "JSON based hello world workflow"
+start: "Inject Hello World SubFlow"
+functions:
+  - name: getOrders
+    operation: specs/openapi.yaml#getOrders
+states:
+  - name: "Inject Hello World SubFlow"
+    type: "inject"
+    data:
+      greeting-subflow: "Hello World SubFlow"
+    transition: "Inject Mantra SubFlow"
+  - name: "Inject Mantra SubFlow"
+    type: "inject"
+    data:
+      mantra-subflow: "SubFlow Serverless Workflow is awesome!"
+    end: true
diff --git 
a/packages/kn-plugin-workflow/pkg/specs/testdata/refs/workflow.sw.yaml 
b/packages/kn-plugin-workflow/pkg/specs/testdata/refs/workflow.sw.yaml
new file mode 100644
index 00000000000..566d18e4fcd
--- /dev/null
+++ b/packages/kn-plugin-workflow/pkg/specs/testdata/refs/workflow.sw.yaml
@@ -0,0 +1,38 @@
+id: flink-workflow
+version: "1.0"
+specVersion: "0.8"
+name: flink workflow
+description: Create a starter flink job management
+functions:
+  - name: getItems
+    operation: specs/openapi.yaml#getItems
+  - name: getOrders
+    operation: specs/openapi.yaml#getOrders
+  - name: createOrder
+    operation: specs/openapi.yaml#createOrder
+  - name: getOrder
+    operation: specs/openapi.yaml#getOrder
+start: Get Flink Jars
+states:
+  - name: Get Flink Jars
+    type: operation
+    actionMode: sequential
+    actions:
+      - name: Get Flink Jars
+        functionRef:
+          refName: getJars
+    transition: Run Flink Job
+  - name: Run Flink Job
+    type: operation
+    actionMode: sequential
+    actions:
+      - actionDataFilter:
+          useResults: true
+        name: Run Flink Job
+        functionRef:
+          refName: runFlinkJob
+          arguments:
+            jarid: 72ecfc25-43ca-4f53-a4ee-1aaf93ac709a_flink-streaming-1.0.jar
+            entry-class: com.demo.flink.streaming.StreamingJob
+    end:
+      terminate: true
diff --git 
a/packages/kn-plugin-workflow/pkg/specs/testdata/refs/workflow1.sw.yaml 
b/packages/kn-plugin-workflow/pkg/specs/testdata/refs/workflow1.sw.yaml
new file mode 100644
index 00000000000..6e7f3233236
--- /dev/null
+++ b/packages/kn-plugin-workflow/pkg/specs/testdata/refs/workflow1.sw.yaml
@@ -0,0 +1,34 @@
+id: flink-workflow
+version: "1.0"
+specVersion: "0.8"
+name: flink workflow
+description: Create a starter flink job management
+functions:
+  - name: getItems
+    operation: specs/openapi1.yaml#getItems
+  - name: getOrders
+    operation: specs/openapi2.yaml#getOrders
+start: Get Flink Jars
+states:
+  - name: Get Flink Jars
+    type: operation
+    actionMode: sequential
+    actions:
+      - name: Get Flink Jars
+        functionRef:
+          refName: getJars
+    transition: Run Flink Job
+  - name: Run Flink Job
+    type: operation
+    actionMode: sequential
+    actions:
+      - actionDataFilter:
+          useResults: true
+        name: Run Flink Job
+        functionRef:
+          refName: runFlinkJob
+          arguments:
+            jarid: 72ecfc25-43ca-4f53-a4ee-1aaf93ac709a_flink-streaming-1.0.jar
+            entry-class: com.demo.flink.streaming.StreamingJob
+    end:
+      terminate: true


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@kie.apache.org
For additional commands, e-mail: commits-h...@kie.apache.org

Reply via email to