Skip to content

Commit ed99a4a

Browse files
bnjjjfsamin
authored andcommitted
fix(api): when you update repomanager on an application, update workflow root linked (#2976)
1 parent b996393 commit ed99a4a

File tree

6 files changed

+165
-17
lines changed

6 files changed

+165
-17
lines changed

engine/api/application.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ func (api *API) getApplicationHandler() Handler {
342342
}
343343
}
344344

345+
// loadApplicationUsage return usage of application
345346
func loadApplicationUsage(db gorp.SqlExecutor, projKey, appName string) (sdk.Usage, error) {
346347
usage := sdk.Usage{}
347348

engine/api/repositories_manager.go

Lines changed: 114 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"github.com/ovh/cds/engine/api/project"
2121
"github.com/ovh/cds/engine/api/repositoriesmanager"
2222
"github.com/ovh/cds/engine/api/user"
23+
"github.com/ovh/cds/engine/api/workflow"
2324
"github.com/ovh/cds/engine/api/workflowv0"
2425
"github.com/ovh/cds/sdk"
2526
"github.com/ovh/cds/sdk/log"
@@ -377,20 +378,22 @@ func (api *API) attachRepositoriesManagerHandler() Handler {
377378
appName := vars["permApplicationName"]
378379
rmName := vars["name"]
379380
fullname := r.FormValue("fullname")
381+
db := api.mustDB()
382+
u := getUser(ctx)
380383

381-
app, err := application.LoadByName(api.mustDB(), api.Cache, projectKey, appName, getUser(ctx))
384+
app, err := application.LoadByName(db, api.Cache, projectKey, appName, u)
382385
if err != nil {
383386
return sdk.WrapError(err, "attachRepositoriesManager> Cannot load application %s", appName)
384387
}
385388

386389
//Load the repositoriesManager for the project
387-
rm, err := repositoriesmanager.LoadForProject(api.mustDB(), projectKey, rmName)
390+
rm, err := repositoriesmanager.LoadForProject(db, projectKey, rmName)
388391
if err != nil {
389392
return sdk.WrapError(sdk.ErrNoReposManager, "attachRepositoriesManager> error loading %s-%s: %s", projectKey, rmName, err)
390393
}
391394

392395
//Get an authorized Client
393-
client, err := repositoriesmanager.AuthorizedClient(api.mustDB(), api.Cache, rm)
396+
client, err := repositoriesmanager.AuthorizedClient(db, api.Cache, rm)
394397
if err != nil {
395398
return sdk.WrapError(sdk.ErrNoReposManagerClientAuth, "attachRepositoriesManager> Cannot get client got %s %s : %s", projectKey, rmName, err)
396399
}
@@ -402,7 +405,7 @@ func (api *API) attachRepositoriesManagerHandler() Handler {
402405
app.VCSServer = rm.Name
403406
app.RepositoryFullname = fullname
404407

405-
tx, errT := api.mustDB().Begin()
408+
tx, errT := db.Begin()
406409
if errT != nil {
407410
return sdk.WrapError(errT, "attachRepositoriesManager> Cannot start transaction")
408411
}
@@ -412,15 +415,60 @@ func (api *API) attachRepositoriesManagerHandler() Handler {
412415
return sdk.WrapError(err, "attachRepositoriesManager> Cannot insert for application")
413416
}
414417

415-
if err := application.UpdateLastModified(tx, api.Cache, app, getUser(ctx)); err != nil {
418+
if err := application.UpdateLastModified(tx, api.Cache, app, u); err != nil {
416419
return sdk.WrapError(err, "attachRepositoriesManager> Cannot update application last modified date")
417420
}
418421

419422
if err := tx.Commit(); err != nil {
420423
return sdk.WrapError(err, "attachRepositoriesManager> Cannot commit transaction")
421424
}
422425

423-
event.PublishApplicationRepositoryAdd(projectKey, *app, getUser(ctx))
426+
usage, errU := loadApplicationUsage(db, projectKey, appName)
427+
if errU != nil {
428+
return sdk.WrapError(errU, "attachRepositoriesManager> Cannot load application usage")
429+
}
430+
431+
// Update default payload of linked workflow root
432+
if len(usage.Workflows) > 0 {
433+
proj, errP := project.Load(db, api.Cache, projectKey, u)
434+
if errP != nil {
435+
return sdk.WrapError(errP, "attachRepositoriesManager> Cannot load project")
436+
}
437+
438+
for _, wf := range usage.Workflows {
439+
rootCtx, errNc := workflow.LoadNodeContext(db, api.Cache, proj, wf.RootID, u, workflow.LoadOptions{})
440+
if errNc != nil {
441+
return sdk.WrapError(errNc, "attachRepositoriesManager> Cannot DefaultPayloadToMap")
442+
}
443+
444+
if rootCtx.ApplicationID != app.ID {
445+
continue
446+
}
447+
448+
wf.Root = &sdk.WorkflowNode{
449+
Context: rootCtx,
450+
}
451+
payload, errD := rootCtx.DefaultPayloadToMap()
452+
if errD != nil {
453+
return sdk.WrapError(errP, "attachRepositoriesManager> Cannot DefaultPayloadToMap")
454+
}
455+
456+
if _, ok := payload["git.branch"]; ok && payload["git.repository"] == app.RepositoryFullname {
457+
continue
458+
}
459+
460+
defaultPayload, errPay := workflow.DefaultPayload(db, api.Cache, proj, u, &wf)
461+
if errPay != nil {
462+
return sdk.WrapError(errPay, "attachRepositoriesManager> Cannot get defaultPayload")
463+
}
464+
wf.Root.Context.DefaultPayload = defaultPayload
465+
if err := workflow.UpdateNodeContext(db, wf.Root.Context); err != nil {
466+
return sdk.WrapError(err, "attachRepositoriesManager> Cannot update node context %d", wf.Root.Context.ID)
467+
}
468+
}
469+
}
470+
471+
event.PublishApplicationRepositoryAdd(projectKey, *app, u)
424472

425473
return WriteJSON(w, app, http.StatusOK)
426474
}
@@ -432,26 +480,28 @@ func (api *API) detachRepositoriesManagerHandler() Handler {
432480
projectKey := vars["key"]
433481
appName := vars["permApplicationName"]
434482
rmName := vars["name"]
483+
db := api.mustDB()
484+
u := getUser(ctx)
435485

436-
app, errl := application.LoadByName(api.mustDB(), api.Cache, projectKey, appName, getUser(ctx), application.LoadOptions.WithHooks)
486+
app, errl := application.LoadByName(db, api.Cache, projectKey, appName, u, application.LoadOptions.WithHooks)
437487
if errl != nil {
438488
return sdk.WrapError(errl, "detachRepositoriesManager> error on load project %s", projectKey)
439489
}
440490

441491
//Load the repositoriesManager for the project
442-
rm, err := repositoriesmanager.LoadForProject(api.mustDB(), projectKey, rmName)
492+
rm, err := repositoriesmanager.LoadForProject(db, projectKey, rmName)
443493
if err != nil {
444494
return sdk.WrapError(sdk.ErrNoReposManager, "attachRepositoriesManager> error loading %s-%s: %s", projectKey, rmName, err)
445495
}
446496

447497
//Get an authorized Client
448-
client, err := repositoriesmanager.AuthorizedClient(api.mustDB(), api.Cache, rm)
498+
client, err := repositoriesmanager.AuthorizedClient(db, api.Cache, rm)
449499
if err != nil {
450500
return sdk.WrapError(sdk.ErrNoReposManagerClientAuth, "attachRepositoriesManager> Cannot get client got %s %s : %s", projectKey, rmName, err)
451501
}
452502

453503
//Remove all the things in a transaction
454-
tx, errT := api.mustDB().Begin()
504+
tx, errT := db.Begin()
455505
if errT != nil {
456506
return sdk.WrapError(errT, "detachRepositoriesManager> Cannot start transaction")
457507
}
@@ -461,6 +511,7 @@ func (api *API) detachRepositoriesManagerHandler() Handler {
461511
return sdk.WrapError(err, "detachRepositoriesManager> Cannot delete for application")
462512
}
463513

514+
//TODO: to delete after DEPRECATED workflows are deleted
464515
for _, h := range app.Hooks {
465516
s := api.Config.URL.API + hook.HookLink
466517
link := fmt.Sprintf(s, h.UID, h.Project, h.Repository)
@@ -487,15 +538,66 @@ func (api *API) detachRepositoriesManagerHandler() Handler {
487538
return sdk.WrapError(err, "detachRepositoriesManager> error on poller.DeleteAll")
488539
}
489540

490-
if err := application.UpdateLastModified(tx, api.Cache, app, getUser(ctx)); err != nil {
541+
if err := application.UpdateLastModified(tx, api.Cache, app, u); err != nil {
491542
return sdk.WrapError(err, "detachRepositoriesManager> Cannot update application last modified date")
492543
}
493544

494545
if err := tx.Commit(); err != nil {
495546
return sdk.WrapError(err, "detachRepositoriesManager> Cannot commit transaction")
496547
}
497548

498-
event.PublishApplicationRepositoryDelete(projectKey, appName, app.VCSServer, app.RepositoryFullname, getUser(ctx))
549+
usage, errU := loadApplicationUsage(db, projectKey, appName)
550+
if errU != nil {
551+
return sdk.WrapError(errU, "detachRepositoriesManager> Cannot load application usage")
552+
}
553+
554+
// Update default payload of linked workflow root
555+
if len(usage.Workflows) > 0 {
556+
proj, errP := project.Load(db, api.Cache, projectKey, u)
557+
if errP != nil {
558+
return sdk.WrapError(errP, "detachRepositoriesManager> Cannot load project")
559+
}
560+
561+
hookToDelete := map[string]sdk.WorkflowNodeHook{}
562+
for _, wf := range usage.Workflows {
563+
nodeHooks, err := workflow.LoadHooksByNodeID(db, wf.RootID)
564+
if err != nil {
565+
return sdk.WrapError(err, "detachRepositoriesManager> Cannot load node hook by nodeID %d", wf.RootID)
566+
}
567+
568+
for _, nodeHook := range nodeHooks {
569+
if nodeHook.WorkflowHookModel.Name != sdk.RepositoryWebHookModelName && nodeHook.WorkflowHookModel.Name != sdk.GitPollerModelName {
570+
continue
571+
}
572+
hookToDelete[nodeHook.UUID] = nodeHook
573+
}
574+
}
575+
576+
if len(hookToDelete) > 0 {
577+
txDel, errTx := db.Begin()
578+
if errTx != nil {
579+
return sdk.WrapError(errTx, "detachRepositoriesManager> Cannot create delete transaction")
580+
}
581+
defer func() {
582+
_ = txDel.Rollback()
583+
}()
584+
585+
for _, nodeHook := range hookToDelete {
586+
if err := workflow.DeleteHook(txDel, &nodeHook); err != nil {
587+
return sdk.WrapError(err, "detachRepositoriesManager> Cannot delete hooks")
588+
}
589+
}
590+
if err := workflow.DeleteHookConfiguration(txDel, api.Cache, proj, hookToDelete); err != nil {
591+
return sdk.WrapError(err, "detachRepositoriesManager> Cannot delete hooks vcs configuration")
592+
}
593+
594+
if err := txDel.Commit(); err != nil {
595+
return sdk.WrapError(err, "detachRepositoriesManager> Cannot commit delete transaction")
596+
}
597+
}
598+
}
599+
600+
event.PublishApplicationRepositoryDelete(projectKey, appName, app.VCSServer, app.RepositoryFullname, u)
499601

500602
return WriteJSON(w, app, http.StatusOK)
501603
}

engine/api/workflow/dao.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,7 @@ func Delete(db gorp.SqlExecutor, store cache.Store, p *sdk.Project, w *sdk.Workf
653653

654654
hooks := w.GetHooks()
655655
// Delete all hooks
656-
if err := deleteHookConfiguration(db, store, p, hooks); err != nil {
656+
if err := DeleteHookConfiguration(db, store, p, hooks); err != nil {
657657
return sdk.WrapError(err, "Delete> Unable to delete hooks from workflow")
658658
}
659659

engine/api/workflow/dao_hook.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,15 @@ func UpdateHook(db gorp.SqlExecutor, h *sdk.WorkflowNodeHook) error {
2424
return nil
2525
}
2626

27+
// DeleteHook Delete a workflow node hook
28+
func DeleteHook(db gorp.SqlExecutor, h *sdk.WorkflowNodeHook) error {
29+
dbhook := NodeHook(*h)
30+
if _, err := db.Delete(&dbhook); err != nil {
31+
return sdk.WrapError(err, "updateHook> Cannot update hook")
32+
}
33+
return nil
34+
}
35+
2736
// insertHook inserts a hook
2837
func insertHook(db gorp.SqlExecutor, node *sdk.WorkflowNode, hook *sdk.WorkflowNodeHook) error {
2938
hook.WorkflowNodeID = node.ID
@@ -193,3 +202,29 @@ func LoadHookByUUID(db gorp.SqlExecutor, uuid string) (*sdk.WorkflowNodeHook, er
193202

194203
return &wNodeHook, nil
195204
}
205+
206+
// LoadHooksByNodeID loads hooks linked to a nodeID
207+
func LoadHooksByNodeID(db gorp.SqlExecutor, nodeID int64) ([]sdk.WorkflowNodeHook, error) {
208+
query := `
209+
SELECT id, uuid, ref, workflow_hook_model_id, workflow_node_id
210+
FROM workflow_node_hook
211+
WHERE workflow_node_id = $1`
212+
213+
res := []NodeHook{}
214+
if _, err := db.Select(&res, query, nodeID); err != nil {
215+
if err == sql.ErrNoRows {
216+
return nil, nil
217+
}
218+
return nil, sdk.WrapError(err, "LoadHookByNodeID>")
219+
}
220+
221+
nodeHooks := make([]sdk.WorkflowNodeHook, len(res))
222+
for i, nh := range res {
223+
if err := nh.PostGet(db); err != nil {
224+
return nil, sdk.WrapError(err, "LoadHookByNodeID> cannot load postget")
225+
}
226+
nodeHooks[i] = sdk.WorkflowNodeHook(nh)
227+
}
228+
229+
return nodeHooks, nil
230+
}

engine/api/workflow/hook.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,14 +155,15 @@ func HookRegistration(db gorp.SqlExecutor, store cache.Store, oldW *sdk.Workflow
155155
}
156156

157157
if len(hookToDelete) > 0 {
158-
if err := deleteHookConfiguration(db, store, p, hookToDelete); err != nil {
158+
if err := DeleteHookConfiguration(db, store, p, hookToDelete); err != nil {
159159
return sdk.WrapError(err, "HookRegistration> Cannot remove hook configuration")
160160
}
161161
}
162162
return nil
163163
}
164164

165-
func deleteHookConfiguration(db gorp.SqlExecutor, store cache.Store, p *sdk.Project, hookToDelete map[string]sdk.WorkflowNodeHook) error {
165+
// DeleteHookConfiguration delete hooks configuration (and their vcs configuration)
166+
func DeleteHookConfiguration(db gorp.SqlExecutor, store cache.Store, p *sdk.Project, hookToDelete map[string]sdk.WorkflowNodeHook) error {
166167
// Delete from vcs configuration if needed
167168
for _, h := range hookToDelete {
168169
if h.WorkflowHookModel.Name == sdk.RepositoryWebHookModelName {

ui/src/app/service/application/application.store.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
import {BehaviorSubject, Observable, of as observableOf} from 'rxjs';
32

43
import {Injectable} from '@angular/core';
@@ -15,6 +14,7 @@ import {Scheduler} from '../../model/scheduler.model';
1514
import {Trigger} from '../../model/trigger.model';
1615
import {Variable} from '../../model/variable.model';
1716
import {ProjectStore} from '../project/project.store';
17+
import {WorkflowStore} from '../workflow/workflow.store';
1818
import {ApplicationService} from './application.service';
1919

2020
import {Key} from '../../model/keys.model';
@@ -33,7 +33,10 @@ export class ApplicationStore {
3333
new BehaviorSubject(immutable.List<NavbarRecentData>());
3434

3535

36-
constructor(private _applicationService: ApplicationService, private _projectStore: ProjectStore) {
36+
constructor(
37+
private _applicationService: ApplicationService,
38+
private _projectStore: ProjectStore,
39+
private _workflowStore: WorkflowStore) {
3740
this.loadRecentApplication();
3841

3942
}
@@ -227,6 +230,9 @@ export class ApplicationStore {
227230
appToUpdate.vcs_server = app.vcs_server;
228231
appToUpdate.repository_fullname = app.repository_fullname;
229232
this._application.next(cache.set(appKey, appToUpdate));
233+
if (appToUpdate.usage && Array.isArray(appToUpdate.usage.workflows)) {
234+
appToUpdate.usage.workflows.forEach((wf) => this._workflowStore.removeFromStore(key + '-' + wf.name));
235+
}
230236
}
231237
return app;
232238
}));
@@ -248,6 +254,9 @@ export class ApplicationStore {
248254
delete pToUpdate.vcs_server;
249255
delete pToUpdate.repository_fullname;
250256
this._application.next(cache.set(appKey, pToUpdate));
257+
if (pToUpdate.usage && Array.isArray(pToUpdate.usage.workflows)) {
258+
pToUpdate.usage.workflows.forEach((wf) => this._workflowStore.removeFromStore(key + '-' + wf.name));
259+
}
251260
}
252261
return app;
253262
}));

0 commit comments

Comments
 (0)