From c650c77a9b93514708fed3933a6f3b3c7d3bfee4 Mon Sep 17 00:00:00 2001 From: ilia-medvedev-codefresh <ilia.medvedev@codefresh.io> Date: Mon, 26 Feb 2024 17:43:23 +0200 Subject: [PATCH] Feat: Add permit restart from failed steps to pipeline resource (#137) ## What Add possibility to disable restart From failed step in pipeline resource. ## Why This property was absent from the terraform provider, causing the default "true" value to always be applied and would reset manual changes on apply ## Notes <!-- Add any notes here --> ## Checklist * [x] _I have read [CONTRIBUTING.md](https://github.com/codefresh-io/terraform-provider-codefresh/blob/master/CONTRIBUTING.md)._ * [x] _I have [allowed changes to my fork to be made](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork)._ * [x] _I have added tests, assuming new tests are warranted_. * [x] _I understand that the `/test` comment will be ignored by the CI trigger [unless it is made by a repo admin or collaborator](https://codefresh.io/docs/docs/pipelines/triggers/git-triggers/#support-for-building-pull-requests-from-forks)._ --- codefresh/cfclient/pipeline.go | 39 ++++++++++--------- codefresh/resource_pipeline.go | 20 +++++++--- codefresh/resource_pipeline_test.go | 60 +++++++++++++++++++++++++++++ docs/resources/pipeline.md | 1 + 4 files changed, 95 insertions(+), 25 deletions(-) diff --git a/codefresh/cfclient/pipeline.go b/codefresh/cfclient/pipeline.go index 442c8d5..d25de84 100644 --- a/codefresh/cfclient/pipeline.go +++ b/codefresh/cfclient/pipeline.go @@ -103,25 +103,26 @@ func (t *CronTrigger) SetVariables(variables map[string]interface{}) { } type Spec struct { - Variables []Variable `json:"variables,omitempty"` - SpecTemplate *SpecTemplate `json:"specTemplate,omitempty"` - Triggers []Trigger `json:"triggers,omitempty"` - CronTriggers []CronTrigger `json:"cronTriggers,omitempty"` - Priority int `json:"priority,omitempty"` - Concurrency int `json:"concurrency,omitempty"` - BranchConcurrency int `json:"branchConcurrency,omitempty"` - TriggerConcurrency int `json:"triggerConcurrency,omitempty"` - Contexts []interface{} `json:"contexts,omitempty"` - Steps *Steps `json:"steps,omitempty"` - Stages *Stages `json:"stages,omitempty"` - Mode string `json:"mode,omitempty"` - FailFast *bool `json:"fail_fast,omitempty"` - RuntimeEnvironment RuntimeEnvironment `json:"runtimeEnvironment,omitempty"` - TerminationPolicy []map[string]interface{} `json:"terminationPolicy,omitempty"` - PackId string `json:"packId,omitempty"` - RequiredAvailableStorage string `json:"requiredAvailableStorage,omitempty"` - Hooks *Hooks `json:"hooks,omitempty"` - Options map[string]bool `json:"options,omitempty"` + Variables []Variable `json:"variables,omitempty"` + SpecTemplate *SpecTemplate `json:"specTemplate,omitempty"` + Triggers []Trigger `json:"triggers,omitempty"` + CronTriggers []CronTrigger `json:"cronTriggers,omitempty"` + Priority int `json:"priority,omitempty"` + Concurrency int `json:"concurrency,omitempty"` + BranchConcurrency int `json:"branchConcurrency,omitempty"` + TriggerConcurrency int `json:"triggerConcurrency,omitempty"` + Contexts []interface{} `json:"contexts,omitempty"` + Steps *Steps `json:"steps,omitempty"` + Stages *Stages `json:"stages,omitempty"` + Mode string `json:"mode,omitempty"` + FailFast *bool `json:"fail_fast,omitempty"` + RuntimeEnvironment RuntimeEnvironment `json:"runtimeEnvironment,omitempty"` + TerminationPolicy []map[string]interface{} `json:"terminationPolicy,omitempty"` + PackId string `json:"packId,omitempty"` + RequiredAvailableStorage string `json:"requiredAvailableStorage,omitempty"` + Hooks *Hooks `json:"hooks,omitempty"` + Options map[string]bool `json:"options,omitempty"` + PermitRestartFromFailedSteps bool `json:"permitRestartFromFailedSteps,omitempty"` } type Steps struct { diff --git a/codefresh/resource_pipeline.go b/codefresh/resource_pipeline.go index 4430262..b3fd98c 100644 --- a/codefresh/resource_pipeline.go +++ b/codefresh/resource_pipeline.go @@ -101,6 +101,12 @@ Or: <code>original_yaml_string = file("/path/to/my/codefresh.yml")</code> Optional: true, Default: 0, }, + "permit_restart_from_failed_steps": { + Description: "Defines whether it is permitted to restart builds in this pipeline from failed step. Defaults to true", + Type: schema.TypeBool, + Optional: true, + Default: true, + }, "spec_template": { Description: "The pipeline's spec template.", Type: schema.TypeList, @@ -774,6 +780,7 @@ func flattenSpec(spec cfclient.Spec) []interface{} { m["concurrency"] = spec.Concurrency m["branch_concurrency"] = spec.BranchConcurrency m["trigger_concurrency"] = spec.TriggerConcurrency + m["permit_restart_from_failed_steps"] = spec.PermitRestartFromFailedSteps m["priority"] = spec.Priority @@ -923,12 +930,13 @@ func mapResourceToPipeline(d *schema.ResourceData) (*cfclient.Pipeline, error) { OriginalYamlString: originalYamlString, }, Spec: cfclient.Spec{ - PackId: d.Get("spec.0.pack_id").(string), - RequiredAvailableStorage: d.Get("spec.0.required_available_storage").(string), - Priority: d.Get("spec.0.priority").(int), - Concurrency: d.Get("spec.0.concurrency").(int), - BranchConcurrency: d.Get("spec.0.branch_concurrency").(int), - TriggerConcurrency: d.Get("spec.0.trigger_concurrency").(int), + PackId: d.Get("spec.0.pack_id").(string), + RequiredAvailableStorage: d.Get("spec.0.required_available_storage").(string), + Priority: d.Get("spec.0.priority").(int), + Concurrency: d.Get("spec.0.concurrency").(int), + BranchConcurrency: d.Get("spec.0.branch_concurrency").(int), + TriggerConcurrency: d.Get("spec.0.trigger_concurrency").(int), + PermitRestartFromFailedSteps: d.Get("spec.0.permit_restart_from_failed_steps").(bool), }, } diff --git a/codefresh/resource_pipeline_test.go b/codefresh/resource_pipeline_test.go index 07dff4a..d3530aa 100644 --- a/codefresh/resource_pipeline_test.go +++ b/codefresh/resource_pipeline_test.go @@ -79,6 +79,39 @@ func TestAccCodefreshPipeline_Concurrency(t *testing.T) { }) } +func TestAccCodefreshPipeline_PremitRestartFromFailedSteps(t *testing.T) { + name := pipelineNamePrefix + acctest.RandString(10) + resourceName := "codefresh_pipeline.test" + var pipeline cfclient.Pipeline + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckCodefreshPipelineDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCodefreshPipelineBasicConfigPermitRestartFromFailedSteps(name, "codefresh-contrib/react-sample-app", "./codefresh.yml", "master", "git", true), + Check: resource.ComposeTestCheckFunc( + testAccCheckCodefreshPipelineExists(resourceName, &pipeline), + resource.TestCheckResourceAttr(resourceName, "spec.0.permit_restart_from_failed_steps", "true"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccCodefreshPipelineBasicConfigPermitRestartFromFailedSteps(name, "codefresh-contrib/react-sample-app", "./codefresh.yml", "master", "git", false), + Check: resource.ComposeTestCheckFunc( + testAccCheckCodefreshPipelineExists(resourceName, &pipeline), + resource.TestCheckResourceAttr(resourceName, "spec.0.permit_restart_from_failed_steps", "false"), + ), + }, + }, + }) +} + func TestAccCodefreshPipeline_Tags(t *testing.T) { name := pipelineNamePrefix + acctest.RandString(10) resourceName := "codefresh_pipeline.test" @@ -955,6 +988,33 @@ resource "codefresh_pipeline" "test" { `, rName, repo, path, revision, context, concurrency, concurrencyBranch, concurrencyTrigger) } +func testAccCodefreshPipelineBasicConfigPermitRestartFromFailedSteps(rName string, repo string, path string, revision string, context string, permitRestartFromFailedSteps bool) string { + return fmt.Sprintf(` +resource "codefresh_pipeline" "test" { + + lifecycle { + ignore_changes = [ + revision + ] + } + + name = "%s" + + spec { + spec_template { + repo = %q + path = %q + revision = %q + context = %q + } + + permit_restart_from_failed_steps = %t + + } +} +`, rName, repo, path, revision, context, permitRestartFromFailedSteps) +} + func testAccCodefreshPipelineBasicConfigTriggers( rName, repo, diff --git a/docs/resources/pipeline.md b/docs/resources/pipeline.md index 9313d8a..8d4014e 100644 --- a/docs/resources/pipeline.md +++ b/docs/resources/pipeline.md @@ -130,6 +130,7 @@ Optional: - `cron_trigger` (Block List) The pipeline's cron triggers. Conflicts with the deprecated [codefresh_pipeline_cron_trigger](https://registry.terraform.io/providers/codefresh-io/codefresh/latest/docs/resources/pipeline_cron_trigger) resource. (see [below for nested schema](#nestedblock--spec--cron_trigger)) - `options` (Block List, Max: 1) The options for the pipeline. (see [below for nested schema](#nestedblock--spec--options)) - `pack_id` (String) SAAS pack (`5cd1746617313f468d669013` for Small; `5cd1746717313f468d669014` for Medium; `5cd1746817313f468d669015` for Large; `5cd1746817313f468d669017` for XL; `5cd1746817313f468d669018` for XXL); `5cd1746817313f468d669020` for 4XL). +- `permit_restart_from_failed_steps` (Boolean) Defines whether it is permitted to restart builds in this pipeline from failed step. Defaults to true - `priority` (Number) Helps to organize the order of builds execution in case of reaching the concurrency limit (default: `0`). - `required_available_storage` (String) Minimum disk space required for build filesystem ( unit Gi is required). - `runtime_environment` (Block List) The runtime environment for the pipeline. (see [below for nested schema](#nestedblock--spec--runtime_environment))