Skip to content

Commit a007679

Browse files
wayneisubasinghe
authored andcommitted
fix(cli): handle multi-resource yaml in offline lint. Fixes #12137 (#13531)
Signed-off-by: Wang, Wayne <Wayne.Wang@fmr.com>
1 parent 70cdcad commit a007679

2 files changed

Lines changed: 91 additions & 30 deletions

File tree

cmd/argo/commands/lint_test.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,4 +211,65 @@ spec:
211211

212212
assert.False(t, fatal, "should not have exited")
213213
})
214+
215+
workflowMultiDocsPath := filepath.Join(subdir, "workflowMultiDocs.yaml")
216+
err = os.WriteFile(workflowMultiDocsPath, []byte(`
217+
apiVersion: argoproj.io/v1alpha1
218+
kind: WorkflowTemplate
219+
metadata:
220+
name: hello-world-template-local-arg-1
221+
spec:
222+
templates:
223+
- name: hello-world
224+
inputs:
225+
parameters:
226+
- name: msg
227+
value: 'hello world'
228+
container:
229+
image: busybox
230+
command: [echo]
231+
args: ['{{inputs.parameters.msg}}']
232+
---
233+
apiVersion: argoproj.io/v1alpha1
234+
kind: WorkflowTemplate
235+
metadata:
236+
name: hello-world-template-local-arg-2
237+
spec:
238+
templates:
239+
- name: hello-world
240+
inputs:
241+
parameters:
242+
- name: msg
243+
value: 'hello world'
244+
container:
245+
image: busybox
246+
command: [echo]
247+
args: ['{{inputs.parameters.msg}}']
248+
---
249+
apiVersion: argoproj.io/v1alpha1
250+
kind: Workflow
251+
metadata:
252+
generateName: hello-world-local-arg-
253+
spec:
254+
entrypoint: whalesay
255+
templates:
256+
- name: whalesay
257+
steps:
258+
- - name: hello-world
259+
templateRef:
260+
name: hello-world-template-local-arg-2
261+
template: hello-world
262+
`), 0644)
263+
require.NoError(t, err)
264+
265+
t.Run("linting a workflow in multi-documents yaml", func(t *testing.T) {
266+
defer func() { logrus.StandardLogger().ExitFunc = nil }()
267+
var fatal bool
268+
logrus.StandardLogger().ExitFunc = func(int) { fatal = true }
269+
err = runLint(context.Background(), []string{workflowMultiDocsPath}, true, nil, "pretty", false)
270+
271+
require.NoError(t, err)
272+
assert.False(t, fatal, "should not have exited")
273+
})
274+
214275
}

pkg/apiclient/offline-client.go

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,8 @@ import (
1212
"github.com/argoproj/argo-workflows/v3/pkg/apiclient/workflowtemplate"
1313
wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1"
1414
"github.com/argoproj/argo-workflows/v3/util/file"
15+
"github.com/argoproj/argo-workflows/v3/workflow/common"
1516
"github.com/argoproj/argo-workflows/v3/workflow/templateresolution"
16-
17-
"sigs.k8s.io/yaml"
1817
)
1918

2019
type offlineWorkflowTemplateGetterMap map[string]templateresolution.WorkflowTemplateNamespacedGetter
@@ -50,42 +49,43 @@ func newOfflineClient(paths []string) (context.Context, Client, error) {
5049

5150
for _, basePath := range paths {
5251
err := file.WalkManifests(basePath, func(path string, bytes []byte) error {
53-
var generic map[string]interface{}
54-
if err := yaml.Unmarshal(bytes, &generic); err != nil {
55-
return fmt.Errorf("failed to parse YAML from file %s: %w", path, err)
56-
}
57-
switch generic["kind"] {
58-
case "ClusterWorkflowTemplate":
59-
cwftmpl := new(wfv1.ClusterWorkflowTemplate)
60-
if err := yaml.Unmarshal(bytes, &cwftmpl); err != nil {
61-
return fmt.Errorf("failed to unmarshal file %s as a ClusterWorkflowTemplate: %w", path, err)
52+
for _, pr := range common.ParseObjects(bytes, false) {
53+
obj, err := pr.Object, pr.Err
54+
if err != nil {
55+
return fmt.Errorf("failed to parse YAML from file %s: %w", path, err)
6256
}
6357

64-
if _, ok := clusterWorkflowTemplateGetter.clusterWorkflowTemplates[cwftmpl.Name]; ok {
65-
return fmt.Errorf("duplicate ClusterWorkflowTemplate found: %q", cwftmpl.Name)
58+
if obj == nil {
59+
continue // could not parse to kubernetes object
6660
}
67-
clusterWorkflowTemplateGetter.clusterWorkflowTemplates[cwftmpl.Name] = cwftmpl
6861

69-
case "WorkflowTemplate":
70-
wftmpl := new(wfv1.WorkflowTemplate)
71-
if err := yaml.Unmarshal(bytes, &wftmpl); err != nil {
72-
return fmt.Errorf("failed to unmarshal file %s as a WorkflowTemplate: %w", path, err)
73-
}
74-
getter, ok := workflowTemplateGetters[wftmpl.Namespace]
75-
if !ok {
76-
getter = &offlineWorkflowTemplateNamespacedGetter{
77-
namespace: wftmpl.Namespace,
78-
workflowTemplates: map[string]*wfv1.WorkflowTemplate{},
62+
objName := obj.GetName()
63+
namespace := obj.GetNamespace()
64+
65+
switch v := obj.(type) {
66+
case *wfv1.ClusterWorkflowTemplate:
67+
if _, ok := clusterWorkflowTemplateGetter.clusterWorkflowTemplates[objName]; ok {
68+
return fmt.Errorf("duplicate ClusterWorkflowTemplate found: %q", objName)
69+
}
70+
clusterWorkflowTemplateGetter.clusterWorkflowTemplates[objName] = v
71+
72+
case *wfv1.WorkflowTemplate:
73+
getter, ok := workflowTemplateGetters[namespace]
74+
if !ok {
75+
getter = &offlineWorkflowTemplateNamespacedGetter{
76+
namespace: namespace,
77+
workflowTemplates: map[string]*wfv1.WorkflowTemplate{},
78+
}
79+
workflowTemplateGetters[namespace] = getter
7980
}
80-
workflowTemplateGetters[wftmpl.Namespace] = getter
81-
}
8281

83-
if _, ok := getter.(*offlineWorkflowTemplateNamespacedGetter).workflowTemplates[wftmpl.Name]; ok {
84-
return fmt.Errorf("duplicate WorkflowTemplate found: %q", wftmpl.Name)
82+
if _, ok := getter.(*offlineWorkflowTemplateNamespacedGetter).workflowTemplates[objName]; ok {
83+
return fmt.Errorf("duplicate WorkflowTemplate found: %q", objName)
84+
}
85+
getter.(*offlineWorkflowTemplateNamespacedGetter).workflowTemplates[objName] = v
8586
}
86-
getter.(*offlineWorkflowTemplateNamespacedGetter).workflowTemplates[wftmpl.Name] = wftmpl
87-
}
8887

88+
}
8989
return nil
9090
})
9191

0 commit comments

Comments
 (0)