Skip to content

Commit

Permalink
feat: return workflow holder for pipeline
Browse files Browse the repository at this point in the history
  • Loading branch information
richardlt committed Apr 21, 2020
1 parent 50d0078 commit d06985c
Show file tree
Hide file tree
Showing 17 changed files with 99 additions and 152 deletions.
1 change: 0 additions & 1 deletion engine/api/api_routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,6 @@ func (api *API) InitRouter() {
r.Handle("/project/{permProjectKey}/export/application/{applicationName}", Scope(sdk.AuthConsumerScopeProject), r.GET(api.getApplicationExportHandler))

// Application
r.Handle("/project/{permProjectKey}/ascode/application", Scope(sdk.AuthConsumerScopeProject), r.GET(api.getAsCodeApplicationHandler))
r.Handle("/project/{permProjectKey}/application/{applicationName}", Scope(sdk.AuthConsumerScopeProject), r.GET(api.getApplicationHandler), r.PUT(api.updateApplicationHandler), r.DELETE(api.deleteApplicationHandler))
r.Handle("/project/{permProjectKey}/application/{applicationName}/metrics/{metricName}", Scope(sdk.AuthConsumerScopeProject), r.GET(api.getApplicationMetricHandler))
r.Handle("/project/{permProjectKey}/application/{applicationName}/keys", Scope(sdk.AuthConsumerScopeProject), r.GET(api.getKeysInApplicationHandler), r.POST(api.addKeyInApplicationHandler))
Expand Down
14 changes: 0 additions & 14 deletions engine/api/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,20 +106,6 @@ func (api *API) getApplicationsHandler() service.Handler {
}
}

func (api *API) getAsCodeApplicationHandler() service.Handler {
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
vars := mux.Vars(r)
projectKey := vars[permProjectKey]
fromRepo := FormString(r, "repo")

apps, err := application.LoadAsCode(api.mustDB(), projectKey, fromRepo)
if err != nil {
return sdk.WrapError(err, "cannot load application from repo %s for project %s from db", fromRepo, projectKey)
}
return service.WriteJSON(w, apps, http.StatusOK)
}
}

func (api *API) getApplicationHandler() service.Handler {
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
vars := mux.Vars(r)
Expand Down
11 changes: 0 additions & 11 deletions engine/api/application/dao.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,17 +59,6 @@ func Exists(db gorp.SqlExecutor, projectKey, appName string) (bool, error) {
return count == 1, nil
}

// LoadAsCode load an ascode application from DB
func LoadAsCode(db gorp.SqlExecutor, projectKey, fromRepo string) ([]sdk.Application, error) {
query := gorpmapping.NewQuery(`
SELECT application.*
FROM application
JOIN project ON project.id = application.project_id
WHERE project.projectkey = $1
AND application.from_repository = $2`).Args(projectKey, fromRepo)
return getAll(context.Background(), db, nil, query)
}

// LoadByName load an application from DB
func LoadByName(db gorp.SqlExecutor, projectKey, appName string, opts ...LoadOptionFunc) (*sdk.Application, error) {
query := gorpmapping.NewQuery(`
Expand Down
59 changes: 0 additions & 59 deletions engine/api/application_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,19 @@ package api

import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"testing"

"gopkg.in/yaml.v2"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/ovh/cds/engine/api/application"
"github.com/ovh/cds/engine/api/authentication"
"github.com/ovh/cds/engine/api/authentication/builtin"
"github.com/ovh/cds/engine/api/group"
"github.com/ovh/cds/engine/api/repositoriesmanager"
"github.com/ovh/cds/engine/api/test"
"github.com/ovh/cds/engine/api/test/assets"
"github.com/ovh/cds/sdk"
"github.com/ovh/cds/sdk/cdsclient"
"github.com/ovh/cds/sdk/exportentities"
)

func Test_postApplicationMetadataHandler_AsProvider(t *testing.T) {
Expand Down Expand Up @@ -69,54 +61,3 @@ func Test_postApplicationMetadataHandler_AsProvider(t *testing.T) {
test.NoError(t, err)
assert.Equal(t, 1, len(apps))
}

func Test_getAsCodeApplicationHandler(t *testing.T) {
api, db, _, end := newTestAPI(t)
defer end()

u, pass := assets.InsertAdminUser(t, db)
pkey := sdk.RandomString(10)
p := assets.InsertTestProject(t, db, api.Cache, pkey, pkey)

assert.NoError(t, repositoriesmanager.InsertForProject(db, p, &sdk.ProjectVCSServer{
Name: "github",
Data: map[string]string{
"token": "foo",
"secret": "bar",
},
}))

// Add application
appS := `version: v1.0
name: blabla
vcs_server: github
repo: sguiheux/demo
vcs_ssh_key: proj-blabla
`
var eapp = new(exportentities.Application)
assert.NoError(t, yaml.Unmarshal([]byte(appS), eapp))
app, _, globalError := application.ParseAndImport(context.Background(), db, api.Cache, *p, eapp, application.ImportOptions{Force: true}, nil, u)
assert.NoError(t, globalError)

app.FromRepository = "myrepository"
assert.NoError(t, application.Update(db, app))

uri := api.Router.GetRoute("GET", api.getAsCodeApplicationHandler, map[string]string{
"permProjectKey": pkey,
})
uri = fmt.Sprintf("%s?repo=myrepository", uri)

req, err := http.NewRequest("GET", uri, nil)
test.NoError(t, err)
assets.AuthentifyRequest(t, req, u, pass)

// Do the request
w := httptest.NewRecorder()
api.Router.Mux.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code)

var appDB []sdk.Application
assert.NoError(t, json.Unmarshal(w.Body.Bytes(), &appDB))
assert.Equal(t, app.ID, appDB[0].ID)

}
2 changes: 1 addition & 1 deletion engine/api/ascode/ascode_pr.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type EntityData struct {
}

// UpdateAsCodeResult pulls repositories operation and the create pullrequest + update workflow
func UpdateAsCodeResult(ctx context.Context, db *gorp.DbMap, store cache.Store, proj sdk.Project, app *sdk.Application, ed EntityData, u sdk.Identifiable) *sdk.AsCodeEvent {
func UpdateAsCodeResult(ctx context.Context, db *gorp.DbMap, store cache.Store, proj sdk.Project, app sdk.Application, ed EntityData, u sdk.Identifiable) *sdk.AsCodeEvent {
tick := time.NewTicker(2 * time.Second)
ctx, cancel := context.WithTimeout(ctx, 1*time.Minute)
defer func() {
Expand Down
31 changes: 15 additions & 16 deletions engine/api/pipeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ func (api *API) updateAsCodePipelineHandler() service.Handler {
vars := mux.Vars(r)
key := vars[permProjectKey]
name := vars["pipelineKey"]

branch := FormString(r, "branch")
message := FormString(r, "message")
fromRepo := FormString(r, "repo")

var p sdk.Pipeline
if err := service.UnmarshalBody(r, &p); err != nil {
Expand All @@ -54,28 +54,29 @@ func (api *API) updateAsCodePipelineHandler() service.Handler {
return sdk.NewErrorFrom(sdk.ErrForbidden, "current pipeline is not ascode")
}

wk, err := workflow.LoadByRepo(ctx, api.Cache, api.mustDB(), *proj, fromRepo, workflow.LoadOptions{
wkHolder, err := workflow.LoadByRepo(ctx, api.Cache, api.mustDB(), *proj, pipelineDB.FromRepository, workflow.LoadOptions{
WithTemplate: true,
})
if err != nil {
return err
}
if wk.TemplateInstance != nil {
if wkHolder.TemplateInstance != nil {
return sdk.NewErrorFrom(sdk.ErrForbidden, "cannot edit a pipeline that was generated by a template")
}

apps, err := application.LoadAsCode(api.mustDB(), key, fromRepo)
if err != nil {
return err
var rootApp *sdk.Application
if wkHolder.WorkflowData.Node.Context != nil && wkHolder.WorkflowData.Node.Context.ApplicationID != 0 {
rootApp, err = application.LoadByIDWithClearVCSStrategyPassword(api.mustDB(), wkHolder.WorkflowData.Node.Context.ApplicationID)
if err != nil {
return err
}
}

app, err := application.LoadByIDWithClearVCSStrategyPassword(api.mustDB(), apps[0].ID)
if err != nil {
return err
if rootApp == nil {
return sdk.NewErrorFrom(sdk.ErrWrongRequest, "cannot find the root application of the workflow %s that hold the pipeline", wkHolder.Name)
}

u := getAPIConsumer(ctx)
ope, err := pipeline.UpdatePipelineAsCode(ctx, api.Cache, api.mustDB(), *proj, p, app.VCSServer, app.RepositoryFullname, branch, message, app.RepositoryStrategy, u)
ope, err := pipeline.UpdatePipelineAsCode(ctx, api.Cache, api.mustDB(), *proj, p, rootApp.VCSServer, rootApp.RepositoryFullname, branch, message, rootApp.RepositoryStrategy, u)
if err != nil {
return err
}
Expand All @@ -88,7 +89,7 @@ func (api *API) updateAsCodePipelineHandler() service.Handler {
Name: pipelineDB.Name,
Operation: ope,
}
asCodeEvent := ascode.UpdateAsCodeResult(ctx, api.mustDB(), api.Cache, *proj, &apps[0], ed, u)
asCodeEvent := ascode.UpdateAsCodeResult(ctx, api.mustDB(), api.Cache, *proj, *rootApp, ed, u)
if asCodeEvent != nil {
event.PublishAsCodeEvent(ctx, proj.Key, *asCodeEvent, u)
}
Expand Down Expand Up @@ -322,15 +323,13 @@ func (api *API) getPipelineHandler() service.Handler {
}

if p.FromRepository != "" {
wkHolder, err := workflow.LoadByRepo(ctx, api.Cache, api.mustDB(), *proj, p.FromRepository, workflow.LoadOptions{
wkAscodeHolder, err := workflow.LoadByRepo(ctx, api.Cache, api.mustDB(), *proj, p.FromRepository, workflow.LoadOptions{
WithTemplate: true,
})
if err != nil {
return sdk.NewErrorFrom(err, "cannot found workflow holder of the pipeline")
}
if wkHolder.TemplateInstance != nil {
p.FromTemplate = wkHolder.FromTemplate
}
p.WorkflowAscodeHolder = wkAscodeHolder
}

return service.WriteJSON(w, p, http.StatusOK)
Expand Down
40 changes: 38 additions & 2 deletions engine/api/pipeline_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/ovh/cds/engine/api/application"
"github.com/ovh/cds/engine/api/pipeline"
Expand Down Expand Up @@ -38,9 +39,11 @@ func TestUpdateAsCodePipelineHandler(t *testing.T) {

a, _ := assets.InsertService(t, db, "TestUpdateAsCodePipelineHandler", services.TypeVCS)
b, _ := assets.InsertService(t, db, "TestUpdateAsCodePipelineHandler", services.TypeRepositories)
c, _ := assets.InsertService(t, db, "TestUpdateAsCodePipelineHandler", services.TypeHooks)
defer func() {
_ = services.Delete(db, a) // nolint
_ = services.Delete(db, b) // nolint
_ = services.Delete(db, c) // nolint
}()
//This is a mock for the repositories service
services.HTTPClient = mock(
Expand All @@ -65,7 +68,14 @@ func TestUpdateAsCodePipelineHandler(t *testing.T) {
if err := enc.Encode(ope); err != nil {
return writeError(w, err)
}

case "/vcs/github/webhooks":
hookInfo := repositoriesmanager.WebhooksInfos{
WebhooksSupported: true,
WebhooksDisabled: false,
}
if err := enc.Encode(hookInfo); err != nil {
return writeError(w, err)
}
case "/vcs/github/repos/foo/myrepo":
vcsRepo := sdk.VCSRepo{
Name: "foo/myrepo",
Expand All @@ -75,13 +85,32 @@ func TestUpdateAsCodePipelineHandler(t *testing.T) {
if err := enc.Encode(vcsRepo); err != nil {
return writeError(w, err)
}
case "/vcs/github/repos/foo/myrepo/hooks":
hook := sdk.VCSHook{
ID: "myod",
}
if err := enc.Encode(hook); err != nil {
return writeError(w, err)
}
case "/vcs/github/repos/foo/myrepo/pullrequests":
vcsPR := sdk.VCSPullRequest{
URL: "myURL",
}
if err := enc.Encode(vcsPR); err != nil {
return writeError(w, err)
}
case "/task/bulk":
var hooks map[string]sdk.NodeHook
bts, err := ioutil.ReadAll(r.Body)
if err != nil {
return writeError(w, err)
}
if err := json.Unmarshal(bts, &hooks); err != nil {
return writeError(w, err)
}
if err := enc.Encode(hooks); err != nil {
return writeError(w, err)
}
default:
t.Logf("[WRONG ROUTE] %s", r.URL.String())
w.StatusCode = http.StatusNotFound
Expand Down Expand Up @@ -130,10 +159,17 @@ func TestUpdateAsCodePipelineHandler(t *testing.T) {
assert.NoError(t, application.Insert(db, *proj, &app))
assert.NoError(t, repositoriesmanager.InsertForApplication(db, &app, proj.Key))

repoModel, err := workflow.LoadHookModelByName(db, sdk.RepositoryWebHookModelName)
assert.NoError(t, err)

wk := initWorkflow(t, db, proj, &app, &pip, repoModel)
wk.FromRepository = "myrepofrom"
require.NoError(t, workflow.Insert(context.Background(), db, api.Cache, *proj, wk))

uri := api.Router.GetRoute("PUT", api.updateAsCodePipelineHandler, map[string]string{
"permProjectKey": proj.Key,
"pipelineKey": pip.Name,
}) + "?repo=myrepofrom"
})
req := assets.NewJWTAuthentifiedRequest(t, pass, "PUT", uri, pip)

// Do the request
Expand Down
Loading

0 comments on commit d06985c

Please sign in to comment.