From fab02ea4787e18e33db264edadb7b5bf5f47c8ee Mon Sep 17 00:00:00 2001 From: The Magician Date: Wed, 12 Dec 2018 17:57:01 -0800 Subject: [PATCH] add souce repo support to cloud functions (#2650) --- google/resource_cloudfunctions_function.go | 68 +++++++++++++++++-- .../resource_cloudfunctions_function_test.go | 42 ++++++++++++ .../r/cloudfunctions_function.html.markdown | 21 ++++-- 3 files changed, 122 insertions(+), 9 deletions(-) diff --git a/google/resource_cloudfunctions_function.go b/google/resource_cloudfunctions_function.go index 1c39f59d..a9638089 100644 --- a/google/resource_cloudfunctions_function.go +++ b/google/resource_cloudfunctions_function.go @@ -123,12 +123,31 @@ func resourceCloudFunctionsFunction() *schema.Resource { "source_archive_bucket": { Type: schema.TypeString, - Required: true, + Optional: true, }, "source_archive_object": { Type: schema.TypeString, - Required: true, + Optional: true, + }, + + "source_repository": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + ConflictsWith: []string{"source_archive_bucket", "source_archive_object"}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "url": { + Type: schema.TypeString, + Required: true, + }, + "deployed_url": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, }, "description": { @@ -302,9 +321,17 @@ func resourceCloudFunctionsCreate(d *schema.ResourceData, meta interface{}) erro ForceSendFields: []string{}, } - sourceArchiveBucket := d.Get("source_archive_bucket").(string) - sourceArchiveObj := d.Get("source_archive_object").(string) - function.SourceArchiveUrl = fmt.Sprintf("gs://%v/%v", sourceArchiveBucket, sourceArchiveObj) + sourceRepos := d.Get("source_repository").([]interface{}) + if len(sourceRepos) > 0 { + function.SourceRepository = expandSourceRepository(sourceRepos) + } else { + sourceArchiveBucket := d.Get("source_archive_bucket").(string) + sourceArchiveObj := d.Get("source_archive_object").(string) + if sourceArchiveBucket == "" || sourceArchiveObj == "" { + return fmt.Errorf("either source_repository or both of source_archive_bucket+source_archive_object must be set") + } + function.SourceArchiveUrl = fmt.Sprintf("gs://%v/%v", sourceArchiveBucket, sourceArchiveObj) + } if v, ok := d.GetOk("available_memory_mb"); ok { availableMemoryMb := v.(int) @@ -396,6 +423,7 @@ func resourceCloudFunctionsRead(d *schema.ResourceData, meta interface{}) error d.Set("source_archive_bucket", bucket) d.Set("source_archive_object", object) } + d.Set("source_repository", flattenSourceRepository(function.SourceRepository)) if function.HttpsTrigger != nil { d.Set("trigger_http", true) @@ -444,6 +472,11 @@ func resourceCloudFunctionsUpdate(d *schema.ResourceData, meta interface{}) erro updateMaskArr = append(updateMaskArr, "sourceArchiveUrl") } + if d.HasChange("source_repository") { + function.SourceRepository = expandSourceRepository(d.Get("source_repository").([]interface{})) + updateMaskArr = append(updateMaskArr, "sourceRepository") + } + if d.HasChange("description") { function.Description = d.Get("description").(string) updateMaskArr = append(updateMaskArr, "description") @@ -608,3 +641,28 @@ func flattenFailurePolicy(failurePolicy *cloudfunctions.FailurePolicy) []map[str return result } + +func expandSourceRepository(configured []interface{}) *cloudfunctions.SourceRepository { + if len(configured) == 0 || configured[0] == nil { + return &cloudfunctions.SourceRepository{} + } + + data := configured[0].(map[string]interface{}) + return &cloudfunctions.SourceRepository{ + Url: data["url"].(string), + } +} + +func flattenSourceRepository(sourceRepo *cloudfunctions.SourceRepository) []map[string]interface{} { + result := make([]map[string]interface{}, 0, 1) + if sourceRepo == nil { + return nil + } + + result = append(result, map[string]interface{}{ + "url": sourceRepo.Url, + "deployed_url": sourceRepo.DeployedUrl, + }) + + return result +} diff --git a/google/resource_cloudfunctions_function_test.go b/google/resource_cloudfunctions_function_test.go index f82372d1..f9344bc5 100644 --- a/google/resource_cloudfunctions_function_test.go +++ b/google/resource_cloudfunctions_function_test.go @@ -234,6 +234,29 @@ func TestAccCloudFunctionsFunction_firestore(t *testing.T) { }) } +func TestAccCloudFunctionsFunction_sourceRepo(t *testing.T) { + t.Parallel() + + funcResourceName := "google_cloudfunctions_function.function" + functionName := fmt.Sprintf("tf-test-%s", acctest.RandString(10)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckCloudFunctionsFunctionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCloudFunctionsFunction_sourceRepo(functionName), + }, + { + ResourceName: funcResourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccCheckCloudFunctionsFunctionDestroy(s *terraform.State) error { config := testAccProvider.Meta().(*Config) @@ -564,3 +587,22 @@ resource "google_cloudfunctions_function" "function" { } }`, bucketName, zipFilePath, functionName) } + +func testAccCloudFunctionsFunction_sourceRepo(functionName string) string { + return fmt.Sprintf(` +resource "google_cloudfunctions_function" "function" { + name = "%s" + + source_repository { + // There isn't yet an API that'll allow us to create a source repository and + // put code in it, so we created this repository outside the test to be used + // here. If this test is run outside of CI, it may fail because of permissions + // errors. + url = "https://source.developers.google.com/projects/hc-terraform-testing/repos/cloudfunctions-test-do-not-delete/moveable-aliases/master/paths/" + } + + trigger_http = true + entry_point = "helloGET" +} +`, functionName) +} diff --git a/website/docs/r/cloudfunctions_function.html.markdown b/website/docs/r/cloudfunctions_function.html.markdown index 5d4e3c7d..d952d968 100644 --- a/website/docs/r/cloudfunctions_function.html.markdown +++ b/website/docs/r/cloudfunctions_function.html.markdown @@ -50,10 +50,6 @@ The following arguments are supported: * `name` - (Required) A user-defined name of the function. Function names must be unique globally. -* `source_archive_bucket` - (Required) The GCS bucket containing the zip archive which contains the function. - -* `source_archive_object` - (Required) The source archive object (file) in archive bucket. - - - - * `description` - (Optional) Description of the function. @@ -74,6 +70,13 @@ The following arguments are supported: * `environment_variables` - (Optional) A set of key/value environment variable pairs to assign to the function. +* `source_archive_bucket` - (Optional) The GCS bucket containing the zip archive which contains the function. + +* `source_archive_object` - (Optional) The source archive object (file) in archive bucket. + +* `source_repository` - (Optional) Represents parameters related to source repository where a function is hosted. + Cannot be set alongside `source_archive_bucket` or `source_archive_object`. Structure is documented below. + The `event_trigger` block supports: * `event_type` - (Required) The type of event to observe. For example: `"google.storage.object.finalize"`. @@ -90,6 +93,14 @@ The `failure_policy` block supports: * `retry` - (Required) Whether the function should be retried on failure. Defaults to `false`. +The `source_reposoitory` block supports: + +* `url` - (Required) The URL pointing to the hosted repository where the function is defined. There are supported Cloud Source Repository URLs in the following formats: + + * To refer to a specific commit: `https://source.developers.google.com/projects/*/repos/*/revisions/*/paths/*` + * To refer to a moveable alias (branch): `https://source.developers.google.com/projects/*/repos/*/moveable-aliases/*/paths/*`. To refer to HEAD, use the `master` moveable alias. + * To refer to a specific fixed alias (tag): `https://source.developers.google.com/projects/*/repos/*/fixed-aliases/*/paths/*` + ## Attributes Reference In addition to the arguments listed above, the following computed attributes are @@ -97,6 +108,8 @@ exported: * `https_trigger_url` - URL which triggers function execution. Returned only if `trigger_http` is used. +* `source_reposoitory.0.deployed_url` - The URL pointing to the hosted repository where the function was defined at the time of deployment. + * `project` - Project of the function. If it is not provided, the provider project is used. * `region` - Region of function. Currently can be only "us-central1". If it is not provided, the provider region is used.