Skip to content

Commit

Permalink
feat(api): lock update ascode with template, workflow pull with templ…
Browse files Browse the repository at this point in the history
…ate (#5134)
  • Loading branch information
richardlt authored Apr 22, 2020
1 parent 724564e commit 0834d56
Show file tree
Hide file tree
Showing 17 changed files with 86 additions and 157 deletions.
4 changes: 2 additions & 2 deletions engine/api/environment/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func LoadEnvironmentByID(db gorp.SqlExecutor, ID int64) (*sdk.Environment, error
WHERE id = $1`
if err := db.QueryRow(query, ID).Scan(&env.ID, &env.Name, &env.ProjectID, &env.FromRepository); err != nil {
if err == sql.ErrNoRows {
return nil, sdk.ErrEnvironmentNotFound
return nil, sdk.WithStack(sdk.ErrEnvironmentNotFound)
}
return nil, err
}
Expand All @@ -99,7 +99,7 @@ func LoadEnvironmentByName(db gorp.SqlExecutor, projectKey, envName string) (*sd
var lastModified time.Time
if err := db.QueryRow(query, projectKey, envName).Scan(&env.ID, &env.Name, &env.ProjectID, &env.FromRepository, &lastModified); err != nil {
if err == sql.ErrNoRows {
return nil, sdk.ErrorWithData(sdk.ErrEnvironmentNotFound, envName)
return nil, sdk.WithData(sdk.ErrEnvironmentNotFound, envName)
}
return nil, sdk.WithStack(err)
}
Expand Down
2 changes: 1 addition & 1 deletion engine/api/pipeline/pipeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func LoadPipeline(ctx context.Context, db gorp.SqlExecutor, projectKey, name str

if err := db.SelectOne(&p, query, name, projectKey); err != nil {
if err == sql.ErrNoRows {
return nil, sdk.WithStack(sdk.ErrorWithData(sdk.ErrPipelineNotFound, name))
return nil, sdk.WithData(sdk.ErrPipelineNotFound, name)
}
return nil, sdk.WithStack(err)
}
Expand Down
17 changes: 1 addition & 16 deletions engine/api/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
"github.com/ovh/cds/engine/api/project"
"github.com/ovh/cds/engine/api/services"
"github.com/ovh/cds/engine/api/workflow"
"github.com/ovh/cds/engine/api/workflowtemplate"
"github.com/ovh/cds/engine/service"
"github.com/ovh/cds/sdk"
"github.com/ovh/cds/sdk/exportentities"
Expand Down Expand Up @@ -86,6 +85,7 @@ func (api *API) getWorkflowHandler() service.Handler {
WithLabels: withLabels,
WithAsCodeUpdateEvent: withAsCodeEvents,
WithIntegrations: true,
WithTemplate: withTemplate,
}
w1, err := workflow.Load(ctx, api.mustDB(), api.Cache, *proj, name, opts)
if err != nil {
Expand Down Expand Up @@ -113,21 +113,6 @@ func (api *API) getWorkflowHandler() service.Handler {
w1.Audits = audits
}

if withTemplate {
if err := workflowtemplate.AggregateTemplateInstanceOnWorkflow(ctx, api.mustDB(), w1); err != nil {
return err
}
if w1.TemplateInstance != nil {
if err := workflowtemplate.LoadInstanceOptions.WithTemplate(ctx, api.mustDB(), w1.TemplateInstance); err != nil {
return err
}
if w1.TemplateInstance.Template != nil {
w1.FromTemplate = fmt.Sprintf("%s@%d", w1.TemplateInstance.Template.Path(), w1.TemplateInstance.WorkflowTemplateVersion)
w1.TemplateUpToDate = w1.TemplateInstance.Template.Version == w1.TemplateInstance.WorkflowTemplateVersion
}
}
}

if isAdmin(ctx) {
w1.Permissions = sdk.Permissions{Readable: true, Writable: true, Executable: true}
} else {
Expand Down
18 changes: 16 additions & 2 deletions engine/api/workflow/dao.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/ovh/cds/engine/api/keys"
"github.com/ovh/cds/engine/api/observability"
"github.com/ovh/cds/engine/api/pipeline"
"github.com/ovh/cds/engine/api/workflowtemplate"
"github.com/ovh/cds/sdk"
"github.com/ovh/cds/sdk/log"
)
Expand Down Expand Up @@ -71,6 +72,7 @@ type LoadOptions struct {
WithIcon bool
WithAsCodeUpdateEvent bool
WithIntegrations bool
WithTemplate bool
}

// UpdateOptions is option to parse a workflow
Expand Down Expand Up @@ -587,6 +589,18 @@ func load(ctx context.Context, db gorp.SqlExecutor, proj sdk.Project, opts LoadO
res.EventIntegrations = integrations
}

if opts.WithTemplate {
wti, err := workflowtemplate.LoadInstanceByWorkflowID(ctx, db, res.ID, workflowtemplate.LoadInstanceOptions.WithTemplate)
if err != nil && !sdk.ErrorIs(err, sdk.ErrNotFound) {
return nil, err
}
if wti != nil {
res.TemplateInstance = wti
res.FromTemplate = fmt.Sprintf("%s@%d", wti.Template.Path(), wti.WorkflowTemplateVersion)
res.TemplateUpToDate = wti.Template.Version == wti.WorkflowTemplateVersion
}
}

_, next = observability.Span(ctx, "workflow.load.loadNotifications")
notifs, errN := loadNotifications(db, &res)
next()
Expand Down Expand Up @@ -1256,7 +1270,7 @@ func checkProjectIntegration(proj sdk.Project, w *sdk.Workflow, n *sdk.Node) err
}
}
if ppProj.ID == 0 {
return sdk.WithStack(sdk.ErrorWithData(sdk.ErrIntegrationtNotFound, n.Context.ProjectIntegrationName))
return sdk.WithData(sdk.ErrIntegrationtNotFound, n.Context.ProjectIntegrationName)
}
w.ProjectIntegrations[ppProj.ID] = ppProj
n.Context.ProjectIntegrationID = ppProj.ID
Expand Down Expand Up @@ -1338,7 +1352,7 @@ func checkApplication(store cache.Store, db gorp.SqlExecutor, proj sdk.Project,
appDB, err := application.LoadByName(db, proj.Key, n.Context.ApplicationName, application.LoadOptions.WithDeploymentStrategies, application.LoadOptions.WithVariables)
if err != nil {
if sdk.ErrorIs(err, sdk.ErrNotFound) {
return sdk.WithStack(sdk.ErrorWithData(sdk.ErrNotFound, n.Context.ApplicationName))
return sdk.WithData(sdk.ErrNotFound, n.Context.ApplicationName)
}
return sdk.WrapError(err, "unable to load application %s", n.Context.ApplicationName)
}
Expand Down
18 changes: 15 additions & 3 deletions engine/api/workflow/workflow_exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package workflow

import (
"context"
"fmt"

"github.com/go-gorp/gorp"

Expand All @@ -19,9 +20,9 @@ func Export(ctx context.Context, db gorp.SqlExecutor, cache cache.Store, proj sd
ctx, end := observability.Span(ctx, "workflow.Export")
defer end()

wf, errload := Load(ctx, db, cache, proj, name, LoadOptions{})
if errload != nil {
return v2.Workflow{}, sdk.WrapError(errload, "workflow.Export> Cannot load workflow %s", name)
wf, err := Load(ctx, db, cache, proj, name, LoadOptions{})
if err != nil {
return v2.Workflow{}, sdk.WrapError(err, "cannot load workflow %s", name)
}

// If repo is from as-code do not export WorkflowSkipIfOnlyOneRepoWebhook
Expand All @@ -48,11 +49,22 @@ func Pull(ctx context.Context, db gorp.SqlExecutor, cache cache.Store, proj sdk.

wf, err := Load(ctx, db, cache, proj, name, LoadOptions{
DeepPipeline: true,
WithTemplate: true,
})
if err != nil {
return wp, sdk.WrapError(err, "cannot load workflow %s", name)
}

if wf.TemplateInstance != nil {
return exportentities.WorkflowComponents{
Template: exportentities.TemplateInstance{
Name: wf.Name,
From: fmt.Sprintf("%s@%d", wf.TemplateInstance.Template.Path(), wf.TemplateInstance.WorkflowTemplateVersion),
Parameters: wf.TemplateInstance.Request.Parameters,
},
}, nil
}

// Reload app to retrieve secrets
for i := range wf.Applications {
app := wf.Applications[i]
Expand Down
4 changes: 2 additions & 2 deletions engine/api/workflow/workflow_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ func ParseAndImport(ctx context.Context, db gorp.SqlExecutor, store cache.Store,
// Get spawn infos from error
msg, ok := sdk.ErrorToMessage(err)
if ok {
return nil, []sdk.Message{msg}, sdk.WrapError(err, "Workflow is not valid")
return nil, []sdk.Message{msg}, sdk.WrapError(err, "workflow is not valid")
}
return nil, nil, sdk.WrapError(err, "Workflow is not valid")
return nil, nil, sdk.WrapError(err, "workflow is not valid")
}

if err := RenameNode(ctx, db, w); err != nil {
Expand Down
12 changes: 8 additions & 4 deletions engine/api/workflow_ascode.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,13 @@ func (api *API) getWorkflowAsCodeHandler() service.Handler {
}
}

// postWorkflowAsCodeHandler Update an as code workflow
// @title Make the workflow as code
// @title Update an as code workflow
// postWorkflowAsCodeHandler update an ascode workflow, this will create a pull request to target repository.
func (api *API) postWorkflowAsCodeHandler() service.Handler {
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
vars := mux.Vars(r)
key := vars["key"]
workflowName := vars["permWorkflowName"]

migrate := FormBool(r, "migrate")
branch := FormString(r, "branch")
message := FormString(r, "message")
Expand All @@ -64,6 +63,7 @@ func (api *API) postWorkflowAsCodeHandler() service.Handler {
wfDB, err := workflow.Load(ctx, api.mustDB(), api.Cache, *p, workflowName, workflow.LoadOptions{
DeepPipeline: migrate,
WithAsCodeUpdateEvent: migrate,
WithTemplate: true,
})
if err != nil {
return err
Expand All @@ -84,7 +84,11 @@ func (api *API) postWorkflowAsCodeHandler() service.Handler {

// UPDATE EXISTING AS CODE WORKFLOW
if wfDB.FromRepository == "" {
return sdk.WithStack(sdk.ErrForbidden)
return sdk.NewErrorFrom(sdk.ErrForbidden, "cannot update a workflow that is not ascode")
}

if wfDB.TemplateInstance != nil {
return sdk.NewErrorFrom(sdk.ErrForbidden, "cannot update a workflow that was generated by a template")
}

// Get workflow from body
Expand Down
16 changes: 7 additions & 9 deletions engine/api/workflow_import.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,25 +217,23 @@ func (api *API) putWorkflowImportHandler() service.Handler {

// if workflow is as-code, we can't save it from edit as yml
if wf.FromRepository != "" {
return sdk.WithStack(sdk.ErrForbidden)
return sdk.NewErrorFrom(sdk.ErrForbidden, "can't edit a workflow that is ascode")
}

tx, errtx := api.mustDB().Begin()
if errtx != nil {
return sdk.WrapError(errtx, "Unable to start transaction")
tx, err := api.mustDB().Begin()
if err != nil {
return sdk.WrapError(err, "unable to start transaction")
}
defer func() {
_ = tx.Rollback()
}()
defer tx.Rollback() //nolint

wrkflw, msgList, globalError := workflow.ParseAndImport(ctx, tx, api.Cache, *proj, wf, ew, u, workflow.ImportOptions{Force: true, WorkflowName: wfName})
msgListString := translate(r, msgList)
if globalError != nil {
if len(msgListString) != 0 {
sdkErr := sdk.ExtractHTTPError(globalError, r.Header.Get("Accept-Language"))
return service.WriteJSON(w, append(msgListString, sdkErr.Message), sdkErr.Status)
return service.WriteJSON(w, append(msgListString, sdkErr.Error()), sdkErr.Status)
}
return sdk.WrapError(globalError, "Unable to import workflow %s", ew.GetName())
return sdk.WrapError(globalError, "unable to import workflow %s", ew.GetName())
}

if err := tx.Commit(); err != nil {
Expand Down
6 changes: 1 addition & 5 deletions engine/api/workflow_run.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
"github.com/ovh/cds/engine/api/permission"
"github.com/ovh/cds/engine/api/project"
"github.com/ovh/cds/engine/api/workflow"
"github.com/ovh/cds/engine/api/workflowtemplate"
"github.com/ovh/cds/engine/service"
"github.com/ovh/cds/sdk"
"github.com/ovh/cds/sdk/log"
Expand Down Expand Up @@ -894,15 +893,12 @@ func (api *API) postWorkflowRunHandler() service.Handler {
WithAsCodeUpdateEvent: true,
WithIcon: true,
WithIntegrations: true,
WithTemplate: true,
})
if errWf != nil {
return sdk.WrapError(errWf, "unable to load workflow %s", name)
}

if err := workflowtemplate.AggregateTemplateInstanceOnWorkflow(ctx, api.mustDB(), wf); err != nil {
return sdk.WrapError(err, "cannot load workflow template")
}

// Check node permission
if isService := isService(ctx); !isService && !permission.AccessToWorkflowNode(ctx, api.mustDB(), wf, &wf.WorkflowData.Node, getAPIConsumer(ctx), sdk.PermissionReadExecute) {
return sdk.WrapError(sdk.ErrNoPermExecution, "not enough right on node %s", wf.WorkflowData.Node.Name)
Expand Down
39 changes: 0 additions & 39 deletions engine/api/workflowtemplate/aggregate.go

This file was deleted.

51 changes: 0 additions & 51 deletions engine/api/workflowtemplate/aggregate_test.go

This file was deleted.

6 changes: 3 additions & 3 deletions engine/repositories/processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func (s *Service) do(ctx context.Context, op sdk.Operation) error {
}
log.ErrorWithFields(ctx, fields, "%s", err)

op.Error = sdk.Cause(err).Error()
op.Error = sdk.ExtractHTTPError(err, "").Error()
op.Status = sdk.OperationStatusError
} else {
op.Error = ""
Expand All @@ -70,7 +70,7 @@ func (s *Service) do(ctx context.Context, op sdk.Operation) error {
}
log.ErrorWithFields(ctx, fields, "%s", err)

op.Error = sdk.Cause(err).Error()
op.Error = sdk.ExtractHTTPError(err, "").Error()
op.Status = sdk.OperationStatusError
} else {
op.Error = ""
Expand All @@ -91,7 +91,7 @@ func (s *Service) do(ctx context.Context, op sdk.Operation) error {
}
log.ErrorWithFields(ctx, fields, "%s", err)

op.Error = sdk.Cause(err).Error()
op.Error = sdk.ExtractHTTPError(err, "").Error()
op.Status = sdk.OperationStatusError
} else {
op.Error = ""
Expand Down
Loading

0 comments on commit 0834d56

Please sign in to comment.