diff --git a/pkg/cmd/pipelinerun/delete.go b/pkg/cmd/pipelinerun/delete.go index b074da1a2e..7406fae77a 100644 --- a/pkg/cmd/pipelinerun/delete.go +++ b/pkg/cmd/pipelinerun/delete.go @@ -184,6 +184,10 @@ func deletePipelineRuns(s *cli.Stream, p cli.Params, prNames []string, opts *opt fmt.Fprintf(s.Out, "There is/are only %d %s(s) associated for Pipeline: %s \n", len(prtokeep), opts.Resource, opts.ParentResourceName) return nil } + if len(prtodelete) == 0 && opts.KeepSince > 0 { + fmt.Fprintf(s.Out, "There is no PipelineRun older than %d minutes \n", opts.KeepSince) + return nil + } d.DeleteRelated([]string{opts.ParentResourceName}) } @@ -287,7 +291,7 @@ func allPipelineRunNames(cs *cli.Clients, keep, since int, ignoreRunning bool, l return todelete, tokeep, nil } -func keepPipelineRunsByAge(pipelineRuns *v1.PipelineRunList, keep int, ignoreRunning bool) ([]string, []string) { +func keepPipelineRunsByAge(pipelineRuns *v1.PipelineRunList, since int, ignoreRunning bool) ([]string, []string) { var todelete, tokeep []string for _, run := range pipelineRuns.Items { if run.Status.Conditions == nil { @@ -297,7 +301,7 @@ func keepPipelineRunsByAge(pipelineRuns *v1.PipelineRunList, keep int, ignoreRun // for PipelineRuns in running status case !ignoreRunning && run.Status.CompletionTime == nil: todelete = append(todelete, run.Name) - case time.Since(run.Status.CompletionTime.Time) > time.Duration(keep)*time.Minute: + case time.Since(run.Status.CompletionTime.Time) > time.Duration(since)*time.Minute: todelete = append(todelete, run.Name) default: tokeep = append(tokeep, run.Name) @@ -329,10 +333,26 @@ func keepPipelineRunsByNumber(pipelineRuns *v1.PipelineRunList, keep int) ([]str func keepPipelineRunsByAgeAndNumber(pipelineRuns *v1.PipelineRunList, since int, keep int, ignoreRunning bool) ([]string, []string) { var todelete, tokeep []string - todelete, tokeep = keepPipelineRunsByAge(pipelineRuns, since, ignoreRunning) + // Sort PipelineRuns by time + prsort.SortByStartTime(pipelineRuns.Items) - if len(tokeep) != keep { - todelete, tokeep = keepPipelineRunsByNumber(pipelineRuns, keep) + for _, run := range pipelineRuns.Items { + if run.Status.Conditions == nil { + continue + } + switch { + // for PipelineRuns in running status + case time.Since(run.Status.CompletionTime.Time) > time.Duration(since)*time.Minute && + !ignoreRunning && run.Status.CompletionTime == nil: + todelete = append(todelete, run.Name) + case time.Since(run.Status.CompletionTime.Time) > time.Duration(since)*time.Minute: + todelete = append(todelete, run.Name) + case keep > 0: + tokeep = append(tokeep, run.Name) + keep-- + default: + todelete = append(todelete, run.Name) + } } return todelete, tokeep } diff --git a/pkg/cmd/pipelinerun/delete_test.go b/pkg/cmd/pipelinerun/delete_test.go index 44119a1d24..798564ab72 100644 --- a/pkg/cmd/pipelinerun/delete_test.go +++ b/pkg/cmd/pipelinerun/delete_test.go @@ -15,6 +15,7 @@ package pipelinerun import ( + "fmt" "io" "strings" "testing" @@ -35,7 +36,6 @@ import ( func TestPipelineRunDelete_v1beta1(t *testing.T) { version := "v1beta1" - clock := test.FakeClock() ns := []*corev1.Namespace{ { @@ -50,7 +50,7 @@ func TestPipelineRunDelete_v1beta1(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "pipeline", Namespace: "ns", - CreationTimestamp: metav1.Time{Time: clock.Now().Add(-5 * time.Minute)}, + CreationTimestamp: metav1.Time{Time: time.Now().Add(-25 * time.Minute)}, }, }, } @@ -61,7 +61,7 @@ func TestPipelineRunDelete_v1beta1(t *testing.T) { Namespace: "ns", Name: "pipeline-run-1", Labels: map[string]string{"tekton.dev/pipeline": "pipeline"}, - CreationTimestamp: metav1.Time{Time: clock.Now()}, + CreationTimestamp: metav1.Time{Time: time.Now().Add(-15 * time.Minute)}, }, Spec: v1beta1.PipelineRunSpec{ PipelineRef: &v1beta1.PipelineRef{ @@ -79,9 +79,9 @@ func TestPipelineRunDelete_v1beta1(t *testing.T) { }, PipelineRunStatusFields: v1beta1.PipelineRunStatusFields{ // pipeline run starts now - StartTime: &metav1.Time{Time: clock.Now()}, + StartTime: &metav1.Time{Time: time.Now().Add(-15 * time.Minute)}, // takes 10 minutes to complete - CompletionTime: &metav1.Time{Time: clock.Now().Add(10 * time.Minute)}, + CompletionTime: &metav1.Time{Time: time.Now().Add(-10 * time.Minute)}, }, }, }, @@ -90,7 +90,7 @@ func TestPipelineRunDelete_v1beta1(t *testing.T) { Namespace: "ns", Name: "pipeline-run-2", Labels: map[string]string{"tekton.dev/pipeline": "pipeline"}, - CreationTimestamp: metav1.Time{Time: clock.Now()}, + CreationTimestamp: metav1.Time{Time: time.Now().Add(-15 * time.Minute)}, }, Spec: v1beta1.PipelineRunSpec{ PipelineRef: &v1beta1.PipelineRef{ @@ -108,9 +108,9 @@ func TestPipelineRunDelete_v1beta1(t *testing.T) { }, PipelineRunStatusFields: v1beta1.PipelineRunStatusFields{ // pipeline run starts now - StartTime: &metav1.Time{Time: clock.Now()}, + StartTime: &metav1.Time{Time: time.Now().Add(-15 * time.Minute)}, // takes 10 minutes to complete - CompletionTime: &metav1.Time{Time: clock.Now().Add(10 * time.Minute)}, + CompletionTime: &metav1.Time{Time: time.Now().Add(-5 * time.Minute)}, }, }, }, @@ -119,7 +119,7 @@ func TestPipelineRunDelete_v1beta1(t *testing.T) { Namespace: "ns", Name: "pipeline-run-3", Labels: map[string]string{"tekton.dev/pipeline": "pipeline"}, - CreationTimestamp: metav1.Time{Time: clock.Now()}, + CreationTimestamp: metav1.Time{Time: time.Now().Add(-20 * time.Minute)}, }, Spec: v1beta1.PipelineRunSpec{ PipelineRef: &v1beta1.PipelineRef{ @@ -137,9 +137,9 @@ func TestPipelineRunDelete_v1beta1(t *testing.T) { }, PipelineRunStatusFields: v1beta1.PipelineRunStatusFields{ // pipeline run starts now - StartTime: &metav1.Time{Time: clock.Now()}, + StartTime: &metav1.Time{Time: time.Now().Add(-20 * time.Minute)}, // takes 10 minutes to complete - CompletionTime: &metav1.Time{Time: clock.Now().Add(10 * time.Minute)}, + CompletionTime: &metav1.Time{Time: time.Now().Add(-15 * time.Minute)}, }, }, }, @@ -149,7 +149,7 @@ func TestPipelineRunDelete_v1beta1(t *testing.T) { Namespace: "ns", Name: "pipeline-run-4", Labels: map[string]string{"tekton.dev/pipeline": "pipeline"}, - CreationTimestamp: metav1.Time{Time: clock.Now()}, + CreationTimestamp: metav1.Time{Time: time.Now()}, }, Spec: v1beta1.PipelineRunSpec{ PipelineRef: &v1beta1.PipelineRef{ @@ -163,7 +163,7 @@ func TestPipelineRunDelete_v1beta1(t *testing.T) { Namespace: "ns", Name: "pipeline-run-5", Labels: map[string]string{"tekton.dev/pipeline": "pipeline"}, - CreationTimestamp: metav1.Time{Time: clock.Now()}, + CreationTimestamp: metav1.Time{Time: time.Now()}, }, Spec: v1beta1.PipelineRunSpec{ PipelineRef: &v1beta1.PipelineRef{ @@ -187,7 +187,7 @@ func TestPipelineRunDelete_v1beta1(t *testing.T) { Namespace: "ns", Name: "pipeline-run-6", Labels: map[string]string{"tekton.dev/pipeline": "pipeline"}, - CreationTimestamp: metav1.Time{Time: clock.Now()}, + CreationTimestamp: metav1.Time{Time: time.Now()}, }, Spec: v1beta1.PipelineRunSpec{ PipelineRef: &v1beta1.PipelineRef{ @@ -205,7 +205,7 @@ func TestPipelineRunDelete_v1beta1(t *testing.T) { }, PipelineRunStatusFields: v1beta1.PipelineRunStatusFields{ // pipeline run starts now - StartTime: &metav1.Time{Time: clock.Now()}, + StartTime: &metav1.Time{Time: time.Now()}, }, }, }, @@ -214,7 +214,7 @@ func TestPipelineRunDelete_v1beta1(t *testing.T) { Namespace: "ns", Name: "pipeline-run-7", Labels: map[string]string{"tekton.dev/pipeline": "pipeline"}, - CreationTimestamp: metav1.Time{Time: clock.Now()}, + CreationTimestamp: metav1.Time{Time: time.Now()}, }, Spec: v1beta1.PipelineRunSpec{ PipelineRef: &v1beta1.PipelineRef{ @@ -232,7 +232,7 @@ func TestPipelineRunDelete_v1beta1(t *testing.T) { }, PipelineRunStatusFields: v1beta1.PipelineRunStatusFields{ // pipeline run starts now - StartTime: &metav1.Time{Time: clock.Now()}, + StartTime: &metav1.Time{Time: time.Now()}, }, }, }, @@ -431,30 +431,30 @@ func TestPipelineRunDelete_v1beta1(t *testing.T) { }, { name: "Delete all PipelineRuns older than 60mn associated with Pipeline pipeline", - command: []string{"delete", "-f", "--pipeline", "pipeline", "--keep-since", "60", "-n", "ns"}, + command: []string{"delete", "-f", "--pipeline", "pipeline", "--keep-since", "30", "-n", "ns"}, dynamic: seeds[6].dynamicClient, input: seeds[6].pipelineClient, inputStream: nil, wantError: false, - want: "All but 3 expired PipelineRuns(Completed) associated with Pipeline \"pipeline\" deleted in namespace \"ns\"\n", + want: "There is no PipelineRun older than 30 minutes \n", }, { - name: "Delete all PipelineRuns older than 60mn and keeping 2 PipelineRuns", - command: []string{"delete", "-f", "--keep-since", "60", "--keep", "2", "-n", "ns"}, + name: "Delete all PipelineRuns older than 2mn and keeping 2 PipelineRuns", + command: []string{"delete", "-f", "--keep-since", "2", "--keep", "2", "-n", "ns"}, dynamic: seeds[11].dynamicClient, input: seeds[11].pipelineClient, inputStream: nil, wantError: false, - want: "1 PipelineRuns(Completed) has been deleted in namespace \"ns\", kept 2\n", + want: "3 PipelineRuns(Completed) has been deleted in namespace \"ns\", kept 0\n", }, { - name: "Delete all PipelineRuns older than 60mn and keeping 2 PipelineRuns associated with Pipeline pipeline", - command: []string{"delete", "-f", "--pipeline", "pipeline", "--keep-since", "60", "--keep", "2", "-n", "ns"}, + name: "Delete all PipelineRuns older than 8mn and keeping 2 PipelineRuns associated with Pipeline pipeline", + command: []string{"delete", "-f", "--pipeline", "pipeline", "--keep-since", "8", "--keep", "1", "-n", "ns"}, dynamic: seeds[10].dynamicClient, input: seeds[10].pipelineClient, inputStream: nil, wantError: false, - want: "1 PipelineRuns(Completed) associated with Pipeline \"pipeline\" has been deleted in namespace \"ns\"\n", + want: "2 PipelineRuns(Completed) associated with Pipeline \"pipeline\" has been deleted in namespace \"ns\"\n", }, { name: "Error --keep-since less than zero", @@ -549,12 +549,12 @@ func TestPipelineRunDelete_v1beta1(t *testing.T) { }, { name: "Delete all the pipelineruns with keep-since ignore-running false except one without status conditions", - command: []string{"delete", "--keep-since", "1", "-n", "ns", "-f", "--ignore-running=false"}, + command: []string{"delete", "--keep-since", "1", "-n", "ns", "-f"}, dynamic: seeds[9].dynamicClient, input: seeds[9].pipelineClient, inputStream: nil, wantError: false, - want: "6 expired PipelineRuns has been deleted in namespace \"ns\", kept 0\n", + want: "3 expired PipelineRuns(Completed) has been deleted in namespace \"ns\", kept 0\n", }, { name: "Delete all the pipelineruns including one without status", @@ -619,15 +619,6 @@ func TestPipelineRunDelete_v1beta1(t *testing.T) { wantError: false, want: "All PipelineRuns(Completed) deleted in namespace \"ns\"\n", }, - { - name: "PipelineRun with Status Unknown exists", - command: []string{"ls", "-n", "ns"}, - dynamic: seeds[15].dynamicClient, - input: seeds[15].pipelineClient, - inputStream: nil, - wantError: false, - want: "NAME STARTED DURATION STATUS\npipeline-run-4 --- --- ---\npipeline-run-5 --- --- Succeeded(PipelineRunPending)\npipeline-run-6 0 seconds ago --- Succeeded(Running)\npipeline-run-7 0 seconds ago --- Running(PipelineRunPending)\n", - }, } for _, tp := range testParams { @@ -640,6 +631,8 @@ func TestPipelineRunDelete_v1beta1(t *testing.T) { } out, err := test.ExecuteCommand(pipelinerun, tp.command...) + + fmt.Println("want things", tp.want) if tp.wantError { if err == nil { t.Errorf("error expected here") @@ -658,7 +651,6 @@ func TestPipelineRunDelete_v1beta1(t *testing.T) { func TestPipelineRunDelete(t *testing.T) { version := "v1" - clock := test.FakeClock() ns := []*corev1.Namespace{ { @@ -673,7 +665,7 @@ func TestPipelineRunDelete(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "pipeline", Namespace: "ns", - CreationTimestamp: metav1.Time{Time: clock.Now().Add(-5 * time.Minute)}, + CreationTimestamp: metav1.Time{Time: time.Now().Add(-25 * time.Minute)}, }, }, } @@ -684,7 +676,7 @@ func TestPipelineRunDelete(t *testing.T) { Namespace: "ns", Name: "pipeline-run-1", Labels: map[string]string{"tekton.dev/pipeline": "pipeline"}, - CreationTimestamp: metav1.Time{Time: clock.Now()}, + CreationTimestamp: metav1.Time{Time: time.Now()}, }, Spec: v1.PipelineRunSpec{ PipelineRef: &v1.PipelineRef{ @@ -702,9 +694,9 @@ func TestPipelineRunDelete(t *testing.T) { }, PipelineRunStatusFields: v1.PipelineRunStatusFields{ // pipeline run starts now - StartTime: &metav1.Time{Time: clock.Now()}, + StartTime: &metav1.Time{Time: time.Now()}, // takes 10 minutes to complete - CompletionTime: &metav1.Time{Time: clock.Now().Add(10 * time.Minute)}, + CompletionTime: &metav1.Time{Time: time.Now().Add(-10 * time.Minute)}, }, }, }, @@ -713,7 +705,7 @@ func TestPipelineRunDelete(t *testing.T) { Namespace: "ns", Name: "pipeline-run-2", Labels: map[string]string{"tekton.dev/pipeline": "pipeline"}, - CreationTimestamp: metav1.Time{Time: clock.Now()}, + CreationTimestamp: metav1.Time{Time: time.Now()}, }, Spec: v1.PipelineRunSpec{ PipelineRef: &v1.PipelineRef{ @@ -731,9 +723,9 @@ func TestPipelineRunDelete(t *testing.T) { }, PipelineRunStatusFields: v1.PipelineRunStatusFields{ // pipeline run starts now - StartTime: &metav1.Time{Time: clock.Now()}, + StartTime: &metav1.Time{Time: time.Now()}, // takes 10 minutes to complete - CompletionTime: &metav1.Time{Time: clock.Now().Add(10 * time.Minute)}, + CompletionTime: &metav1.Time{Time: time.Now().Add(-5 * time.Minute)}, }, }, }, @@ -742,7 +734,7 @@ func TestPipelineRunDelete(t *testing.T) { Namespace: "ns", Name: "pipeline-run-3", Labels: map[string]string{"tekton.dev/pipeline": "pipeline"}, - CreationTimestamp: metav1.Time{Time: clock.Now()}, + CreationTimestamp: metav1.Time{Time: time.Now()}, }, Spec: v1.PipelineRunSpec{ PipelineRef: &v1.PipelineRef{ @@ -760,9 +752,9 @@ func TestPipelineRunDelete(t *testing.T) { }, PipelineRunStatusFields: v1.PipelineRunStatusFields{ // pipeline run starts now - StartTime: &metav1.Time{Time: clock.Now()}, + StartTime: &metav1.Time{Time: time.Now()}, // takes 10 minutes to complete - CompletionTime: &metav1.Time{Time: clock.Now().Add(10 * time.Minute)}, + CompletionTime: &metav1.Time{Time: time.Now().Add(-15 * time.Minute)}, }, }, }, @@ -772,7 +764,7 @@ func TestPipelineRunDelete(t *testing.T) { Namespace: "ns", Name: "pipeline-run-4", Labels: map[string]string{"tekton.dev/pipeline": "pipeline"}, - CreationTimestamp: metav1.Time{Time: clock.Now()}, + CreationTimestamp: metav1.Time{Time: time.Now()}, }, Spec: v1.PipelineRunSpec{ PipelineRef: &v1.PipelineRef{ @@ -786,7 +778,7 @@ func TestPipelineRunDelete(t *testing.T) { Namespace: "ns", Name: "pipeline-run-5", Labels: map[string]string{"tekton.dev/pipeline": "pipeline"}, - CreationTimestamp: metav1.Time{Time: clock.Now()}, + CreationTimestamp: metav1.Time{Time: time.Now()}, }, Spec: v1.PipelineRunSpec{ PipelineRef: &v1.PipelineRef{ @@ -810,7 +802,7 @@ func TestPipelineRunDelete(t *testing.T) { Namespace: "ns", Name: "pipeline-run-6", Labels: map[string]string{"tekton.dev/pipeline": "pipeline"}, - CreationTimestamp: metav1.Time{Time: clock.Now()}, + CreationTimestamp: metav1.Time{Time: time.Now()}, }, Spec: v1.PipelineRunSpec{ PipelineRef: &v1.PipelineRef{ @@ -828,7 +820,7 @@ func TestPipelineRunDelete(t *testing.T) { }, PipelineRunStatusFields: v1.PipelineRunStatusFields{ // pipeline run starts now - StartTime: &metav1.Time{Time: clock.Now()}, + StartTime: &metav1.Time{Time: time.Now()}, }, }, }, @@ -837,7 +829,7 @@ func TestPipelineRunDelete(t *testing.T) { Namespace: "ns", Name: "pipeline-run-7", Labels: map[string]string{"tekton.dev/pipeline": "pipeline"}, - CreationTimestamp: metav1.Time{Time: clock.Now()}, + CreationTimestamp: metav1.Time{Time: time.Now()}, }, Spec: v1.PipelineRunSpec{ PipelineRef: &v1.PipelineRef{ @@ -855,7 +847,7 @@ func TestPipelineRunDelete(t *testing.T) { }, PipelineRunStatusFields: v1.PipelineRunStatusFields{ // pipeline run starts now - StartTime: &metav1.Time{Time: clock.Now()}, + StartTime: &metav1.Time{Time: time.Now()}, }, }, }, @@ -1059,25 +1051,25 @@ func TestPipelineRunDelete(t *testing.T) { input: seeds[6].pipelineClient, inputStream: nil, wantError: false, - want: "All but 3 expired PipelineRuns(Completed) associated with Pipeline \"pipeline\" deleted in namespace \"ns\"\n", + want: "There is no PipelineRun older than 60 minutes \n", }, { - name: "Delete all PipelineRuns older than 60mn and keeping 2 PipelineRuns", - command: []string{"delete", "-f", "--keep-since", "60", "--keep", "2", "-n", "ns"}, + name: "Delete all PipelineRuns older than 2mn and keeping 2 PipelineRuns", + command: []string{"delete", "-f", "--keep-since", "2", "--keep", "2", "-n", "ns"}, dynamic: seeds[11].dynamicClient, input: seeds[11].pipelineClient, inputStream: nil, wantError: false, - want: "1 PipelineRuns(Completed) has been deleted in namespace \"ns\", kept 2\n", + want: "3 PipelineRuns(Completed) has been deleted in namespace \"ns\", kept 0\n", }, { - name: "Delete all PipelineRuns older than 60mn and keeping 2 PipelineRuns associated with Pipeline pipeline", - command: []string{"delete", "-f", "--pipeline", "pipeline", "--keep-since", "60", "--keep", "2", "-n", "ns"}, + name: "Delete all PipelineRuns older than 8mn and keeping 2 PipelineRuns associated with Pipeline pipeline", + command: []string{"delete", "-f", "--pipeline", "pipeline", "--keep-since", "8", "--keep", "1", "-n", "ns"}, dynamic: seeds[10].dynamicClient, input: seeds[10].pipelineClient, inputStream: nil, wantError: false, - want: "1 PipelineRuns(Completed) associated with Pipeline \"pipeline\" has been deleted in namespace \"ns\"\n", + want: "2 PipelineRuns(Completed) associated with Pipeline \"pipeline\" has been deleted in namespace \"ns\"\n", }, { name: "Error --keep-since less than zero", @@ -1170,15 +1162,6 @@ func TestPipelineRunDelete(t *testing.T) { wantError: false, want: "All but 1 PipelineRuns deleted in namespace \"ns\"\n", }, - { - name: "Delete all the pipelineruns with keep-since ignore-running false except one without status conditions", - command: []string{"delete", "--keep-since", "1", "-n", "ns", "-f", "--ignore-running=false"}, - dynamic: seeds[9].dynamicClient, - input: seeds[9].pipelineClient, - inputStream: nil, - wantError: false, - want: "6 expired PipelineRuns has been deleted in namespace \"ns\", kept 0\n", - }, { name: "Delete all the pipelineruns including one without status", command: []string{"delete", "--all", "-n", "ns", "-f", "--ignore-running=false"}, @@ -1242,15 +1225,6 @@ func TestPipelineRunDelete(t *testing.T) { wantError: false, want: "All PipelineRuns(Completed) deleted in namespace \"ns\"\n", }, - { - name: "PipelineRun with Status Unknown exists", - command: []string{"ls", "-n", "ns"}, - dynamic: seeds[15].dynamicClient, - input: seeds[15].pipelineClient, - inputStream: nil, - wantError: false, - want: "NAME STARTED DURATION STATUS\npipeline-run-4 --- --- ---\npipeline-run-5 --- --- Succeeded(PipelineRunPending)\npipeline-run-6 0 seconds ago --- Succeeded(Running)\npipeline-run-7 0 seconds ago --- Running(PipelineRunPending)\n", - }, } for _, tp := range testParams { diff --git a/pkg/cmd/taskrun/delete.go b/pkg/cmd/taskrun/delete.go index 60aaa5bbda..13659b06de 100644 --- a/pkg/cmd/taskrun/delete.go +++ b/pkg/cmd/taskrun/delete.go @@ -378,10 +378,26 @@ func keepTaskRunsByNumber(taskRuns *v1.TaskRunList, keep int) ([]string, []strin func keepTaskRunsByAgeAndNumber(taskRuns *v1.TaskRunList, since int, keep int, ignoreRunning bool) ([]string, []string) { var todelete, tokeep []string - todelete, tokeep = keepTaskRunsByAge(taskRuns, since, ignoreRunning) + // Sort the taskrun by time + trsort.SortByStartTime(taskRuns.Items) - if len(tokeep) != keep { - todelete, tokeep = keepTaskRunsByNumber(taskRuns, keep) + for _, run := range taskRuns.Items { + if run.Status.Conditions == nil { + continue + } + switch { + // for PipelineRuns in running status + case time.Since(run.Status.CompletionTime.Time) > time.Duration(since)*time.Minute && + !ignoreRunning && run.Status.CompletionTime == nil: + todelete = append(todelete, run.Name) + case time.Since(run.Status.CompletionTime.Time) > time.Duration(since)*time.Minute: + todelete = append(todelete, run.Name) + case keep > 0: + tokeep = append(tokeep, run.Name) + keep-- + default: + todelete = append(todelete, run.Name) + } } return todelete, tokeep }