diff --git a/codefresh/cfclient/pipeline.go b/codefresh/cfclient/pipeline.go
index 0b7c9a9..c15bd69 100644
--- a/codefresh/cfclient/pipeline.go
+++ b/codefresh/cfclient/pipeline.go
@@ -90,6 +90,17 @@ type RuntimeEnvironment struct {
RequiredAvailableStorage string `json:"requiredAvailableStorage,omitempty"`
}
+type ExternalResource struct {
+ ID string `json:"id,omitempty"`
+ Type string `json:"type"`
+ Source string `json:"source"`
+ Context string `json:"context"`
+ Destination string `json:"destination"`
+ IsFolder bool `json:"isFolder"`
+ Repo string `json:"repo"`
+ Revision string `json:"revision"`
+}
+
func (t *Trigger) SetVariables(variables map[string]interface{}, encrypted bool) {
for key, value := range variables {
t.Variables = append(t.Variables, Variable{Key: key, Value: value.(string), Encrypted: encrypted})
@@ -123,6 +134,7 @@ type Spec struct {
Hooks *Hooks `json:"hooks,omitempty"`
Options map[string]bool `json:"options,omitempty"`
PermitRestartFromFailedSteps bool `json:"permitRestartFromFailedSteps,omitempty"`
+ ExternalResources []ExternalResource `json:"externalResources,omitempty"`
}
type Steps struct {
@@ -149,7 +161,6 @@ func (d Hooks) MarshalJSON() ([]byte, error) {
bytes := []byte(d.Hooks)
return bytes, nil
}
-
func (d *Steps) UnmarshalJSON(data []byte) error {
d.Steps = string(data)
return nil
diff --git a/codefresh/resource_pipeline.go b/codefresh/resource_pipeline.go
index 0da0da6..35adc3b 100644
--- a/codefresh/resource_pipeline.go
+++ b/codefresh/resource_pipeline.go
@@ -641,6 +641,58 @@ Pipeline concurrency policy: Builds on 'Pending Approval' state should be:
},
},
},
+ "external_resource": {
+ Type: schema.TypeList,
+ Optional: true,
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "id" : {
+ Type: schema.TypeString,
+ Computed: true,
+ },
+ "type" : {
+ Type: schema.TypeString,
+ Optional: true,
+ Description: "Type of the external resource. Currently only 'git' is supported",
+ ValidateFunc: validation.StringInSlice([]string{
+ "git",
+ }, false),
+ Default: "git",
+ },
+ "repo" : {
+ Type: schema.TypeString,
+ Required: true,
+ Description: "git repository url",
+ },
+ "context" : {
+ Type: schema.TypeString,
+ Required: true,
+ Description: "Context name for the git repository",
+ },
+ "revision": {
+ Type: schema.TypeString,
+ Required: true,
+ Description: "Revision/branch in the git repository",
+ },
+ "is_folder": {
+ Type: schema.TypeBool,
+ Description: "Whether or not the resource specified in source_path is a folder",
+ Optional: true,
+ Default: false,
+ },
+ "source_path": {
+ Type: schema.TypeString,
+ Description: "The source folder in the repository (use relative path)",
+ Required: true,
+ },
+ "target_path": {
+ Type: schema.TypeString,
+ Description: "The target folder in the pipeline workspace where the file/folder will be copied to (use absolute path)",
+ Required: true,
+ },
+ },
+ },
+ },
},
},
},
@@ -832,6 +884,10 @@ func flattenSpec(spec cfclient.Spec) []map[string]interface{} {
m["runtime_environment"] = flattenSpecRuntimeEnvironment(spec.RuntimeEnvironment)
}
+ if len(spec.ExternalResources) > 0 {
+ m["external_resource"] = flattenExternalResources(spec.ExternalResources)
+ }
+
if len(spec.TerminationPolicy) > 0 {
m["termination_policy"] = flattenSpecTerminationPolicy(spec.TerminationPolicy)
}
@@ -988,6 +1044,25 @@ func flattenCronTriggers(cronTriggers []cfclient.CronTrigger) []map[string]inter
return res
}
+func flattenExternalResources(externalResources []cfclient.ExternalResource) []map[string]interface{} {
+ var res = make([]map[string]interface{}, len(externalResources))
+ for i, externalResource := range externalResources {
+ m := make(map[string]interface{})
+ m["type"] = externalResource.Type
+ m["repo"] = externalResource.Repo
+ m["context"] = externalResource.Context
+ m["source_path"] = externalResource.Source
+ m["target_path"] = externalResource.Destination
+ m["revision"] = externalResource.Revision
+ m["is_folder"] = externalResource.IsFolder
+ m["id"] = externalResource.ID
+
+ res[i] = m
+ }
+
+ return res
+}
+
func mapResourceToPipeline(d *schema.ResourceData) (*cfclient.Pipeline, error) {
tags := d.Get("tags").(*schema.Set).List()
@@ -1146,6 +1221,23 @@ func mapResourceToPipeline(d *schema.ResourceData) (*cfclient.Pipeline, error) {
}
}
+ if externalResources, ok := d.GetOk("spec.0.external_resource"); ok {
+ for idx := range externalResources.([]interface{}) {
+ codefreshExternalResource := cfclient.ExternalResource{
+ Type: d.Get(fmt.Sprintf("spec.0.external_resource.%v.type", idx)).(string),
+ Repo: d.Get(fmt.Sprintf("spec.0.external_resource.%v.repo", idx)).(string),
+ Revision: d.Get(fmt.Sprintf("spec.0.external_resource.%v.revision", idx)).(string),
+ Context: d.Get(fmt.Sprintf("spec.0.external_resource.%v.context", idx)).(string),
+ Source: d.Get(fmt.Sprintf("spec.0.external_resource.%v.source_path", idx)).(string),
+ Destination: d.Get(fmt.Sprintf("spec.0.external_resource.%v.target_path", idx)).(string),
+ IsFolder: d.Get(fmt.Sprintf("spec.0.external_resource.%v.is_folder", idx)).(bool),
+ ID: d.Get(fmt.Sprintf("spec.0.external_resource.%v.id", idx)).(string),
+ }
+
+ pipeline.Spec.ExternalResources = append(pipeline.Spec.ExternalResources, codefreshExternalResource)
+ }
+ }
+
var codefreshTerminationPolicy []map[string]interface{}
if _, ok := d.GetOk("spec.0.termination_policy.0.on_create_branch"); ok {
diff --git a/codefresh/resource_pipeline_test.go b/codefresh/resource_pipeline_test.go
index 9c82d82..8e52d61 100644
--- a/codefresh/resource_pipeline_test.go
+++ b/codefresh/resource_pipeline_test.go
@@ -700,6 +700,61 @@ func TestAccCodefreshPipeline_IsPublic(t *testing.T) {
})
}
+func TestAccCodefreshPipeline_ExternalResources(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: testAccCodefreshPipelineExternalResources(name, "codefresh-contrib/react-sample-app", "./codefresh.yml", "master", "git",
+ "github", "codefresh-io/external-resources1", "master", "test.py", "/codefresh/volume/test.py",
+ "github2", "codefresh-io/external-resources2", "main", "test2.py", "/codefresh/volume/test2.py"),
+ Check: resource.ComposeTestCheckFunc(
+ testAccCheckCodefreshPipelineExists(resourceName, &pipeline),
+ resource.TestCheckResourceAttr(resourceName, "spec.0.external_resource.0.context", "github"),
+ resource.TestCheckResourceAttr(resourceName, "spec.0.external_resource.0.repo", "codefresh-io/external-resources1"),
+ resource.TestCheckResourceAttr(resourceName, "spec.0.external_resource.0.revision", "master"),
+ resource.TestCheckResourceAttr(resourceName, "spec.0.external_resource.0.source_path", "test.py"),
+ resource.TestCheckResourceAttr(resourceName, "spec.0.external_resource.0.target_path", "/codefresh/volume/test.py"),
+ resource.TestCheckResourceAttr(resourceName, "spec.0.external_resource.1.context", "github2"),
+ resource.TestCheckResourceAttr(resourceName, "spec.0.external_resource.1.repo", "codefresh-io/external-resources2"),
+ resource.TestCheckResourceAttr(resourceName, "spec.0.external_resource.1.revision", "main"),
+ resource.TestCheckResourceAttr(resourceName, "spec.0.external_resource.1.source_path", "test2.py"),
+ resource.TestCheckResourceAttr(resourceName, "spec.0.external_resource.1.target_path", "/codefresh/volume/test2.py"),
+ ),
+ },
+ {
+ ResourceName: resourceName,
+ ImportState: true,
+ ImportStateVerify: true,
+ },
+ {
+ Config: testAccCodefreshPipelineExternalResources(name, "codefresh-contrib/react-sample-app", "./codefresh.yml", "master", "git",
+ "github2", "codefresh-io/external-resources2", "main", "test2.py", "/codefresh/volume/test2.py",
+ "github", "codefresh-io/external-resources1", "master", "test.py", "/codefresh/volume/test.py"),
+ Check: resource.ComposeTestCheckFunc(
+ testAccCheckCodefreshPipelineExists(resourceName, &pipeline),
+ resource.TestCheckResourceAttr(resourceName, "spec.0.external_resource.1.context", "github"),
+ resource.TestCheckResourceAttr(resourceName, "spec.0.external_resource.1.repo", "codefresh-io/external-resources1"),
+ resource.TestCheckResourceAttr(resourceName, "spec.0.external_resource.1.revision", "master"),
+ resource.TestCheckResourceAttr(resourceName, "spec.0.external_resource.1.source_path", "test.py"),
+ resource.TestCheckResourceAttr(resourceName, "spec.0.external_resource.1.target_path", "/codefresh/volume/test.py"),
+ resource.TestCheckResourceAttr(resourceName, "spec.0.external_resource.0.context", "github2"),
+ resource.TestCheckResourceAttr(resourceName, "spec.0.external_resource.0.repo", "codefresh-io/external-resources2"),
+ resource.TestCheckResourceAttr(resourceName, "spec.0.external_resource.0.revision", "main"),
+ resource.TestCheckResourceAttr(resourceName, "spec.0.external_resource.0.source_path", "test2.py"),
+ resource.TestCheckResourceAttr(resourceName, "spec.0.external_resource.0.target_path", "/codefresh/volume/test2.py"),
+ ),
+ },
+ },
+ })
+}
+
func TestAccCodefreshPipelineOnCreateBranchIgnoreTrigger(t *testing.T) {
name := pipelineNamePrefix + acctest.RandString(10)
resourceName := "codefresh_pipeline.test"
@@ -1477,3 +1532,46 @@ resource "codefresh_pipeline" "test" {
}
`, rName, repo, path, revision, context, isPublic)
}
+
+func testAccCodefreshPipelineExternalResources(rName, repo, path, revision, context, extResource1Context, extResource1Repo, extResource1Revision, extResourse1SourcePath, extResource1DestPath, extResource2Context, extResource2Repo, extResource2Revision, extResourse2SourcePath, extResource2DestPath string) 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
+ }
+
+ external_resource {
+ context = %q
+ repo = %q
+ revision = %q
+ source_path = %q
+ target_path = %q
+ }
+
+ external_resource {
+ context = %q
+ repo = %q
+ revision = %q
+ source_path = %q
+ target_path = %q
+ }
+ }
+}
+`,
+rName, repo, path, revision, context,
+extResource1Context, extResource1Repo ,extResource1Revision, extResourse1SourcePath, extResource1DestPath,
+extResource2Context, extResource2Repo ,extResource2Revision, extResourse2SourcePath, extResource2DestPath)
+}
diff --git a/docs/resources/pipeline.md b/docs/resources/pipeline.md
index c1b467c..bbc02e5 100644
--- a/docs/resources/pipeline.md
+++ b/docs/resources/pipeline.md
@@ -129,6 +129,7 @@ Optional:
- `contexts` (List of String) A list of strings representing the contexts ([shared_configuration](https://codefresh.io/docs/docs/configure-ci-cd-pipeline/shared-configuration/)) to be configured for the pipeline.
- `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))
- `encrypted_variables` (Map of String) Pipeline level encrypted variables. Please note that drift will not be detected for encrypted variables
+- `external_resource` (Block List) (see [below for nested schema](#nestedblock--spec--external_resource))
- `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
@@ -185,6 +186,27 @@ Optional:
+
+### Nested Schema for `spec.external_resource`
+
+Required:
+
+- `context` (String) Context name for the git repository
+- `repo` (String) git repository url
+- `revision` (String) Revision/branch in the git repository
+- `source_path` (String) The source folder in the repository (use relative path)
+- `target_path` (String) The target folder in the pipeline workspace where the file/folder will be copied to (use absolute path)
+
+Optional:
+
+- `is_folder` (Boolean) Whether or not the resource specified in source_path is a folder
+- `type` (String) Type of the external resource. Currently only 'git' is supported
+
+Read-Only:
+
+- `id` (String) The ID of this resource.
+
+
### Nested Schema for `spec.options`