diff --git a/engine/api/entity_search.go b/engine/api/entity_search.go index 238f5283c7..3c55e5a05b 100644 --- a/engine/api/entity_search.go +++ b/engine/api/entity_search.go @@ -334,3 +334,106 @@ func (ef *EntityFinder) searchEntity(ctx context.Context, db gorp.SqlExecutor, s } return completePath, "", nil } + +func (ef *EntityFinder) searchAction(ctx context.Context, db gorp.SqlExecutor, store cache.Store, name string) (*sdk.V2Action, string, string, error) { + // Local def + if strings.HasPrefix(name, ".cds/actions/") { + // Find action from path + localAct, has := ef.localActionsCache[name] + if !has { + actionEntity, err := entity.LoadEntityByPathAndRefAndCommit(ctx, db, ef.currentRepo.ID, name, ef.currentRef, ef.currentSha) + if err != nil { + return nil, "", fmt.Sprintf("Unable to find action %s", name), nil + } + if err := yaml.Unmarshal([]byte(actionEntity.Data), &localAct); err != nil { + return nil, "", "", err + } + ef.localActionsCache[name] = localAct + } + completeName := fmt.Sprintf("%s/%s/%s/%s@%s", ef.currentProject, ef.currentVCS.Name, ef.currentRepo.Name, localAct.Name, ef.currentRef) + return &localAct, completeName, "", nil + } + + actionName := strings.TrimPrefix(name, "actions/") + actionSplit := strings.Split(actionName, "/") + + // If plugins + if strings.HasPrefix(name, "actions/") && len(actionSplit) == 1 { + // Check plugins + if _, has := ef.plugins[actionSplit[0]]; !has { + return nil, "", fmt.Sprintf("Action %s doesn't exist", actionSplit[0]), nil + } + return nil, "", "", nil + } + + // Others + completePath, msg, err := ef.searchEntity(ctx, db, store, actionName, sdk.EntityTypeAction) + if msg != "" || err != nil { + return nil, completePath, msg, err + } + act := ef.actionsCache[completePath] + return &act, completePath, msg, err +} + +func (ef *EntityFinder) searchWorkerModel(ctx context.Context, db gorp.SqlExecutor, store cache.Store, name string) (*sdk.EntityWithObject, string, string, error) { + // Local def + if strings.HasPrefix(name, ".cds/worker-models/") { + // Find worker model from path + localWM, has := ef.localWorkerModelCache[name] + if !has { + wmEntity, err := entity.LoadEntityByPathAndRefAndCommit(ctx, db, ef.currentRepo.ID, name, ef.currentRef, ef.currentSha) + if err != nil { + return nil, "", fmt.Sprintf("Unable to find worker model %s", name), nil + } + var wm sdk.V2WorkerModel + if err := yaml.Unmarshal([]byte(wmEntity.Data), &wm); err != nil { + return nil, "", "", err + } + localWM = sdk.EntityWithObject{Entity: *wmEntity, Model: wm} + ef.localWorkerModelCache[name] = localWM + } + completeName := fmt.Sprintf("%s/%s/%s/%s@%s", ef.currentProject, ef.currentVCS.Name, ef.currentRepo.Name, localWM.Model.Name, ef.currentRef) + return &localWM, completeName, "", nil + } + + completeName, msg, err := ef.searchEntity(ctx, db, store, name, sdk.EntityTypeWorkerModel) + if err != nil { + return nil, completeName, "", err + } + if msg != "" { + return nil, completeName, msg, nil + } + wm := ef.workerModelCache[completeName] + return &wm, completeName, "", nil +} + +func (ef *EntityFinder) searchWorkflowTemplate(ctx context.Context, db gorp.SqlExecutor, store cache.Store, name string) (*sdk.EntityWithObject, string, string, error) { + if strings.HasPrefix(name, ".cds/workflow-templates/") { + // Find tempalte from path + localEntity, has := ef.localTemplatesCache[name] + if !has { + wtEntity, err := entity.LoadEntityByPathAndRefAndCommit(ctx, db, ef.currentRepo.ID, name, ef.currentRef, ef.currentSha) + if err != nil { + msg := fmt.Sprintf("Unable to find workflow template %s %s %s %s", ef.currentRepo.ID, name, ef.currentRef, ef.currentSha) + return nil, "", msg, nil + } + if err := yaml.Unmarshal([]byte(wtEntity.Data), &localEntity.Template); err != nil { + return nil, "", "", sdk.NewErrorFrom(sdk.ErrInvalidData, "unable to read workflow template %s: %v", name, err) + } + localEntity.Entity = *wtEntity + ef.localTemplatesCache[name] = localEntity + } + completeName := fmt.Sprintf("%s/%s/%s/%s@%s", ef.currentProject, ef.currentVCS.Name, ef.currentRepo.Name, localEntity.Template.Name, ef.currentRef) + return &localEntity, completeName, "", nil + } + completeName, msg, err := ef.searchEntity(ctx, db, store, name, sdk.EntityTypeWorkflowTemplate) + if err != nil { + return nil, completeName, "", err + } + if msg != "" { + return nil, completeName, msg, nil + } + e := ef.templatesCache[completeName] + return &e, completeName, "", nil + +} diff --git a/engine/api/v2_repository_analyze.go b/engine/api/v2_repository_analyze.go index d4a64bd9e6..58bd60cb70 100644 --- a/engine/api/v2_repository_analyze.go +++ b/engine/api/v2_repository_analyze.go @@ -28,6 +28,7 @@ import ( "github.com/ovh/cds/engine/api/event_v2" "github.com/ovh/cds/engine/api/link" "github.com/ovh/cds/engine/api/operation" + "github.com/ovh/cds/engine/api/plugin" "github.com/ovh/cds/engine/api/project" "github.com/ovh/cds/engine/api/rbac" "github.com/ovh/cds/engine/api/repositoriesmanager" @@ -536,6 +537,14 @@ func (api *API) analyzeRepository(ctx context.Context, projectRepoID string, ana ef := NewEntityFinder(proj.Key, analysis.Ref, analysis.Commit, *repo, *vcsProjectWithSecret, *u, analysis.Data.CDSAdminWithMFA, api.Config.WorkflowV2.LibraryProjectKey) + plugins, err := plugin.LoadAllByType(ctx, api.mustDB(), sdk.GRPCPluginAction) + if err != nil { + return err + } + for _, p := range plugins { + ef.plugins[p.Name] = p + } + // Transform file content into entities entities, multiErr := api.handleEntitiesFiles(ctx, ef, filesContent, analysis) if multiErr != nil { @@ -860,27 +869,14 @@ func manageWorkflowHooks(ctx context.Context, db gorpmapper.SqlExecutorWithTx, c // If there is a workflow template and non hooks on workflow, check the workflow template if e.Workflow.From != "" && e.Workflow.On == nil { - var wkfTmpl sdk.V2WorkflowTemplate - if strings.HasPrefix(e.Workflow.From, ".cds/") { - tmpl, err := entity.LoadEntityByPathAndRefAndCommit(ctx, db, e.ProjectRepositoryID, e.Workflow.From, e.Ref, e.Commit) - if err != nil { - return nil, err - } - if err := yaml.Unmarshal([]byte(tmpl.Data), &wkfTmpl); err != nil { - return nil, err - } - } else { - completePath, errMsg, err := ef.searchEntity(ctx, db, cache, e.Workflow.From, sdk.EntityTypeWorkflowTemplate) - if err != nil { - return nil, err - } - if errMsg != "" { - return nil, sdk.NewErrorFrom(sdk.ErrInvalidData, errMsg) - } - workflowTemplate := ef.templatesCache[completePath] - wkfTmpl = workflowTemplate.Template + entTemplate, _, msg, err := ef.searchWorkflowTemplate(ctx, db, cache, e.Workflow.From) + if err != nil { + return nil, err + } + if msg != "" { + return nil, sdk.NewErrorFrom(sdk.ErrInvalidData, msg) } - if _, err := wkfTmpl.Resolve(ctx, &e.Workflow); err != nil { + if _, err := entTemplate.Template.Resolve(ctx, &e.Workflow); err != nil { return nil, sdk.NewErrorFrom(sdk.ErrInvalidData, "unable to compute workflow from template: %v", err) } } @@ -1565,44 +1561,57 @@ func Lint[T sdk.Lintable](ctx context.Context, api *API, o T, ef *EntityFinder) case sdk.V2Workflow: switch { case x.From != "": - var tmpl *sdk.V2WorkflowTemplate - if strings.HasPrefix(x.From, ".cds/workflow-templates/") { - // Retrieve tmpl from current analysis - for _, v := range ef.templatesCache { - if v.FilePath == x.From { - tmpl = &v.Template - break - } - } - } else { - // Retrieve existing template in DB - path, msg, errSearch := ef.searchEntity(ctx, api.mustDB(), api.Cache, x.From, sdk.EntityTypeWorkflowTemplate) - if errSearch != nil { - err = append(err, sdk.NewErrorFrom(sdk.ErrWrongRequest, "unable to retrieve entity %s of type %s: %v", x.From, sdk.EntityTypeWorkflowTemplate, errSearch)) - break - } - if msg != "" { - err = append(err, sdk.NewErrorFrom(sdk.ErrWrongRequest, msg)) - break - } - t := ef.templatesCache[path].Template - tmpl = &t + entTmpl, _, msg, errSearch := ef.searchWorkflowTemplate(ctx, api.mustDB(), api.Cache, x.From) + if errSearch != nil { + err = append(err, sdk.NewErrorFrom(sdk.ErrWrongRequest, "workflow %s: unable to retrieve template %s of type %s: %v", x.Name, x.From, sdk.EntityTypeWorkflowTemplate, errSearch)) + break } - if tmpl == nil || tmpl.Name == "" { - err = append(err, sdk.NewErrorFrom(sdk.ErrWrongRequest, "unknown workflow template %s", x.From)) - } else { - // Check required parameters - for _, v := range tmpl.Parameters { - if wkfP, has := x.Parameters[v.Key]; (!has || len(wkfP) == 0) && v.Required { - err = append(err, sdk.NewErrorFrom(sdk.ErrWrongRequest, "required template parameter %s is required by template %s", v.Key, x.From)) - } + if msg != "" { + err = append(err, sdk.NewErrorFrom(sdk.ErrWrongRequest, "workflow %s: %s", x.Name, msg)) + break + } + if entTmpl == nil || entTmpl.Template.Name == "" { + err = append(err, sdk.NewErrorFrom(sdk.ErrWrongRequest, "workflow %s: unknown workflow template %s", x.Name, x.From)) + } + // Check required parameters + for _, v := range entTmpl.Template.Parameters { + if wkfP, has := x.Parameters[v.Key]; (!has || len(wkfP) == 0) && v.Required { + err = append(err, sdk.NewErrorFrom(sdk.ErrWrongRequest, "workflow %s: required template parameter %s is missing or empty", x.Name, x.From)) } } + default: sameVCS := x.Repository == nil || x.Repository.VCSServer == ef.currentVCS.Name || x.Repository.VCSServer == "" sameRepo := x.Repository == nil || x.Repository.Name == ef.currentRepo.Name || x.Repository.Name == "" if sameVCS && sameRepo && x.Repository != nil && x.Repository.InsecureSkipSignatureVerify { - err = append(err, sdk.NewErrorFrom(sdk.ErrWrongRequest, "parameter `insecure-skip-signature-verify`is not allowed if the workflow is defined on the same repository as `workfow.repository.name`. ")) + err = append(err, sdk.NewErrorFrom(sdk.ErrWrongRequest, "workflow %s: parameter `insecure-skip-signature-verify`is not allowed if the workflow is defined on the same repository as `workfow.repository.name`. ", x.Name)) + } + for _, j := range x.Jobs { + // Check if worker model exists + if !strings.Contains(j.RunsOn.Model, "${{") && len(j.Steps) > 0 { + _, _, msg, errSearch := ef.searchWorkerModel(ctx, api.mustDB(), api.Cache, j.RunsOn.Model) + if errSearch != nil { + err = append(err, errSearch) + } + if msg != "" { + err = append(err, sdk.NewErrorFrom(sdk.ErrInvalidData, "workflow %s: %s", x.Name, msg)) + } + } + + // Check if actions/plugins exists + for _, s := range j.Steps { + if s.Uses == "" { + continue + } + _, _, msg, errSearch := ef.searchAction(ctx, api.mustDB(), api.Cache, s.Uses) + if errSearch != nil { + err = append(err, errSearch) + } + if msg != "" { + err = append(err, sdk.NewErrorFrom(sdk.ErrInvalidData, msg)) + } + } + } } } @@ -1646,14 +1655,17 @@ func ReadEntityFile[T sdk.Lintable](ctx context.Context, api *API, directory, fi switch t { case sdk.EntityTypeWorkerModel: eo.Model = any(o).(sdk.V2WorkerModel) + ef.localWorkerModelCache[eo.Entity.FilePath] = eo ef.workerModelCache[fmt.Sprintf("%s/%s/%s/%s@%s", analysis.ProjectKey, ef.currentVCS.Name, ef.currentRepo.Name, eo.Model.Name, analysis.Ref)] = eo case sdk.EntityTypeAction: eo.Action = any(o).(sdk.V2Action) + ef.localActionsCache[eo.Entity.FilePath] = eo.Action ef.actionsCache[fmt.Sprintf("%s/%s/%s/%s@%s", analysis.ProjectKey, ef.currentVCS.Name, ef.currentRepo.Name, eo.Action.Name, analysis.Ref)] = eo.Action case sdk.EntityTypeWorkflow: eo.Workflow = any(o).(sdk.V2Workflow) case sdk.EntityTypeWorkflowTemplate: eo.Template = any(o).(sdk.V2WorkflowTemplate) + ef.localTemplatesCache[eo.Entity.FilePath] = eo ef.templatesCache[fmt.Sprintf("%s/%s/%s/%s@%s", analysis.ProjectKey, ef.currentVCS.Name, ef.currentRepo.Name, eo.Template.Name, analysis.Ref)] = eo } diff --git a/engine/api/v2_repository_analyze_test.go b/engine/api/v2_repository_analyze_test.go index 2e938b278a..69670b72a8 100644 --- a/engine/api/v2_repository_analyze_test.go +++ b/engine/api/v2_repository_analyze_test.go @@ -2459,7 +2459,7 @@ parameters: anal, err := repository.LoadRepositoryAnalysisById(ctx, db, repo.ID, analysis.ID) require.NoError(t, err) require.Equal(t, sdk.RepositoryAnalysisStatusError, anal.Status) - require.Equal(t, "unable to find workflow dependency: mytemplate", anal.Data.Error) + require.Equal(t, "workflow myworkflow: unable to find workflow dependency: mytemplate", anal.Data.Error) } func TestAnalyzeGithubUpdateWorkflowNoRight(t *testing.T) { api, db, _ := newTestAPI(t) @@ -2597,14 +2597,22 @@ GDFkaTe3nUJdYV4= servicesClients.EXPECT().DoJSONRequest(gomock.Any(), "POST", "/v2/repository/event/callback", gomock.Any(), gomock.Any()).AnyTimes() - wkf := ` - name: myworkflow - jobs: - root: - steps: - - run: echo toto` + wkf := `name: myworkflow +jobs: + root: + runs-on: .cds/worker-models/mymodel.yml + steps: + - run: echo toto` encodedWorkflow := base64.StdEncoding.EncodeToString([]byte(wkf)) + wm := `name: mymodel +osarch: linux/amd64 +type: docker +spec: + image: myimage` + + encodedWorkerModel := base64.StdEncoding.EncodeToString([]byte(wm)) + servicesClients.EXPECT(). DoJSONRequest(gomock.Any(), "GET", "/vcs/vcs-server/repos/myrepo/branches/?branch=devBranch&default=false&noCache=true", gomock.Any(), gomock.Any(), gomock.Any()). DoAndReturn( @@ -2642,6 +2650,10 @@ GDFkaTe3nUJdYV4= IsDirectory: true, Name: "workflows", }, + { + IsDirectory: true, + Name: "worker-models", + }, } *(out.(*[]sdk.VCSContent)) = contents return nil, 200, nil @@ -2662,6 +2674,21 @@ GDFkaTe3nUJdYV4= return nil, 200, nil }, ).MaxTimes(1) + servicesClients.EXPECT(). + DoJSONRequest(gomock.Any(), "GET", "/vcs/vcs-server/repos/myrepo/contents/.cds%2Fworker-models?commit=zyxwv&offset=0&limit=100", gomock.Any(), gomock.Any(), gomock.Any()). + DoAndReturn( + func(ctx context.Context, method, path string, in interface{}, out interface{}, _ interface{}) (http.Header, int, error) { + contents := []sdk.VCSContent{ + { + IsDirectory: false, + IsFile: true, + Name: "mymodel.yml", + }, + } + *(out.(*[]sdk.VCSContent)) = contents + return nil, 200, nil + }, + ).MaxTimes(1) servicesClients.EXPECT(). DoJSONRequest(gomock.Any(), "GET", "/vcs/vcs-server/repos/myrepo/content/.cds%2Fworkflows%2Fmyworkflow.yml?commit=zyxwv", gomock.Any(), gomock.Any(), gomock.Any()). DoAndReturn( @@ -2678,6 +2705,22 @@ GDFkaTe3nUJdYV4= }, ).MaxTimes(1) + servicesClients.EXPECT(). + DoJSONRequest(gomock.Any(), "GET", "/vcs/vcs-server/repos/myrepo/content/.cds%2Fworker-models%2Fmymodel.yml?commit=zyxwv", gomock.Any(), gomock.Any(), gomock.Any()). + DoAndReturn( + func(ctx context.Context, method, path string, in interface{}, out interface{}, _ interface{}) (http.Header, int, error) { + + content := sdk.VCSContent{ + IsDirectory: false, + IsFile: true, + Name: "mymodel.yml", + Content: encodedWorkerModel, + } + *(out.(*sdk.VCSContent)) = content + return nil, 200, nil + }, + ).MaxTimes(1) + servicesClients.EXPECT().DoJSONRequest(gomock.Any(), "GET", "/vcs/vcs-server/repos/myrepo/branches/?branch=&default=true&noCache=true", gomock.Any(), gomock.Any(), gomock.Any()).Times(1). DoAndReturn( func(ctx context.Context, method, path string, in interface{}, out interface{}, _ interface{}) (http.Header, int, error) { @@ -2694,6 +2737,7 @@ GDFkaTe3nUJdYV4= analysisUpdated, err := repository.LoadRepositoryAnalysisById(ctx, db, repo.ID, analysis.ID) require.NoError(t, err) + t.Logf(">>>>%+v", analysisUpdated.Data.Error) require.Equal(t, sdk.RepositoryAnalysisStatusSkipped, analysisUpdated.Status) entitiesNonHEad, err := entity.LoadByTypeAndRefCommit(context.TODO(), db, repo.ID, sdk.EntityTypeWorkflow, "refs/heads/devBranch", "zyxwv") diff --git a/engine/api/v2_workflow_run_craft.go b/engine/api/v2_workflow_run_craft.go index 583ce233d7..7eb9dab6e2 100644 --- a/engine/api/v2_workflow_run_craft.go +++ b/engine/api/v2_workflow_run_craft.go @@ -19,7 +19,6 @@ import ( "go.opencensus.io/trace" "github.com/ovh/cds/engine/api/database/gorpmapping" - "github.com/ovh/cds/engine/api/entity" "github.com/ovh/cds/engine/api/event_v2" "github.com/ovh/cds/engine/api/hatchery" "github.com/ovh/cds/engine/api/integration" @@ -593,60 +592,25 @@ func searchActions(ctx context.Context, db *gorp.DbMap, store cache.Store, wref continue } - if strings.HasPrefix(step.Uses, ".cds/actions/") { - // Find action from path - localAct, has := wref.ef.localActionsCache[step.Uses] - if !has { - actionEntity, err := entity.LoadEntityByPathAndRefAndCommit(ctx, db, wref.ef.currentRepo.ID, step.Uses, wref.run.WorkflowRef, wref.run.WorkflowSha) - if err != nil { - msg := sdk.V2WorkflowRunInfo{ - WorkflowRunID: wref.run.ID, - Level: sdk.WorkflowRunInfoLevelError, - Message: fmt.Sprintf("Unable to find action %s", step.Uses), - } - return &msg, nil - } - if err := yaml.Unmarshal([]byte(actionEntity.Data), &localAct); err != nil { - return nil, err - } - wref.ef.localActionsCache[step.Uses] = localAct - msg, err := searchActions(ctx, db, store, wref, localAct.Runs.Steps) - if msg != nil || err != nil { - return msg, err - } + act, completePath, msg, err := wref.ef.searchAction(ctx, db, store, step.Uses) + if err != nil { + return nil, err + } + if msg != "" { + runMsg := sdk.V2WorkflowRunInfo{ + WorkflowRunID: wref.run.ID, + Level: sdk.WorkflowRunInfoLevelError, + Message: msg, } - completeName := fmt.Sprintf("%s/%s/%s/%s@%s", wref.run.ProjectKey, wref.ef.currentVCS.Name, wref.ef.currentRepo.Name, localAct.Name, wref.run.WorkflowRef) - step.Uses = "actions/" + completeName - } else { - actionName := strings.TrimPrefix(step.Uses, "actions/") - actionSplit := strings.Split(actionName, "/") - // If plugins - if strings.HasPrefix(step.Uses, "actions/") && len(actionSplit) == 1 { - // Check plugins - if _, has := wref.ef.plugins[actionSplit[0]]; !has { - msg := sdk.V2WorkflowRunInfo{ - WorkflowRunID: wref.run.ID, - Level: sdk.WorkflowRunInfoLevelError, - Message: fmt.Sprintf("Action %s doesn't exist", actionSplit[0]), - } - return &msg, nil - } - continue - } else { - completeName, msg, err := wref.ef.searchEntity(ctx, db, store, actionName, sdk.EntityTypeAction) - if msg != "" || err != nil { - return &sdk.V2WorkflowRunInfo{WorkflowRunID: wref.run.ID, Level: sdk.WorkflowRunInfoLevelError, Message: msg}, err - } - // rewrite step with full path - step.Uses = "actions/" + completeName - act := wref.ef.actionsCache[completeName] - runInfo, err := searchActions(ctx, db, store, wref, act.Runs.Steps) - if runInfo != nil || err != nil { - return runInfo, err - } + return &runMsg, nil + } + if act != nil { + step.Uses = "actions/" + completePath + msgAction, err := searchActions(ctx, db, store, wref, act.Runs.Steps) + if msgAction != nil || err != nil { + return msgAction, err } } - } return nil, nil } @@ -1071,42 +1035,34 @@ func (wref *WorkflowRunEntityFinder) checkWorkerModel(ctx context.Context, db *g modelType := "" if workerModel != "" { - if strings.HasPrefix(workerModel, ".cds/worker-models/") { - // Find action from path - localWM, has := wref.ef.localWorkerModelCache[workerModel] - if !has { - wmEntity, err := entity.LoadEntityByPathAndRefAndCommit(ctx, db, wref.ef.currentRepo.ID, workerModel, wref.run.WorkflowRef, wref.run.WorkflowSha) - if err != nil { - msg := sdk.V2WorkflowRunInfo{ - WorkflowRunID: wref.run.ID, - Level: sdk.WorkflowRunInfoLevelError, - Message: fmt.Sprintf("Unable to find worker model %s", workerModel), - } - return "", &msg, nil - } - var wm sdk.V2WorkerModel - if err := yaml.Unmarshal([]byte(wmEntity.Data), &wm); err != nil { - return "", nil, sdk.NewErrorFrom(sdk.ErrInvalidData, "unable to read worker model %s: %v", workerModel, err) - } - localWM = sdk.EntityWithObject{Entity: *wmEntity, Model: wm} - if err := localWM.Interpolate(ctx); err != nil { - return "", nil, err - } - wref.ef.localWorkerModelCache[workerModel] = localWM - } - modelCompleteName = fmt.Sprintf("%s/%s/%s/%s@%s", wref.run.ProjectKey, wref.ef.currentVCS.Name, wref.ef.currentRepo.Name, localWM.Model.Name, wref.run.WorkflowRef) - modelType = localWM.Model.Type - } else { - completeName, msg, err := wref.ef.searchEntity(ctx, db, store, workerModel, sdk.EntityTypeWorkerModel) - if err != nil { - return "", nil, err + wm, fullName, msg, err := wref.ef.searchWorkerModel(ctx, db, store, workerModel) + if err != nil { + msg := sdk.V2WorkflowRunInfo{ + WorkflowRunID: wref.run.ID, + Level: sdk.WorkflowRunInfoLevelError, + Message: fmt.Sprintf("Unable to find worker model %s", workerModel), } - if msg != "" { - return "", &sdk.V2WorkflowRunInfo{WorkflowRunID: wref.run.ID, Level: sdk.WorkflowRunInfoLevelError, Message: msg}, nil + return "", &msg, nil + } + if msg != "" { + runMsg := sdk.V2WorkflowRunInfo{ + WorkflowRunID: wref.run.ID, + Level: sdk.WorkflowRunInfoLevelError, + Message: msg, } - modelType = wref.ef.workerModelCache[completeName].Model.Type - modelCompleteName = completeName + return "", &runMsg, nil + } + if err := wm.Interpolate(ctx); err != nil { + return "", nil, err + } + if strings.HasPrefix(workerModel, ".cds/worker-models/") { + wref.ef.localWorkerModelCache[workerModel] = *wm + } else { + wref.ef.workerModelCache[fullName] = *wm } + modelType = wm.Model.Type + modelCompleteName = fullName + } for _, h := range hatcheries { @@ -1209,37 +1165,17 @@ func (wref *WorkflowRunEntityFinder) checkWorkflowTemplate(ctx context.Context, ctx, next := telemetry.Span(ctx, "wref.checkWorkflowTemplate", trace.StringAttribute(telemetry.TagWorkflowTemplate, templateName)) defer next() - var e sdk.EntityWithObject - if strings.HasPrefix(templateName, ".cds/workflow-templates/") { - // Find action from path - localEntity, has := wref.ef.localTemplatesCache[templateName] - if !has { - wtEntity, err := entity.LoadEntityByPathAndRefAndCommit(ctx, db, wref.ef.currentRepo.ID, templateName, wref.run.WorkflowRef, wref.run.WorkflowSha) - if err != nil { - msg := sdk.V2WorkflowRunInfo{ - WorkflowRunID: wref.run.ID, - Level: sdk.WorkflowRunInfoLevelError, - Message: fmt.Sprintf("Unable to find workflow template %s %s %s %s", wref.ef.currentRepo.ID, templateName, wref.run.WorkflowRef, wref.run.WorkflowSha), - } - return e, &msg, nil - } - if err := yaml.Unmarshal([]byte(wtEntity.Data), &localEntity.Template); err != nil { - return e, nil, sdk.NewErrorFrom(sdk.ErrInvalidData, "unable to read workflow template %s: %v", templateName, err) - } - localEntity.Entity = *wtEntity - wref.ef.localTemplatesCache[templateName] = localEntity - } - e = localEntity - } else { - completeName, msg, err := wref.ef.searchEntity(ctx, db, store, templateName, sdk.EntityTypeWorkflowTemplate) - if err != nil { - return e, nil, err - } - if msg != "" { - return e, &sdk.V2WorkflowRunInfo{WorkflowRunID: wref.run.ID, Level: sdk.WorkflowRunInfoLevelError, Message: msg}, nil + e, _, msg, err := wref.ef.searchWorkflowTemplate(ctx, db, store, templateName) + if err != nil { + return sdk.EntityWithObject{}, nil, err + } + if msg != "" { + runMsg := sdk.V2WorkflowRunInfo{ + WorkflowRunID: wref.run.ID, + Level: sdk.WorkflowRunInfoLevelError, + Message: msg, } - e = wref.ef.templatesCache[completeName] + return sdk.EntityWithObject{}, &runMsg, nil } - - return e, nil, nil + return *e, nil, nil }