From cd09b20c347a43c160e7f85c2c5d94b97638b041 Mon Sep 17 00:00:00 2001 From: Piotr Truszkowski Date: Tue, 16 Jan 2024 14:57:58 +0100 Subject: [PATCH] MultiVCS: bitbucket Datacenter --- .../bitbucket_datacenter_integration.md | 11 +- docs/data-sources/module.md | 2 + docs/data-sources/stack.md | 2 + docs/data-sources/stacks.md | 2 + docs/resources/module.md | 4 + docs/resources/stack.md | 4 + .../data_bitbucket_datacenter_integration.go | 121 ++++++++++++++---- ...a_bitbucket_datacenter_integration_test.go | 52 ++++++-- spacelift/data_module.go | 10 ++ spacelift/data_stack.go | 10 ++ spacelift/internal/structs/module.go | 2 + spacelift/internal/structs/stack.go | 5 +- spacelift/resource_module.go | 9 ++ spacelift/resource_stack.go | 9 ++ 14 files changed, 203 insertions(+), 40 deletions(-) diff --git a/docs/data-sources/bitbucket_datacenter_integration.md b/docs/data-sources/bitbucket_datacenter_integration.md index b42bad76..a4fba8a5 100644 --- a/docs/data-sources/bitbucket_datacenter_integration.md +++ b/docs/data-sources/bitbucket_datacenter_integration.md @@ -19,10 +19,19 @@ data "spacelift_bitbucket_datacenter_integration" "bitbucket_datacenter_integrat ## Schema +### Optional + +- `id` (String) Bitbucket Datacenter integration id. If not provided, the default integration will be returned + ### Read-Only - `api_host` (String) Bitbucket Datacenter integration api host -- `id` (String) The ID of this resource. +- `description` (String) Bitbucket Datacenter integration description +- `is_default` (Boolean) Bitbucket Datacenter integration is default +- `labels` (List of String) Bitbucket Datacenter integration labels +- `name` (String) Bitbucket Datacenter integration name +- `space_id` (String) Bitbucket Datacenter integration space id - `user_facing_host` (String) Bitbucket Datacenter integration user facing host +- `username` (String) Bitbucket Datacenter username - `webhook_secret` (String) Bitbucket Datacenter integration webhook secret - `webhook_url` (String) Bitbucket Datacenter integration webhook URL diff --git a/docs/data-sources/module.md b/docs/data-sources/module.md index 9fd8f4f1..ee2c4af8 100644 --- a/docs/data-sources/module.md +++ b/docs/data-sources/module.md @@ -63,6 +63,7 @@ Read-Only: Read-Only: +- `id` (String) - `namespace` (String) @@ -71,6 +72,7 @@ Read-Only: Read-Only: +- `id` (String) - `namespace` (String) diff --git a/docs/data-sources/stack.md b/docs/data-sources/stack.md index 004ed6f0..870f7a89 100644 --- a/docs/data-sources/stack.md +++ b/docs/data-sources/stack.md @@ -98,6 +98,7 @@ Read-Only: Read-Only: +- `id` (String) - `namespace` (String) @@ -106,6 +107,7 @@ Read-Only: Read-Only: +- `id` (String) - `namespace` (String) diff --git a/docs/data-sources/stacks.md b/docs/data-sources/stacks.md index f57e47cc..55e7dfbd 100644 --- a/docs/data-sources/stacks.md +++ b/docs/data-sources/stacks.md @@ -195,6 +195,7 @@ Read-Only: Read-Only: +- `id` (String) - `namespace` (String) @@ -203,6 +204,7 @@ Read-Only: Read-Only: +- `id` (String) - `namespace` (String) diff --git a/docs/resources/module.md b/docs/resources/module.md index 130475b1..0b5279fa 100644 --- a/docs/resources/module.md +++ b/docs/resources/module.md @@ -97,6 +97,10 @@ Required: - `namespace` (String) The Bitbucket project containing the repository +Optional: + +- `id` (String) The ID of the Bitbucket Datacenter integration. If not specified, the default integration will be used. + ### Nested Schema for `github_enterprise` diff --git a/docs/resources/stack.md b/docs/resources/stack.md index 571a091a..1a7eb811 100644 --- a/docs/resources/stack.md +++ b/docs/resources/stack.md @@ -282,6 +282,10 @@ Required: - `namespace` (String) The Bitbucket project containing the repository +Optional: + +- `id` (String) The ID of the Bitbucket Datacenter integration. If not specified, the default integration will be used. + ### Nested Schema for `cloudformation` diff --git a/spacelift/data_bitbucket_datacenter_integration.go b/spacelift/data_bitbucket_datacenter_integration.go index 65012ae2..763d63f3 100644 --- a/spacelift/data_bitbucket_datacenter_integration.go +++ b/spacelift/data_bitbucket_datacenter_integration.go @@ -9,17 +9,21 @@ import ( "github.com/spacelift-io/terraform-provider-spacelift/spacelift/internal" ) -var bitbucketDatacenterFields = struct { - UserFacingHost string - APIHost string - WebhookSecret string - WebhookURL string -}{ - UserFacingHost: "user_facing_host", - APIHost: "api_host", - WebhookSecret: "webhook_secret", - WebhookURL: "webhook_url", -} +const ( + bitbucketDatacenterID = "id" + bitbucketDatacenterName = "name" + bitbucketDatacenterDescription = "description" + bitbucketDatacenterIsDefault = "is_default" + bitbucketDatacenterLabels = "labels" + bitbucketDatacenterSpaceID = "space_id" + bitbucketDatacenterUserFacingHost = "user_facing_host" + bitbucketDatacenterAPIHost = "api_host" + bitbucketDatacenterUsername = "username" + bitbucketDatacenterWebhookURL = "webhook_url" + bitbucketDatacenterWebhookSecret = "webhook_secret" + + defaultBitbucketDatacenterIntegrationID = "bitbucket-datacenter-default-integration" +) func dataBitbucketDatacenterIntegration() *schema.Resource { return &schema.Resource{ @@ -28,22 +32,60 @@ func dataBitbucketDatacenterIntegration() *schema.Resource { ReadContext: dataBitbucketDatacenterIntegrationRead, Schema: map[string]*schema.Schema{ - bitbucketDatacenterFields.APIHost: { + bitbucketDatacenterID: { + Type: schema.TypeString, + Description: "Bitbucket Datacenter integration id. If not provided, the default integration will be returned", + Optional: true, + }, + bitbucketDatacenterName: { + Type: schema.TypeString, + Description: "Bitbucket Datacenter integration name", + Computed: true, + }, + bitbucketDatacenterDescription: { + Type: schema.TypeString, + Description: "Bitbucket Datacenter integration description", + Computed: true, + }, + bitbucketDatacenterIsDefault: { + Type: schema.TypeBool, + Description: "Bitbucket Datacenter integration is default", + Computed: true, + }, + bitbucketDatacenterLabels: { + Type: schema.TypeList, + Description: "Bitbucket Datacenter integration labels", + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + bitbucketDatacenterSpaceID: { + Type: schema.TypeString, + Description: "Bitbucket Datacenter integration space id", + Computed: true, + }, + bitbucketDatacenterUsername: { + Type: schema.TypeString, + Description: "Bitbucket Datacenter username", + Computed: true, + }, + bitbucketDatacenterAPIHost: { Type: schema.TypeString, Description: "Bitbucket Datacenter integration api host", Computed: true, }, - bitbucketDatacenterFields.WebhookSecret: { + bitbucketDatacenterWebhookSecret: { Type: schema.TypeString, Description: "Bitbucket Datacenter integration webhook secret", Computed: true, }, - bitbucketDatacenterFields.WebhookURL: { + bitbucketDatacenterWebhookURL: { Type: schema.TypeString, Description: "Bitbucket Datacenter integration webhook URL", Computed: true, }, - bitbucketDatacenterFields.UserFacingHost: { + bitbucketDatacenterUserFacingHost: { Type: schema.TypeString, Description: "Bitbucket Datacenter integration user facing host", Computed: true, @@ -55,14 +97,28 @@ func dataBitbucketDatacenterIntegration() *schema.Resource { func dataBitbucketDatacenterIntegrationRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var query struct { BitbucketDataCenterIntegration *struct { - APIHost string `graphql:"apiHost"` - WebhookSecret string `graphql:"webhookSecret"` - UserFacingHost string `graphql:"userFacingHost"` - WebhookURL string `graphql:"webhookURL"` - } `graphql:"bitbucketDatacenterIntegration"` + ID string `graphql:"id"` + Name string `graphql:"name"` + Description string `graphql:"description"` + IsDefault bool `graphql:"isDefault"` + Space struct { + ID string `graphql:"id"` + } `graphql:"space"` + Labels []string `graphql:"labels"` + APIHost string `graphql:"apiHost"` + WebhookSecret string `graphql:"webhookSecret"` + UserFacingHost string `graphql:"userFacingHost"` + WebhookURL string `graphql:"webhookURL"` + Username string `graphql:"username"` + } `graphql:"bitbucketDatacenterIntegration(id: $id)"` + } + + variables := map[string]interface{}{"id": defaultBitbucketDatacenterIntegrationID} + if id, ok := d.GetOk(bitbucketDatacenterID); ok && id != "" { + variables["id"] = toID(id) } - if err := meta.(*internal.Client).Query(ctx, "BitbucketDatacenterIntegrationRead", &query, map[string]interface{}{}); err != nil { + if err := meta.(*internal.Client).Query(ctx, "BitbucketDatacenterIntegrationRead", &query, variables); err != nil { return diag.Errorf("could not query for bitbucket datacenter integration: %v", err) } @@ -71,11 +127,24 @@ func dataBitbucketDatacenterIntegrationRead(ctx context.Context, d *schema.Resou return diag.Errorf("bitbucket datacenter integration not found") } - d.SetId("spacelift_bitbucket_datacenter_integration_id") // TF expects id to be set otherwise it will fail - d.Set(bitbucketDatacenterFields.APIHost, bitbucketDatacenterIntegration.APIHost) - d.Set(bitbucketDatacenterFields.WebhookSecret, bitbucketDatacenterIntegration.WebhookSecret) - d.Set(bitbucketDatacenterFields.WebhookURL, bitbucketDatacenterIntegration.WebhookURL) - d.Set(bitbucketDatacenterFields.UserFacingHost, bitbucketDatacenterIntegration.UserFacingHost) + d.SetId(bitbucketDatacenterIntegration.ID) + d.Set(bitbucketDatacenterID, bitbucketDatacenterIntegration.ID) + d.Set(bitbucketDatacenterName, bitbucketDatacenterIntegration.Name) + d.Set(bitbucketDatacenterDescription, bitbucketDatacenterIntegration.Description) + d.Set(bitbucketDatacenterIsDefault, bitbucketDatacenterIntegration.IsDefault) + d.Set(bitbucketDatacenterSpaceID, bitbucketDatacenterIntegration.Space.ID) + d.Set(bitbucketDatacenterAPIHost, bitbucketDatacenterIntegration.APIHost) + d.Set(bitbucketDatacenterWebhookSecret, bitbucketDatacenterIntegration.WebhookSecret) + d.Set(bitbucketDatacenterWebhookURL, bitbucketDatacenterIntegration.WebhookURL) + d.Set(bitbucketDatacenterUserFacingHost, bitbucketDatacenterIntegration.UserFacingHost) + d.Set(bitbucketDatacenterUsername, bitbucketDatacenterIntegration.Username) + + labels := schema.NewSet(schema.HashString, []interface{}{}) + for _, label := range bitbucketDatacenterIntegration.Labels { + labels.Add(label) + } + + d.Set(bitbucketDatacenterLabels, labels) return nil } diff --git a/spacelift/data_bitbucket_datacenter_integration_test.go b/spacelift/data_bitbucket_datacenter_integration_test.go index 8618cc0d..977efcb0 100644 --- a/spacelift/data_bitbucket_datacenter_integration_test.go +++ b/spacelift/data_bitbucket_datacenter_integration_test.go @@ -10,16 +10,44 @@ import ( ) func TestBitbucketDataCenterIntegrationData(t *testing.T) { - testSteps(t, []resource.TestStep{{ - Config: ` - data "spacelift_bitbucket_datacenter_integration" "test" {} - `, - Check: Resource( - "data.spacelift_bitbucket_datacenter_integration.test", - Attribute("api_host", Equals(os.Getenv("SPACELIFT_PROVIDER_TEST_BITBUCKET_DATACENTER_API_HOST"))), - Attribute("webhook_secret", Equals(os.Getenv("SPACELIFT_PROVIDER_TEST_BITBUCKET_DATACENTER_WEBHOOK_SECRET"))), - Attribute("webhook_url", Equals(os.Getenv("SPACELIFT_PROVIDER_TEST_BITBUCKET_DATACENTER_WEBHOOK_URL"))), - Attribute("user_facing_host", Equals(os.Getenv("SPACELIFT_PROVIDER_TEST_BITBUCKET_DATACENTER_USER_FACING_HOST"))), - ), - }}) + t.Run("without the id specified", func(t *testing.T) { + testSteps(t, []resource.TestStep{{ + Config: ` + data "spacelift_bitbucket_datacenter_integration" "test" {} + `, + Check: Resource( + "data.spacelift_bitbucket_datacenter_integration.test", + Attribute("id", IsNotEmpty()), + Attribute("name", IsNotEmpty()), + Attribute("is_default", Equals("true")), + Attribute("space_id", IsNotEmpty()), + Attribute("api_host", Equals(os.Getenv("SPACELIFT_PROVIDER_TEST_BITBUCKET_DATACENTER_API_HOST"))), + Attribute("webhook_secret", Equals(os.Getenv("SPACELIFT_PROVIDER_TEST_BITBUCKET_DATACENTER_WEBHOOK_SECRET"))), + Attribute("webhook_url", Equals(os.Getenv("SPACELIFT_PROVIDER_TEST_BITBUCKET_DATACENTER_WEBHOOK_URL"))), + Attribute("user_facing_host", Equals(os.Getenv("SPACELIFT_PROVIDER_TEST_BITBUCKET_DATACENTER_USER_FACING_HOST"))), + ), + }}) + }) + + t.Run("with the id specified", func(t *testing.T) { + testSteps(t, []resource.TestStep{{ + Config: ` + data "spacelift_bitbucket_datacenter_integration" "test" { + id = "bitbucket-datacenter-default-integration" + } + `, + Check: Resource( + "data.spacelift_bitbucket_datacenter_integration.test", + Attribute("id", IsNotEmpty()), + Attribute("name", IsNotEmpty()), + Attribute("is_default", Equals("true")), + Attribute("space_id", IsNotEmpty()), + Attribute("api_host", Equals(os.Getenv("SPACELIFT_PROVIDER_TEST_BITBUCKET_DATACENTER_API_HOST"))), + Attribute("webhook_secret", Equals(os.Getenv("SPACELIFT_PROVIDER_TEST_BITBUCKET_DATACENTER_WEBHOOK_SECRET"))), + Attribute("webhook_url", Equals(os.Getenv("SPACELIFT_PROVIDER_TEST_BITBUCKET_DATACENTER_WEBHOOK_URL"))), + Attribute("user_facing_host", Equals(os.Getenv("SPACELIFT_PROVIDER_TEST_BITBUCKET_DATACENTER_USER_FACING_HOST"))), + ), + }}) + }) + } diff --git a/spacelift/data_module.go b/spacelift/data_module.go index 4c38fbfd..2d9f519e 100644 --- a/spacelift/data_module.go +++ b/spacelift/data_module.go @@ -60,6 +60,11 @@ func dataModule() *schema.Resource { Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Description: "ID of the Bitbucket Cloud integration", + Computed: true, + }, "namespace": { Type: schema.TypeString, Description: "Bitbucket Cloud namespace of the stack's repository", @@ -74,6 +79,11 @@ func dataModule() *schema.Resource { Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Description: "ID of the Bitbucket Datacenter integration", + Computed: true, + }, "namespace": { Type: schema.TypeString, Description: "Bitbucket Datacenter namespace of the stack's repository", diff --git a/spacelift/data_stack.go b/spacelift/data_stack.go index e68dc43e..708c9076 100644 --- a/spacelift/data_stack.go +++ b/spacelift/data_stack.go @@ -157,6 +157,11 @@ func dataStack() *schema.Resource { Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Description: "ID of the Bitbucket Cloud integration", + Computed: true, + }, "namespace": { Type: schema.TypeString, Description: "Bitbucket Cloud namespace of the stack's repository", @@ -171,6 +176,11 @@ func dataStack() *schema.Resource { Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Description: "ID of the Bitbucket Datacenter integration", + Computed: true, + }, "namespace": { Type: schema.TypeString, Description: "Bitbucket Datacenter namespace of the stack's repository", diff --git a/spacelift/internal/structs/module.go b/spacelift/internal/structs/module.go index ae3e4903..bde7d99b 100644 --- a/spacelift/internal/structs/module.go +++ b/spacelift/internal/structs/module.go @@ -43,9 +43,11 @@ func (m *Module) ExportVCSSettings(d *schema.ResourceData) error { vcsSettings["project"] = m.Namespace fieldName = "azure_devops" case VCSProviderBitbucketCloud: + vcsSettings["id"] = m.VCSIntegration.ID vcsSettings["namespace"] = m.Namespace fieldName = "bitbucket_cloud" case VCSProviderBitbucketDatacenter: + vcsSettings["id"] = m.VCSIntegration.ID vcsSettings["namespace"] = m.Namespace fieldName = "bitbucket_datacenter" case VCSProviderGitHubEnterprise: diff --git a/spacelift/internal/structs/stack.go b/spacelift/internal/structs/stack.go index ed957d7c..d6f4b51a 100644 --- a/spacelift/internal/structs/stack.go +++ b/spacelift/internal/structs/stack.go @@ -144,7 +144,10 @@ func (s *Stack) VCSSettings() (string, map[string]interface{}) { "namespace": s.Namespace, } case VCSProviderBitbucketDatacenter: - return "bitbucket_datacenter", singleKeyMap("namespace", s.Namespace) + return "bitbucket_datacenter", map[string]interface{}{ + "id": s.VCSIntegration.ID, + "namespace": s.Namespace, + } case VCSProviderGitHubEnterprise: return "github_enterprise", map[string]interface{}{ "id": s.VCSIntegration.ID, diff --git a/spacelift/resource_module.go b/spacelift/resource_module.go index e66b4bc4..8aeda310 100644 --- a/spacelift/resource_module.go +++ b/spacelift/resource_module.go @@ -93,6 +93,11 @@ func resourceModule() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Optional: true, + Description: "The ID of the Bitbucket Datacenter integration. If not specified, the default integration will be used.", + }, "namespace": { Type: schema.TypeString, Required: true, @@ -375,6 +380,10 @@ func getSourceData(d *schema.ResourceData) (provider *graphql.String, namespace } if bitbucketDatacenter, ok := d.Get("bitbucket_datacenter").([]interface{}); ok && len(bitbucketDatacenter) > 0 { + bitbucketDatacenterSettings := bitbucketDatacenter[0].(map[string]interface{}) + if id, ok := bitbucketDatacenterSettings["id"]; ok && id != nil && id.(string) != "" { + vcsIntegrationID = graphql.NewID(id) + } namespace = toOptionalString(bitbucketDatacenter[0].(map[string]interface{})["namespace"]) provider = graphql.NewString(graphql.String(structs.VCSProviderBitbucketDatacenter)) diff --git a/spacelift/resource_stack.go b/spacelift/resource_stack.go index 834ccef6..637d8c76 100644 --- a/spacelift/resource_stack.go +++ b/spacelift/resource_stack.go @@ -232,6 +232,11 @@ func resourceStack() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Optional: true, + Description: "The ID of the Bitbucket Datacenter integration. If not specified, the default integration will be used.", + }, "namespace": { Type: schema.TypeString, Required: true, @@ -770,6 +775,10 @@ func stackInput(d *schema.ResourceData) structs.StackInput { } if bitbucketDatacenter, ok := d.Get("bitbucket_datacenter").([]interface{}); ok && len(bitbucketDatacenter) > 0 { + bitbucketDatacenterSettings := bitbucketDatacenter[0].(map[string]interface{}) + if id, ok := bitbucketDatacenterSettings["id"]; ok && id != nil && id.(string) != "" { + ret.VCSIntegrationID = graphql.NewID(id.(string)) + } ret.Namespace = toOptionalString(bitbucketDatacenter[0].(map[string]interface{})["namespace"]) ret.Provider = graphql.NewString(graphql.String(structs.VCSProviderBitbucketDatacenter)) }