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/data_project.go b/codefresh/data_project.go new file mode 100644 index 0000000..e0f464b --- /dev/null +++ b/codefresh/data_project.go @@ -0,0 +1,69 @@ +package codefresh + +import ( + "fmt" + + cfClient "github.com/codefresh-io/terraform-provider-codefresh/codefresh/cfclient" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceProject() *schema.Resource { + return &schema.Resource{ + Description: "This data source retrieves a project by its ID or name.", + Read: dataSourceProjectRead, + Schema: map[string]*schema.Schema{ + "_id": { + Type: schema.TypeString, + Optional: true, + }, + "name": { + Type: schema.TypeString, + Optional: true, + }, + "tags": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + } +} + +func dataSourceProjectRead(d *schema.ResourceData, meta interface{}) error { + + client := meta.(*cfClient.Client) + var project *cfClient.Project + var err error + + if _id, _idOk := d.GetOk("_id"); _idOk { + project, err = client.GetProjectByID(_id.(string)) + } else if name, nameOk := d.GetOk("name"); nameOk { + project, err = client.GetProjectByName(name.(string)) + } + + if err != nil { + return err + } + + if project == nil { + return fmt.Errorf("data.codefresh_project - cannot find project") + } + + return mapDataProjectToResource(project, d) + +} + +func mapDataProjectToResource(project *cfClient.Project, d *schema.ResourceData) error { + + if project == nil || project.ID == "" { + return fmt.Errorf("data.codefresh_project - failed to mapDataProjectToResource") + } + d.SetId(project.ID) + + d.Set("_id", project.ID) + d.Set("tags", project.Tags) + + return nil +} diff --git a/codefresh/provider.go b/codefresh/provider.go index c79e808..0a41589 100644 --- a/codefresh/provider.go +++ b/codefresh/provider.go @@ -51,6 +51,7 @@ func Provider() *schema.Provider { "codefresh_users": dataSourceUsers(), "codefresh_registry": dataSourceRegistry(), "codefresh_pipelines": dataSourcePipelines(), + "codefresh_project": dataSourceProject(), }, ResourcesMap: map[string]*schema.Resource{ "codefresh_account": resourceAccount(), diff --git a/codefresh/resource_pipeline.go b/codefresh/resource_pipeline.go index 95e256d..698ab3f 100644 --- a/codefresh/resource_pipeline.go +++ b/codefresh/resource_pipeline.go @@ -101,6 +101,12 @@ Or: original_yaml_string = file("/path/to/my/codefresh.yml") 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, @@ -781,6 +787,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 @@ -930,12 +937,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 f89e2e6..9bd580c 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" @@ -956,6 +989,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/data-sources/project.md b/docs/data-sources/project.md new file mode 100644 index 0000000..d19d7f6 --- /dev/null +++ b/docs/data-sources/project.md @@ -0,0 +1,40 @@ +--- +page_title: "codefresh_project Data Source - terraform-provider-codefresh" +subcategory: "" +description: |- + This data source retrieves a project by its ID or name. +--- + +# codefresh_project (Data Source) + +This data source retrieves a project by its ID or name. + +## Example Usage + +```hcl +data "codefresh_project" "myapp" { + name = "myapp" +} + + +resource "codefresh_pipeline" "myapp-deploy" { + + name = "${data.codefresh_project.myapp.projectName}/myapp-deploy" + + ... +} + +``` + + +## Schema + +### Optional + +- `_id` (String) +- `name` (String) +- `tags` (List of String) + +### Read-Only + +- `id` (String) The ID of this resource. \ No newline at end of file diff --git a/docs/resources/pipeline.md b/docs/resources/pipeline.md index 46add3c..589a117 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)) diff --git a/templates/data-sources/project.md.tmpl b/templates/data-sources/project.md.tmpl new file mode 100644 index 0000000..3b0f8fe --- /dev/null +++ b/templates/data-sources/project.md.tmpl @@ -0,0 +1,29 @@ +--- +page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}" +subcategory: "" +description: |- +{{ .Description | plainmarkdown | trimspace | prefixlines " " }} +--- + +# {{.Name}} ({{.Type}}) + +{{ .Description | trimspace }} + +## Example Usage + +```hcl +data "codefresh_project" "myapp" { + name = "myapp" +} + + +resource "codefresh_pipeline" "myapp-deploy" { + + name = "${data.codefresh_project.myapp.projectName}/myapp-deploy" + + ... +} + +``` + +{{ .SchemaMarkdown | trimspace }} \ No newline at end of file