diff --git a/pkg/cmd/clustertask/start.go b/pkg/cmd/clustertask/start.go index 8b65bc9e11..3e1fee5e80 100644 --- a/pkg/cmd/clustertask/start.go +++ b/pkg/cmd/clustertask/start.go @@ -210,31 +210,31 @@ func startClusterTask(opt startOptions, args []string) error { return err } - if opt.TimeOut != "" { - timeoutDuration, err := time.ParseDuration(opt.TimeOut) + if opt.Last || opt.UseTaskRun != "" { + taskRunOpts := options.TaskRunOpts{ + CliParams: opt.cliparams, + Last: opt.Last, + UseTaskRun: opt.UseTaskRun, + PrefixName: opt.PrefixName, + } + err := taskRunOpts.UseTaskRunFrom(tr, cs, ctname, "ClusterTask") if err != nil { return err } - tr.Spec.Timeout = &metav1.Duration{Duration: timeoutDuration} } - if opt.PrefixName == "" { + if opt.PrefixName == "" && !opt.Last && opt.UseTaskRun == "" { tr.ObjectMeta.GenerateName = ctname + "-run-" - } else { + } else if opt.PrefixName != "" { tr.ObjectMeta.GenerateName = opt.PrefixName + "-" } - if opt.Last || opt.UseTaskRun != "" { - taskRunOpts := options.TaskRunOpts{ - CliParams: opt.cliparams, - Last: opt.Last, - UseTaskRun: opt.UseTaskRun, - PrefixName: opt.PrefixName, - } - err := taskRunOpts.UseTaskRunFrom(tr, cs, ctname, "ClusterTask") + if opt.TimeOut != "" { + timeoutDuration, err := time.ParseDuration(opt.TimeOut) if err != nil { return err } + tr.Spec.Timeout = &metav1.Duration{Duration: timeoutDuration} } if tr.Spec.Resources == nil { diff --git a/pkg/cmd/clustertask/start_test.go b/pkg/cmd/clustertask/start_test.go index 6d211c8512..b2391d1a8e 100644 --- a/pkg/cmd/clustertask/start_test.go +++ b/pkg/cmd/clustertask/start_test.go @@ -1932,3 +1932,93 @@ func Test_start_use_taskrun_cancelled_status_v1beta1(t *testing.T) { // Assert that new TaskRun does not contain cancelled status of previous run test.AssertOutput(t, v1beta1.TaskRunSpecStatus(""), tr.Spec.Status) } + +func Test_start_clustertask_last_override_timeout(t *testing.T) { + ctasks := []*v1beta1.ClusterTask{ + { + ObjectMeta: v1.ObjectMeta{ + Name: "clustertask", + }, + Spec: v1beta1.TaskSpec{ + Steps: []v1beta1.Step{ + { + Container: corev1.Container{ + Name: "hello", + Image: "busybox", + }, + }, + { + Container: corev1.Container{ + Name: "exit", + Image: "busybox", + }, + }, + }, + }, + }, + } + + // Add timeout to last TaskRun for ClusterTask + timeoutDuration, _ := time.ParseDuration("10s") + trName := "ct-run" + taskruns := []*v1beta1.TaskRun{ + { + + ObjectMeta: v1.ObjectMeta{ + Name: trName, + Labels: map[string]string{"tekton.dev/clustertask": "clustertask"}, + Namespace: "ns", + }, + Spec: v1beta1.TaskRunSpec{ + TaskRef: &v1beta1.TaskRef{ + Name: "clustertask", + Kind: v1beta1.ClusterTaskKind, + }, + Timeout: &metav1.Duration{Duration: timeoutDuration}, + }, + }, + } + + ns := []*corev1.Namespace{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "ns", + }, + }, + } + + seedData, _ := test.SeedV1beta1TestData(t, pipelinev1beta1test.Data{Namespaces: ns, ClusterTasks: ctasks, TaskRuns: taskruns}) + objs := []runtime.Object{ctasks[0], taskruns[0]} + trName2 := trName + "-2" + tdc := newDynamicClientOpt(versionB1, trName2, objs...) + + cs := pipelinetest.Clients{ + Pipeline: seedData.Pipeline, + Kube: seedData.Kube, + } + cs.Pipeline.Resources = cb.APIResourceList(versionB1, []string{"clustertask", "taskrun"}) + dc, _ := tdc.Client( + cb.UnstructuredV1beta1CT(ctasks[0], versionB1), + cb.UnstructuredV1beta1TR(taskruns[0], versionB1), + ) + p := &test.Params{Tekton: cs.Pipeline, Kube: cs.Kube, Dynamic: dc} + + clustertask := Command(p) + // Specify new timeout value to override previous value + got, err := test.ExecuteCommand(clustertask, "start", "clustertask", "--use-taskrun", trName, "--timeout", "1s", "-n", "ns") + if err != nil { + t.Errorf("Error listing taskruns %s", err.Error()) + } + + expected := "TaskRun started: ct-run-2\n\nIn order to track the TaskRun progress run:\ntkn taskrun logs ct-run-2 -f -n ns\n" + test.AssertOutput(t, expected, got) + clients, _ := p.Clients() + tr, err := traction.Get(clients, trName2, metav1.GetOptions{}, "ns") + if err != nil { + t.Errorf("Error listing taskruns %s", err.Error()) + } + + // Assert newly started TaskRun has new timeout value + timeoutDuration, _ = time.ParseDuration("1s") + test.AssertOutput(t, timeoutDuration, tr.Spec.Timeout.Duration) +} diff --git a/pkg/cmd/pipeline/start.go b/pkg/cmd/pipeline/start.go index 06eeedd4f0..f02ccdc463 100644 --- a/pkg/cmd/pipeline/start.go +++ b/pkg/cmd/pipeline/start.go @@ -186,20 +186,14 @@ func (opt *startOptions) run(pipeline *v1beta1.Pipeline) error { } func (opt *startOptions) startPipeline(pipelineStart *v1beta1.Pipeline) error { - objMeta := metav1.ObjectMeta{ - Namespace: opt.cliparams.Namespace(), - } - if opt.PrefixName == "" { - objMeta.GenerateName = pipelineStart.ObjectMeta.Name + "-run-" - } else { - objMeta.GenerateName = opt.PrefixName + "-" - } - cs, err := opt.cliparams.Clients() if err != nil { return err } + objMeta := metav1.ObjectMeta{ + Namespace: opt.cliparams.Namespace(), + } var pr *v1beta1.PipelineRun if opt.Filename == "" { pr = &v1beta1.PipelineRun{ @@ -225,14 +219,6 @@ func (opt *startOptions) startPipeline(pipelineStart *v1beta1.Pipeline) error { } } - if opt.TimeOut != "" { - timeoutDuration, err := time.ParseDuration(opt.TimeOut) - if err != nil { - return err - } - pr.Spec.Timeout = &metav1.Duration{Duration: timeoutDuration} - } - if opt.Last || opt.UsePipelineRun != "" { var usepr *v1beta1.PipelineRun if opt.Last { @@ -247,18 +233,32 @@ func (opt *startOptions) startPipeline(pipelineStart *v1beta1.Pipeline) error { } } - // if --prefix-name is specified by user, allow name to be used for pipelinerun if len(usepr.ObjectMeta.GenerateName) > 0 && opt.PrefixName == "" { pr.ObjectMeta.GenerateName = usepr.ObjectMeta.GenerateName } else if opt.PrefixName == "" { pr.ObjectMeta.GenerateName = usepr.ObjectMeta.Name + "-" } + // Copy over spec from last or previous PipelineRun to use same values for this PipelineRun pr.Spec = usepr.Spec // Reapply blank status in case PipelineRun used was cancelled pr.Spec.Status = "" } + if opt.PrefixName == "" && !opt.Last && opt.UsePipelineRun == "" { + pr.ObjectMeta.GenerateName = pipelineStart.ObjectMeta.Name + "-run-" + } else if opt.PrefixName != "" { + pr.ObjectMeta.GenerateName = opt.PrefixName + "-" + } + + if opt.TimeOut != "" { + timeoutDuration, err := time.ParseDuration(opt.TimeOut) + if err != nil { + return err + } + pr.Spec.Timeout = &metav1.Duration{Duration: timeoutDuration} + } + if err := mergeRes(pr, opt.Resources); err != nil { return err } diff --git a/pkg/cmd/pipeline/start_test.go b/pkg/cmd/pipeline/start_test.go index a305192793..4a4dba1597 100644 --- a/pkg/cmd/pipeline/start_test.go +++ b/pkg/cmd/pipeline/start_test.go @@ -3331,6 +3331,199 @@ func Test_start_pipeline_last_v1beta1(t *testing.T) { test.AssertOutput(t, timeoutDuration, pr.Spec.Timeout.Duration) } +func Test_start_pipeline_last_override_timeout_v1beta1(t *testing.T) { + + pipelineName := "test-pipeline" + ps := []*v1beta1.Pipeline{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: pipelineName, + Namespace: "ns", + }, + Spec: v1beta1.PipelineSpec{ + Tasks: []v1beta1.PipelineTask{ + { + Name: "unit-test-1", + TaskRef: &v1beta1.TaskRef{ + Name: "unit-test-task", + }, + Resources: &v1beta1.PipelineTaskResources{ + Inputs: []v1beta1.PipelineTaskInputResource{ + { + Name: "workspace", + Resource: "git-repo", + }, + }, + Outputs: []v1beta1.PipelineTaskOutputResource{ + { + Name: "image-to-use", + Resource: "best-image", + }, + { + Name: "workspace", + Resource: "git-repo", + }, + }, + }, + Workspaces: []v1beta1.WorkspacePipelineTaskBinding{ + { + Name: "task-test-workspace", + Workspace: "test-workspace", + }, + }, + }, + }, + Resources: []v1beta1.PipelineDeclaredResource{ + { + Name: "git-repo", + Type: v1alpha1.PipelineResourceTypeGit, + }, + { + Name: "build-image", + Type: v1alpha1.PipelineResourceTypeImage, + }, + }, + Params: []v1beta1.ParamSpec{ + { + Name: "pipeline-param-1", + Type: v1beta1.ParamTypeString, + Default: &v1beta1.ArrayOrString{ + Type: v1beta1.ParamTypeString, + StringVal: "somethingdifferent-1", + }, + }, + { + Name: "rev-param", + Type: v1beta1.ParamTypeString, + Default: &v1beta1.ArrayOrString{ + Type: v1beta1.ParamTypeString, + StringVal: "revision", + }, + }, + }, + Workspaces: []v1beta1.WorkspacePipelineDeclaration{ + { + Name: "test-workspace", + }, + }, + }, + }, + } + + // Add timeout to last PipelineRun for Pipeline + timeoutDuration, _ := time.ParseDuration("10s") + prs := []*v1beta1.PipelineRun{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "test-pipeline-run-123", + Namespace: "ns", + Labels: map[string]string{"tekton.dev/pipeline": pipelineName}, + }, + Spec: v1beta1.PipelineRunSpec{ + PipelineRef: &v1beta1.PipelineRef{ + Name: pipelineName, + }, + ServiceAccountName: "test-sa", + Resources: []v1beta1.PipelineResourceBinding{ + { + Name: "git-repo", + ResourceRef: &v1beta1.PipelineResourceRef{ + Name: "some-repo", + }, + }, + { + Name: "build-image", + ResourceRef: &v1beta1.PipelineResourceRef{ + Name: "some-image", + }, + }, + }, + Params: []v1beta1.Param{ + { + Name: "pipeline-param-1", + Value: v1beta1.ArrayOrString{ + Type: v1beta1.ParamTypeString, + StringVal: "somethingmorefun", + }, + }, + { + Name: "rev-param", + Value: v1beta1.ArrayOrString{ + Type: v1beta1.ParamTypeString, + StringVal: "revision1", + }, + }, + }, + Workspaces: []v1beta1.WorkspaceBinding{ + { + Name: "test-new", + }, + }, + Timeout: &metav1.Duration{Duration: timeoutDuration}, + }, + Status: v1beta1.PipelineRunStatus{ + Status: duckv1beta1.Status{ + Conditions: duckv1beta1.Conditions{ + { + Status: corev1.ConditionTrue, + Reason: v1beta1.PipelineRunReasonSuccessful.String(), + }, + }, + }, + }, + }, + } + + ns := []*corev1.Namespace{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "ns", + }, + }, + } + + seedData, _ := test.SeedV1beta1TestData(t, pipelinev1beta1test.Data{ + Namespaces: ns, + }) + cs := pipelinetest.Clients{ + Pipeline: seedData.Pipeline, + Kube: seedData.Kube, + Resource: seedData.Resource, + } + cs.Pipeline.Resources = cb.APIResourceList("v1beta1", []string{"pipeline", "pipelinerun"}) + objs := []runtime.Object{ps[0], prs[0]} + _, tdc := newPipelineClient("v1beta1", objs...) + dc, err := tdc.Client( + cb.UnstructuredV1beta1P(ps[0], "v1beta1"), + cb.UnstructuredV1beta1PR(prs[0], "v1beta1"), + ) + if err != nil { + t.Errorf("unable to create dynamic client: %v", err) + } + p := &test.Params{Tekton: cs.Pipeline, Kube: cs.Kube, Dynamic: dc, Resource: cs.Resource} + + pipeline := Command(p) + // Specify new timeout value to override previous value + got, _ := test.ExecuteCommand(pipeline, "start", pipelineName, + "--last", + "--timeout", "1s", + "-n", "ns", + ) + + expected := "PipelineRun started: random\n\nIn order to track the PipelineRun progress run:\ntkn pipelinerun logs random -f -n ns\n" + test.AssertOutput(t, expected, got) + + cl, _ := p.Clients() + pr, err := pipelinerun.Get(cl, "random", v1.GetOptions{}, "ns") + if err != nil { + t.Errorf("Error getting pipelineruns %s", err.Error()) + } + + // Assert newly started PipelineRun has new timeout value + timeoutDuration, _ = time.ParseDuration("1s") + test.AssertOutput(t, timeoutDuration, pr.Spec.Timeout.Duration) +} + func Test_start_pipeline_last_without_res_param(t *testing.T) { pipelineName := "test-pipeline" diff --git a/pkg/cmd/task/start.go b/pkg/cmd/task/start.go index ae7fefc839..14257c31c4 100644 --- a/pkg/cmd/task/start.go +++ b/pkg/cmd/task/start.go @@ -270,31 +270,31 @@ func startTask(opt startOptions, args []string) error { return err } - if opt.TimeOut != "" { - timeoutDuration, err := time.ParseDuration(opt.TimeOut) + if opt.Last || opt.UseTaskRun != "" { + taskRunOpts := options.TaskRunOpts{ + CliParams: opt.cliparams, + Last: opt.Last, + UseTaskRun: opt.UseTaskRun, + PrefixName: opt.PrefixName, + } + err := taskRunOpts.UseTaskRunFrom(tr, cs, tname, "Task") if err != nil { return err } - tr.Spec.Timeout = &metav1.Duration{Duration: timeoutDuration} } - if opt.PrefixName == "" { + if opt.PrefixName == "" && !opt.Last && opt.UseTaskRun == "" { tr.ObjectMeta.GenerateName = tname + "-run-" - } else { + } else if opt.PrefixName != "" { tr.ObjectMeta.GenerateName = opt.PrefixName + "-" } - if opt.Last || opt.UseTaskRun != "" { - taskRunOpts := options.TaskRunOpts{ - CliParams: opt.cliparams, - Last: opt.Last, - UseTaskRun: opt.UseTaskRun, - PrefixName: opt.PrefixName, - } - err := taskRunOpts.UseTaskRunFrom(tr, cs, tname, "Task") + if opt.TimeOut != "" { + timeoutDuration, err := time.ParseDuration(opt.TimeOut) if err != nil { return err } + tr.Spec.Timeout = &metav1.Duration{Duration: timeoutDuration} } if tr.Spec.Resources == nil { diff --git a/pkg/cmd/task/start_test.go b/pkg/cmd/task/start_test.go index 01704bf19d..1e6fb2232e 100644 --- a/pkg/cmd/task/start_test.go +++ b/pkg/cmd/task/start_test.go @@ -909,7 +909,6 @@ func Test_start_task_last_v1beta1(t *testing.T) { } timeoutDuration, _ := time.ParseDuration("10s") - taskruns := []*v1beta1.TaskRun{ { ObjectMeta: v1.ObjectMeta{ @@ -1033,6 +1032,93 @@ func Test_start_task_last_v1beta1(t *testing.T) { test.AssertOutput(t, timeoutDuration, tr.Spec.Timeout.Duration) } +func Test_start_task_last_with_override_timeout_v1beta1(t *testing.T) { + tasks := []*v1beta1.Task{ + { + ObjectMeta: v1.ObjectMeta{ + Name: "task", + Namespace: "ns", + }, + Spec: v1beta1.TaskSpec{ + Steps: []v1beta1.Step{ + { + Container: corev1.Container{ + Name: "hello", + Image: "busybox", + }, + }, + { + Container: corev1.Container{ + Name: "exit", + Image: "busybox", + }, + }, + }, + }, + }, + } + + // Add timeout to last TaskRun for Task + timeoutDuration, _ := time.ParseDuration("10s") + taskruns := []*v1beta1.TaskRun{ + { + ObjectMeta: v1.ObjectMeta{ + Name: "taskrun-123", + Namespace: "ns", + Labels: map[string]string{"tekton.dev/task": "task"}, + }, + Spec: v1beta1.TaskRunSpec{ + Timeout: &metav1.Duration{Duration: timeoutDuration}, + TaskRef: &v1beta1.TaskRef{ + Name: "task", + Kind: v1beta1.NamespacedTaskKind, + }, + }, + }, + } + + ns := []*corev1.Namespace{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "ns", + }, + }, + } + + seedData, _ := test.SeedV1beta1TestData(t, pipelinev1beta1test.Data{Namespaces: ns, Tasks: tasks, TaskRuns: taskruns}) + objs := []runtime.Object{tasks[0], taskruns[0]} + _, tdc := newPipelineClient(versionB1, objs...) + dc, _ := tdc.Client( + cb.UnstructuredV1beta1T(tasks[0], versionB1), + cb.UnstructuredV1beta1TR(taskruns[0], versionB1), + ) + + cs := pipelinetest.Clients{ + Pipeline: seedData.Pipeline, + Kube: seedData.Kube, + } + cs.Pipeline.Resources = cb.APIResourceList(versionB1, []string{"task", "taskrun"}) + p := &test.Params{Tekton: cs.Pipeline, Kube: cs.Kube, Dynamic: dc} + clients, _ := p.Clients() + task := Command(p) + // Specify new timeout value to override previous value + got, err := test.ExecuteCommand(task, "start", "task", "--last", "--timeout", "1s", "-n=ns") + if err != nil { + t.Errorf("Error running task start: %v", err) + } + + expected := "TaskRun started: random\n\nIn order to track the TaskRun progress run:\ntkn taskrun logs random -f -n ns\n" + test.AssertOutput(t, expected, got) + gotTR, err := traction.Get(clients, "random", metav1.GetOptions{}, "ns") + if err != nil { + t.Errorf("Error listing taskruns %s", err.Error()) + } + + // Assert newly started TaskRun has new timeout value + timeoutDuration, _ = time.ParseDuration("1s") + test.AssertOutput(t, timeoutDuration, gotTR.Spec.Timeout.Duration) +} + func Test_start_use_taskrun(t *testing.T) { tasks := []*v1alpha1.Task{ tb.Task("task",