Skip to content

Commit

Permalink
feat(api): add workflow default tags after add repository webhook (#2465
Browse files Browse the repository at this point in the history
)
  • Loading branch information
bnjjj authored and yesnault committed Mar 30, 2018
1 parent 6778b8a commit 0867d44
Show file tree
Hide file tree
Showing 7 changed files with 209 additions and 13 deletions.
1 change: 1 addition & 0 deletions engine/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,7 @@ func (a *API) Serve(ctx context.Context) error {
go migrate.CleanOldWorkflow(ctx, a.Cache, a.DBConnectionFactory.GetDBMap, a.Config.URL.API)
go migrate.KeyMigration(a.Cache, a.DBConnectionFactory.GetDBMap, &sdk.User{Admin: true})
go migrate.DefaultPayloadMigration(a.Cache, a.DBConnectionFactory.GetDBMap, &sdk.User{Admin: true})
go migrate.DefaultTagsMigration(a.Cache, a.DBConnectionFactory.GetDBMap, &sdk.User{Admin: true})

//Temporary migration code
if os.Getenv("CDS_MIGRATE_ENABLE") == "true" {
Expand Down
89 changes: 89 additions & 0 deletions engine/api/migrate/default_tags.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package migrate

import (
"database/sql"

"github.com/go-gorp/gorp"

"github.com/ovh/cds/engine/api/cache"
"github.com/ovh/cds/engine/api/database/gorpmapping"
"github.com/ovh/cds/engine/api/project"
"github.com/ovh/cds/engine/api/workflow"
"github.com/ovh/cds/sdk"
"github.com/ovh/cds/sdk/log"
)

// DefaultTagsMigration useful to set default tags to git.branch git.author
func DefaultTagsMigration(store cache.Store, DBFunc func() *gorp.DbMap, u *sdk.User) {
defaultTagsKey := "default_tags"
db := DBFunc()

log.Info("DefaultTagsMigration> Begin")

projs, errP := project.LoadAll(db, store, u)
if errP != nil {
log.Warning("DefaultTagsMigration> Cannot load all project: %s", errP)
return
}

for _, proj := range projs {
workflows, err := workflow.LoadAll(db, proj.Key)
if err != nil {
log.Warning("DefaultTagsMigration> Cannot load all workflows for project %s : %s", proj.Key, err)
continue
}

for _, wf := range workflows {
tx, errTx := db.Begin()
if errTx != nil {
log.Warning("DefaultTagsMigration> cannot begin a transaction : %s", errTx)
continue
}

var metadataStr sql.NullString
if err := tx.SelectOne(&metadataStr, "SELECT metadata FROM workflow WHERE id = $1 FOR UPDATE NOWAIT", wf.ID); err != nil {
tx.Rollback()
log.Warning("DefaultTagsMigration> Cannot load metadata for workflow %s/%s : %s", proj.Key, wf.Name, err)
continue
}

metadata := sdk.Metadata{}
if err := gorpmapping.JSONNullString(metadataStr, &metadata); err != nil {
tx.Rollback()
log.Warning("DefaultTagsMigration> Cannot unmarshall metadata for workflow %s/%s : %s", proj.Key, wf.Name, err)
continue
}

if metadata == nil || metadata[defaultTagsKey] == "" {
nodeCtx, errLn := workflow.LoadNodeContext(db, store, proj.Key, wf.RootID, u, workflow.LoadOptions{})
if errLn != nil {
log.Warning("DefaultTagsMigration> Cannot load root node context for workflow %s/%s node id %d : %s", proj.Key, wf.Name, wf.RootID, errLn)
tx.Rollback()
continue
}

if nodeCtx.Application == nil || nodeCtx.Application.RepositoryFullname == "" {
tx.Rollback()
continue
}

metadata[defaultTagsKey] = "git.branch,git.author"

if err := workflow.UpdateMetadata(tx, wf.ID, metadata); err != nil {
tx.Rollback()
log.Warning("DefaultTagsMigration> Cannot update metadata for workflow %s/%s node id %d : %s", proj.Key, wf.Name, wf.RootID, err)
continue
}

if err := tx.Commit(); err != nil {
tx.Rollback()
log.Warning("DefaultTagsMigration> Cannot commit transaction for workflow %s/%s node id %d : %s", proj.Key, wf.Name, wf.RootID, err)
continue
}
} else {
tx.Rollback()
}
}
}
log.Info("DefaultTagsMigration> Done")
}
40 changes: 40 additions & 0 deletions engine/api/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"context"
"fmt"
"net/http"
"strings"

"github.com/fsamin/go-dump"
"github.com/go-gorp/gorp"
Expand Down Expand Up @@ -221,6 +222,11 @@ func (api *API) putWorkflowHandler() Handler {
if err := workflow.UpdateNodeContext(tx, wf.Root.Context); err != nil {
return sdk.WrapError(err, "putWorkflowHandler> updateNodeContext")
}
} else if defaultPayload != nil || (wf.Root.Context != nil && wf.Root.Context.Application != nil && wf.Root.Context.Application.RepositoryFullname != "") {
wf.Metadata = getUpdatedMetadata(wf.Metadata)
if err := workflow.UpdateMetadata(tx, wf.ID, wf.Metadata); err != nil {
return sdk.WrapError(err, "putWorkflowHandler> cannot update metadata")
}
}

if err := workflow.UpdateLastModifiedDate(tx, api.Cache, getUser(ctx), p.Key, oldW); err != nil {
Expand Down Expand Up @@ -269,6 +275,40 @@ func isDefaultPayloadEmpty(wf sdk.Workflow) bool {
return len(m) == 0 // if empty, return true
}

func getUpdatedMetadata(metadata sdk.Metadata) sdk.Metadata {
defaultTags, ok := metadata["default_tags"]
if ok {
var gitAuthor, gitBranch bool
tagsList := strings.Split(defaultTags, ",")

for _, tag := range tagsList {
switch tag {
case "git.branch":
gitBranch = true
case "git.author":
gitAuthor = true
}
}

if !gitAuthor {
defaultTags = "git.author," + defaultTags
}

if !gitBranch {
defaultTags = "git.branch," + defaultTags
}
} else {
defaultTags = "git.branch,git.author"
}

if metadata == nil {
metadata = sdk.Metadata{}
}
metadata["default_tags"] = defaultTags

return metadata
}

// putWorkflowHandler deletes a workflow
func (api *API) deleteWorkflowHandler() Handler {
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
Expand Down
30 changes: 25 additions & 5 deletions engine/api/workflow/dao.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,19 @@ func Exists(db gorp.SqlExecutor, key string, name string) (bool, error) {
return count > 0, nil
}

// UpdateMetadata update the metadata of a workflow
func UpdateMetadata(db gorp.SqlExecutor, workflowID int64, metadata sdk.Metadata) error {
b, err := json.Marshal(metadata)
if err != nil {
return err
}
if _, err := db.Exec("update workflow set metadata = $1 where id = $2", b, workflowID); err != nil {
return err
}

return nil
}

// UpdateLastModifiedDate Update workflow last modified date
func UpdateLastModifiedDate(db gorp.SqlExecutor, store cache.Store, u *sdk.User, projKey string, w *sdk.Workflow) error {
t := time.Now()
Expand Down Expand Up @@ -97,11 +110,7 @@ func (w *Workflow) PostGet(db gorp.SqlExecutor) error {

// PostUpdate is a db hook
func (w *Workflow) PostUpdate(db gorp.SqlExecutor) error {
b, err := json.Marshal(w.Metadata)
if err != nil {
return err
}
if _, err := db.Exec("update workflow set metadata = $1 where id = $2", b, w.ID); err != nil {
if err := UpdateMetadata(db, w.ID, w.Metadata); err != nil {
return err
}

Expand Down Expand Up @@ -377,6 +386,17 @@ func Insert(db gorp.SqlExecutor, store cache.Store, w *sdk.Workflow, p *sdk.Proj
}
w.RootID = w.Root.ID

if w.Root.Context != nil && w.Root.Context.Application != nil && w.Root.Context.Application.RepositoryFullname != "" {
if w.Metadata == nil {
w.Metadata = sdk.Metadata{}
}
w.Metadata["default_tags"] = "git.branch,git.author"

if err := UpdateMetadata(db, w.ID, w.Metadata); err != nil {
return sdk.WrapError(err, "Insert> Unable to insert workflow metadata (%#v, %d)", w.Root, w.ID)
}
}

if _, err := db.Exec("UPDATE workflow SET root_node_id = $2 WHERE id = $1", w.ID, w.Root.ID); err != nil {
return sdk.WrapError(err, "Insert> Unable to insert workflow (%#v, %d)", w.Root, w.ID)
}
Expand Down
16 changes: 8 additions & 8 deletions engine/api/workflow/dao_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,14 @@ func insertNode(db gorp.SqlExecutor, store cache.Store, w *sdk.Workflow, n *sdk.
return sdk.WrapError(err, "InsertOrUpdateNode> Unable to insert workflow node %d context", n.ID)
}

if n.Context.Application == nil && n.Context.ApplicationID != 0 {
app, errA := application.LoadByID(db, store, n.Context.ApplicationID, u)
if errA != nil {
return sdk.WrapError(errA, "InsertOrUpdateNode> Cannot load application %d", n.Context.ApplicationID)
}
n.Context.Application = app
}

//Insert hooks
hooksUUIDs := []string{}
for i := range n.Hooks {
Expand Down Expand Up @@ -126,14 +134,6 @@ func insertNode(db gorp.SqlExecutor, store cache.Store, w *sdk.Workflow, n *sdk.
}

if h.WorkflowHookModel.Name == sdk.RepositoryWebHookModelName || h.WorkflowHookModel.Name == sdk.GitPollerModelName {
if n.Context.Application == nil {
app, errA := application.LoadByID(db, store, n.Context.ApplicationID, u)
if errA != nil {
return sdk.WrapError(errA, "InsertOrUpdateNode> Cannot load application %d", n.Context.ApplicationID)
}
n.Context.Application = app
}

if n.Context.Application == nil || n.Context.Application.RepositoryFullname == "" || n.Context.Application.VCSServer == "" {
return sdk.WrapError(sdk.ErrForbidden, "InsertOrUpdateNode> Cannot create a git poller or repository webhook on an application without a repository")
}
Expand Down
35 changes: 35 additions & 0 deletions engine/api/workflow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -348,3 +348,38 @@ func Test_deleteWorkflowHandler(t *testing.T) {
router.Mux.ServeHTTP(w, req)
assert.Equal(t, 200, w.Code)
}

func TestGetUpdatedMetadata(t *testing.T) {
tcs := []struct {
metadata sdk.Metadata
expected sdk.Metadata
}{
{
metadata: sdk.Metadata{},
expected: sdk.Metadata{
"default_tags": "git.branch,git.author",
},
},
{
metadata: sdk.Metadata{"default_tags": "git.hash,git.branch"},
expected: sdk.Metadata{
"default_tags": "git.author,git.hash,git.branch",
},
},
{
metadata: sdk.Metadata{"default_tags": "git.hash,triggered_by"},
expected: sdk.Metadata{
"default_tags": "git.branch,git.author,git.hash,triggered_by",
},
},
{
expected: sdk.Metadata{
"default_tags": "git.branch,git.author",
},
},
}

for _, tc := range tcs {
test.Equal(t, tc.expected, getUpdatedMetadata(tc.metadata))
}
}
11 changes: 11 additions & 0 deletions engine/api/workflow_trigger.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,17 @@ func (api *API) getWorkflowTriggerConditionHandler() Handler {
sdk.AddParameter(&params, "cds.dest.environment", sdk.StringParameter, "")
}
}

if refNode.Context != nil && refNode.Context.Application != nil && refNode.Context.Application.RepositoryFullname != "" {
if sdk.ParameterFind(&params, "git.repository") == nil {
data.ConditionNames = append(data.ConditionNames, "git.repository")
data.ConditionNames = append(data.ConditionNames, "git.branch")
data.ConditionNames = append(data.ConditionNames, "git.message")
data.ConditionNames = append(data.ConditionNames, "git.author")
data.ConditionNames = append(data.ConditionNames, "git.hash")
}
}

for _, p := range params {
data.ConditionNames = append(data.ConditionNames, p.Name)
}
Expand Down

0 comments on commit 0867d44

Please sign in to comment.