Skip to content

Commit

Permalink
feat(webhook): automatically cancel previous build
Browse files Browse the repository at this point in the history
  • Loading branch information
Jian Zeng committed Dec 30, 2020
1 parent a793e99 commit be48578
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 11 deletions.
5 changes: 4 additions & 1 deletion pkg/server/handler/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,15 @@ type JSONPatch struct {
}

// BuildWfrStatusPatch builds patch for updating status of workflowrun
func BuildWfrStatusPatch(statusPhase v1alpha1.StatusPhase) ([]byte, error) {
func BuildWfrStatusPatch(statusPhase v1alpha1.StatusPhase, reason string) ([]byte, error) {
now := metav1.Time{Time: time.Now()}

p := map[string]string{
"/status/overall/phase": string(statusPhase),
"/status/overall/lastTransitionTime": now.UTC().Format(time.RFC3339),
}
if len(reason) > 0 {
p["/status/overall/reason"] = reason
}
return BuildPatch(p)
}
38 changes: 37 additions & 1 deletion pkg/server/handler/v1alpha1/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ func HandleWebhook(ctx context.Context, tenant, eventType, integration string) (

func createWorkflowRun(tenant string, wft v1alpha1.WorkflowTrigger, data *scm.EventData) error {
ns := wft.Namespace
cancelPrevious := false
var err error
var project string
if wft.Labels != nil {
Expand Down Expand Up @@ -144,19 +145,22 @@ func createWorkflowRun(tenant string, wft v1alpha1.WorkflowTrigger, data *scm.Ev
// Always trigger if Branches are not specified
if len(st.PullRequest.Branches) == 0 {
trigger = true
cancelPrevious = true
break
}

for _, branch := range st.PullRequest.Branches {
if branch == data.Branch {
trigger = true
cancelPrevious = true
break
}
}
case scm.PullRequestCommentEventType:
for _, comment := range st.PullRequestComment.Comments {
if comment == data.Comment {
trigger = true
cancelPrevious = true
break
}
}
Expand Down Expand Up @@ -236,7 +240,8 @@ func createWorkflowRun(tenant string, wft v1alpha1.WorkflowTrigger, data *scm.Ev
}

accelerator.NewAccelerator(tenant, project, wfr).Accelerate()
_, err = handler.K8sClient.CycloneV1alpha1().WorkflowRuns(ns).Create(wfr)
cycloneClient := handler.K8sClient.CycloneV1alpha1()
_, err = cycloneClient.WorkflowRuns(ns).Create(wfr)
if err != nil {
return cerr.ConvertK8sError(err)
}
Expand All @@ -248,5 +253,36 @@ func createWorkflowRun(tenant string, wft v1alpha1.WorkflowTrigger, data *scm.Ev
if err != nil {
log.Warningf("Init pull request status for %s error: %v", wfr.Name, err)
}

if !cancelPrevious {
return nil
}
wfrs, err := cycloneClient.WorkflowRuns(ns).List(metav1.ListOptions{
LabelSelector: fmt.Sprintf("%s=%s,%s=%s",
meta.LabelProjectName, project,
meta.LabelWorkflowName, wfName),
})
if err == nil {
log.Infof("Trying to cancel %d previous builds", len(wfrs.Items))
for _, item := range wfrs.Items {
if item.Annotations == nil {
continue
}
evtType := scm.EventType(item.Annotations[meta.AnnotationWorkflowRunTrigger])
if (evtType != scm.PullRequestEventType && evtType != scm.PullRequestCommentEventType) ||
// skip the WorkflowRun created above
item.Name == name {
continue
}
_, err := stopWorkflowRun(context.TODO(), &item, "AutoCancelPreviousBuild")
if err != nil {
log.Warningf("Stop previous WorkflowRun: %v. project=%s, workflow=%s, trigger=%s, name=%s", err,
project, wfName, data.Type, item.Name)
}
}
} else {
log.Warningf("Fail to list previous WorkflowRuns: %v. project=%s, workflow=%s, trigger=%s", err,
project, wfName, data.Type)
}
return nil
}
23 changes: 14 additions & 9 deletions pkg/server/handler/v1alpha1/workflowrun.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,27 +211,32 @@ func StopWorkflowRun(ctx context.Context, project, workflow, workflowrun, tenant
return nil, cerr.ConvertK8sError(err)
}

wfr, err = stopWorkflowRun(ctx, wfr, "ManuallyStop")
if err != nil {
log.Errorf("Stop WorkflowRun %s error %s", workflowrun, err)
return nil, cerr.ConvertK8sError(err)
}
return wfr, nil
}

func stopWorkflowRun(ctx context.Context, wfr *v1alpha1.WorkflowRun, reason string) (*v1alpha1.WorkflowRun, error) {
// If wfr already in terminated state, skip it
if wfr.Status.Overall.Phase == v1alpha1.StatusSucceeded ||
wfr.Status.Overall.Phase == v1alpha1.StatusFailed ||
wfr.Status.Overall.Phase == v1alpha1.StatusCancelled {
return wfr, nil
}

data, err := handler.BuildWfrStatusPatch(v1alpha1.StatusCancelled)
data, err := handler.BuildWfrStatusPatch(v1alpha1.StatusCancelled, reason)
if err != nil {
log.Errorf("Stop WorkflowRun %s error %s", workflowrun, err)
return nil, err
}

wfr, err = handler.K8sClient.CycloneV1alpha1().WorkflowRuns(common.TenantNamespace(tenant)).Patch(workflowrun, k8s_types.JSONPatchType, data)

return wfr, cerr.ConvertK8sError(err)
wfr, err = handler.K8sClient.CycloneV1alpha1().WorkflowRuns(wfr.Namespace).Patch(wfr.Name, k8s_types.JSONPatchType, data)
return wfr, err
}

// PauseWorkflowRun updates the workflowrun overall status to Waiting.
func PauseWorkflowRun(ctx context.Context, project, workflow, workflowrun, tenant string) (*v1alpha1.WorkflowRun, error) {
data, err := handler.BuildWfrStatusPatch(v1alpha1.StatusWaiting)
data, err := handler.BuildWfrStatusPatch(v1alpha1.StatusWaiting, "ManuallyPause")
if err != nil {
log.Errorf("pause workflowrun %s error %s", workflowrun, err)
return nil, err
Expand All @@ -244,7 +249,7 @@ func PauseWorkflowRun(ctx context.Context, project, workflow, workflowrun, tenan

// ResumeWorkflowRun updates the workflowrun overall status to Running.
func ResumeWorkflowRun(ctx context.Context, project, workflow, workflowrun, tenant string) (*v1alpha1.WorkflowRun, error) {
data, err := handler.BuildWfrStatusPatch(v1alpha1.StatusRunning)
data, err := handler.BuildWfrStatusPatch(v1alpha1.StatusRunning, "ManuallyResume")
if err != nil {
log.Errorf("continue workflowrun %s error %s", workflowrun, err)
return nil, err
Expand Down

0 comments on commit be48578

Please sign in to comment.