Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(api): not allow to resynchronize pipeline on as code workflow #4806 #4828

Merged
merged 1 commit into from
Dec 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions engine/api/workflow_run.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,14 @@ func (api *API) resyncWorkflowRunHandler() service.Handler {
return sdk.WrapError(err, "unable to load projet")
}

wf, err := workflow.Load(ctx, api.mustDB(), api.Cache, proj, name, deprecatedGetUser(ctx), workflow.LoadOptions{Minimal: true, DeepPipeline: false})
if err != nil {
return sdk.WrapError(err, "cannot load workflow %s/%s", key, name)
}
if wf.FromRepository != "" {
return sdk.ErrWorkflowAsCodeResync
}

run, err := workflow.LoadRun(ctx, api.mustDB(), key, name, number, workflow.LoadRunOptions{})
if err != nil {
return sdk.WrapError(err, "Unable to load last workflow run [%s/%d]", name, number)
Expand Down
156 changes: 156 additions & 0 deletions engine/api/workflow_run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -962,6 +962,162 @@ func Test_resyncWorkflowRunHandler(t *testing.T) {
assert.Equal(t, "New awesome stage", workflowRun.Workflow.Pipelines[pip.ID].Stages[0].Name)
}

func Test_resyncWorkflowRunHandlerError(t *testing.T) {
api, db, router, end := newTestAPI(t, bootstrap.InitiliazeDB)
defer end()
u, pass := assets.InsertAdminUser(db)
key := sdk.RandomString(10)
proj := assets.InsertTestProject(t, db, api.Cache, key, key, u)

//First pipeline
pip := sdk.Pipeline{
ProjectID: proj.ID,
ProjectKey: proj.Key,
Name: "pip1",
}
test.NoError(t, pipeline.InsertPipeline(db, api.Cache, proj, &pip, u))

s := sdk.NewStage("stage 1")
s.Enabled = true
s.PipelineID = pip.ID
pipeline.InsertStage(db, s)
j := &sdk.Job{
Enabled: true,
Action: sdk.Action{
Enabled: true,
},
}
pipeline.InsertJob(db, j, s.ID, &pip)
s.Jobs = append(s.Jobs, *j)

pip.Stages = append(pip.Stages, *s)

pipeline.InsertStage(db, s)
j = &sdk.Job{
Enabled: true,
Action: sdk.Action{
Enabled: true,
},
}
s.Jobs = append(s.Jobs, *j)

// Create Application
app := sdk.Application{
Name: sdk.RandomString(10),
ProjectID: proj.ID,
RepositoryFullname: "foo/myrepo",
VCSServer: "github",
}
assert.NoError(t, application.Insert(db, api.Cache, proj, &app, u))
assert.NoError(t, repositoriesmanager.InsertForApplication(db, &app, proj.Key))

w := sdk.Workflow{
Name: "test_1",
ProjectID: proj.ID,
ProjectKey: proj.Key,
FromRepository: "foo/myrepo",
WorkflowData: &sdk.WorkflowData{
Node: sdk.Node{
Name: "root",
Type: sdk.NodeTypePipeline,
Context: &sdk.NodeContext{
PipelineID: pip.ID,
ApplicationID: app.ID,
},
Triggers: []sdk.NodeTrigger{
{
ChildNode: sdk.Node{
Name: "child",
Type: sdk.NodeTypePipeline,
Context: &sdk.NodeContext{
PipelineID: pip.ID,
},
},
},
},
},
},
}

proj2, errP := project.Load(api.mustDB(), api.Cache, proj.Key, u, project.LoadOptions.WithPipelines, project.LoadOptions.WithGroups, project.LoadOptions.WithIntegrations)
test.NoError(t, errP)

test.NoError(t, workflow.Insert(db, api.Cache, &w, proj2, u))
w1, err := workflow.Load(context.TODO(), db, api.Cache, proj2, "test_1", u, workflow.LoadOptions{})
test.NoError(t, err)

//Prepare request
vars := map[string]string{
"key": proj.Key,
"permWorkflowName": w1.Name,
}
uri := router.GetRoute("POST", api.postWorkflowRunHandler, vars)
test.NotEmpty(t, uri)

opts := &sdk.WorkflowRunPostHandlerOption{
Manual: &sdk.WorkflowNodeRunManual{
Payload: map[string]string{
"git.branch": "master",
},
},
}
req := assets.NewAuthentifiedRequest(t, u, pass, "POST", uri, opts)

//Do the request
rec := httptest.NewRecorder()
router.Mux.ServeHTTP(rec, req)
assert.Equal(t, 202, rec.Code)

wr := &sdk.WorkflowRun{}
test.NoError(t, json.Unmarshal(rec.Body.Bytes(), wr))
assert.Equal(t, int64(1), wr.Number)

cpt := 0
for {
varsGet := map[string]string{
"key": proj.Key,
"permWorkflowName": w1.Name,
"number": "1",
}
uriGet := router.GetRoute("GET", api.getWorkflowRunHandler, varsGet)
reqGet := assets.NewAuthentifiedRequest(t, u, pass, "GET", uriGet, nil)
recGet := httptest.NewRecorder()
router.Mux.ServeHTTP(recGet, reqGet)

var wrGet sdk.WorkflowRun
assert.NoError(t, json.Unmarshal(recGet.Body.Bytes(), &wrGet))

if wrGet.Status != sdk.StatusPending.String() {
assert.Equal(t, sdk.StatusBuilding.String(), wrGet.Status)
break
}
t.Logf("workflow run response %+v\n", wrGet)
cpt++
if cpt > 10 {
break
}
}

pip.Stages[0].Name = "New awesome stage"
errS := pipeline.UpdateStage(db, &pip.Stages[0])
test.NoError(t, errS)

//Prepare request
vars = map[string]string{
"key": proj.Key,
"permWorkflowName": w1.Name,
"number": fmt.Sprintf("%d", wr.Number),
}
uri = router.GetRoute("POST", api.resyncWorkflowRunHandler, vars)
test.NotEmpty(t, uri)
req = assets.NewAuthentifiedRequest(t, u, pass, "POST", uri, nil)

//Do the request
rec = httptest.NewRecorder()
router.Mux.ServeHTTP(rec, req)
assert.Equal(t, 403, rec.Code)
}

func Test_postWorkflowRunHandler(t *testing.T) {
api, db, router, end := newTestAPI(t, bootstrap.InitiliazeDB)
defer end()
Expand Down
3 changes: 3 additions & 0 deletions sdk/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ var (
ErrBadBrokerConfiguration = Error{ID: 181, Status: http.StatusBadRequest}
ErrInvalidJobRequirementNetworkAccess = Error{ID: 182, Status: http.StatusBadRequest}
ErrInvalidWorkerModelNamePattern = Error{ID: 183, Status: http.StatusBadRequest}
ErrWorkflowAsCodeResync = Error{ID: 184, Status: http.StatusForbidden}
)

var errorsAmericanEnglish = map[int]string{
Expand Down Expand Up @@ -378,6 +379,7 @@ var errorsAmericanEnglish = map[int]string{
ErrIntegrationtNotFound.ID: "integration not found",
ErrBadBrokerConfiguration.ID: "Cannot connect to the broker of your event integration. Check your configuration",
ErrInvalidJobRequirementNetworkAccess.ID: "Invalid job requirement: network requirement must contains ':'. Example: golang.org:http, golang.org:443",
ErrWorkflowAsCodeResync.ID: "You cannot resynchronize an as-code workflow",
}

var errorsFrench = map[int]string{
Expand Down Expand Up @@ -557,6 +559,7 @@ var errorsFrench = map[int]string{
ErrEnvironmentNotFound.ID: "l'environnement n'existe pas",
ErrBadBrokerConfiguration.ID: "Impossible de se connecter à votre intégration de type évènement. Veuillez vérifier votre configuration",
ErrInvalidJobRequirementNetworkAccess.ID: "Pré-requis de job invalide: Le pré-requis network doit contenir un ':'. Exemple: golang.org:http, golang.org:443",
ErrWorkflowAsCodeResync.ID: "Impossible de resynchroniser un workflow en mode as-code",
}

var errorsLanguages = []map[int]string{
Expand Down