From 0790157154cc8b858143cb51a07d5f5a5b80abdb Mon Sep 17 00:00:00 2001 From: Jeffrey Arneson Date: Wed, 12 Feb 2025 20:19:35 -0600 Subject: [PATCH 1/4] Populate team_id for vercel_integration_project_access when using the team from the provider. --- vercel/resource_integration_project_access.go | 80 ++++++++++--------- ...esource_integration_project_access_test.go | 43 ++++++++++ 2 files changed, 86 insertions(+), 37 deletions(-) diff --git a/vercel/resource_integration_project_access.go b/vercel/resource_integration_project_access.go index d9a75a2c..7c45ce2c 100644 --- a/vercel/resource_integration_project_access.go +++ b/vercel/resource_integration_project_access.go @@ -88,6 +88,19 @@ func (r *integrationProjectAccessResource) Create(ctx context.Context, req resou return } + teamID := plan.TeamID + if teamID.ValueString() == "" { + t, err := r.client.Team(ctx, "") + if err != nil { + resp.Diagnostics.AddError( + "Error getting team from provider", + "Could not read team from provider, unexpected error: "+err.Error(), + ) + return + } + teamID = types.StringValue(t.ID) + } + _, err := r.client.GrantIntegrationProjectAccess(ctx, plan.IntegrationID.ValueString(), plan.ProjectID.ValueString(), plan.TeamID.ValueString()) if err != nil { resp.Diagnostics.AddError( @@ -98,7 +111,7 @@ func (r *integrationProjectAccessResource) Create(ctx context.Context, req resou } result := IntegrationProjectAccess{ - TeamID: plan.TeamID, + TeamID: teamID, IntegrationID: plan.IntegrationID, ProjectID: plan.ProjectID, } @@ -124,6 +137,19 @@ func (r *integrationProjectAccessResource) Read(ctx context.Context, req resourc return } + teamID := state.TeamID + if teamID.ValueString() == "" { + t, err := r.client.Team(ctx, "") + if err != nil { + resp.Diagnostics.AddError( + "Error getting team from provider", + "Could not read team from provider, unexpected error: "+err.Error(), + ) + return + } + teamID = types.StringValue(t.ID) + } + allowed, err := r.client.GetIntegrationProjectAccess(ctx, state.IntegrationID.ValueString(), state.ProjectID.ValueString(), state.TeamID.ValueString()) if err != nil { resp.Diagnostics.AddError( @@ -134,7 +160,7 @@ func (r *integrationProjectAccessResource) Read(ctx context.Context, req resourc } result := IntegrationProjectAccess{ - TeamID: state.TeamID, + TeamID: teamID, IntegrationID: state.IntegrationID, ProjectID: state.ProjectID, } @@ -157,40 +183,7 @@ func (r *integrationProjectAccessResource) Read(ctx context.Context, req resourc } func (r *integrationProjectAccessResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - var plan IntegrationProjectAccess - diags := req.Plan.Get(ctx, &plan) - resp.Diagnostics.Append(diags...) - if resp.Diagnostics.HasError() { - return - } - - allowed, err := r.client.GrantIntegrationProjectAccess(ctx, plan.IntegrationID.ValueString(), plan.ProjectID.ValueString(), plan.TeamID.ValueString()) - if err != nil { - resp.Diagnostics.AddError( - "Error granting integration project access", - "Could not grant integration project access, unexpected error: "+err.Error(), - ) - return - } - - result := IntegrationProjectAccess{ - TeamID: plan.TeamID, - IntegrationID: plan.IntegrationID, - ProjectID: plan.ProjectID, - } - - tflog.Info(ctx, "granted integration project access", map[string]interface{}{ - "team_id": result.TeamID.ValueString(), - "integration_id": result.IntegrationID.ValueString(), - "project_id": result.ProjectID.ValueString(), - "allowed": allowed, - }) - - diags = resp.State.Set(ctx, result) - resp.Diagnostics.Append(diags...) - if resp.Diagnostics.HasError() { - return - } + panic("all plans should result in recreation") } func (r *integrationProjectAccessResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { @@ -201,6 +194,19 @@ func (r *integrationProjectAccessResource) Delete(ctx context.Context, req resou return } + teamID := plan.TeamID + if teamID.ValueString() == "" { + t, err := r.client.Team(ctx, "") + if err != nil { + resp.Diagnostics.AddError( + "Error getting team from provider", + "Could not read team from provider, unexpected error: "+err.Error(), + ) + return + } + teamID = types.StringValue(t.ID) + } + allowed, err := r.client.RevokeIntegrationProjectAccess(ctx, plan.IntegrationID.ValueString(), plan.ProjectID.ValueString(), plan.TeamID.ValueString()) if err != nil { resp.Diagnostics.AddError( @@ -211,7 +217,7 @@ func (r *integrationProjectAccessResource) Delete(ctx context.Context, req resou } result := IntegrationProjectAccess{ - TeamID: plan.TeamID, + TeamID: teamID, IntegrationID: plan.IntegrationID, ProjectID: plan.ProjectID, } diff --git a/vercel/resource_integration_project_access_test.go b/vercel/resource_integration_project_access_test.go index 70e76839..b722c1dd 100644 --- a/vercel/resource_integration_project_access_test.go +++ b/vercel/resource_integration_project_access_test.go @@ -59,6 +59,25 @@ func TestAcc_IntegrationProjectAccess(t *testing.T) { Config: testAccIntegrationProjectAccess(name, teamIDConfig(), testExistingIntegration()), Check: resource.ComposeAggregateTestCheckFunc( testCheckIntegrationProjectAccessExists("vercel_integration_project_access.test_integration_access", testTeam()), + resource.TestCheckResourceAttr("vercel_integration_project_access.test_integration_access", "team_id", testTeam()), + ), + }, + }, + }) +} + +func TestAcc_IntegrationProjectAccessWithoutExplicitTeam(t *testing.T) { + name := acctest.RandString(16) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + CheckDestroy: testCheckIntegrationProjectAccessDestroyed("vercel_integration_project_access.test_integration_access", testTeam()), + Steps: []resource.TestStep{ + { + Config: testAccIntegrationProjectAccessUsingProvider(name, testTeam(), testExistingIntegration()), + Check: resource.ComposeAggregateTestCheckFunc( + testCheckIntegrationProjectAccessExists("vercel_integration_project_access.test_integration_access", testTeam()), + resource.TestCheckResourceAttr("vercel_integration_project_access.test_integration_access", "team_id", testTeam()), ), }, }, @@ -67,6 +86,10 @@ func TestAcc_IntegrationProjectAccess(t *testing.T) { func testAccIntegrationProjectAccess(name, team, integration string) string { return fmt.Sprintf(` +provider "vercel" { + team = "%[4]s" +} + data "vercel_endpoint_verification" "test" { %[2]s } @@ -81,5 +104,25 @@ resource "vercel_integration_project_access" "test_integration_access" { project_id = vercel_project.test.id %[2]s } +`, name, team, integration, testTeam()) +} + +func testAccIntegrationProjectAccessUsingProvider(name, team, integration string) string { + return fmt.Sprintf(` +provider "vercel" { + team = "%[2]s" +} + +data "vercel_endpoint_verification" "test" { +} + +resource "vercel_project" "test" { + name = "test-acc-%[1]s" +} + +resource "vercel_integration_project_access" "test_integration_access" { + integration_id = "%[3]s" + project_id = vercel_project.test.id +} `, name, team, integration) } From a4f1f758350fc22e6452f3630ef235402a02c950 Mon Sep 17 00:00:00 2001 From: Jeffrey Arneson Date: Thu, 13 Feb 2025 09:26:30 -0600 Subject: [PATCH 2/4] fix lint --- vercel/resource_integration_project_access.go | 2 +- vercel/resource_integration_project_access_test.go | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/vercel/resource_integration_project_access.go b/vercel/resource_integration_project_access.go index 7c45ce2c..e6585780 100644 --- a/vercel/resource_integration_project_access.go +++ b/vercel/resource_integration_project_access.go @@ -183,7 +183,7 @@ func (r *integrationProjectAccessResource) Read(ctx context.Context, req resourc } func (r *integrationProjectAccessResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - panic("all plans should result in recreation") + resp.Diagnostics.AddError("Access should always be recreated", "Something incorrectly caused an Update, this should always be recreated instead of updated.") } func (r *integrationProjectAccessResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { diff --git a/vercel/resource_integration_project_access_test.go b/vercel/resource_integration_project_access_test.go index b722c1dd..a8fa3752 100644 --- a/vercel/resource_integration_project_access_test.go +++ b/vercel/resource_integration_project_access_test.go @@ -86,10 +86,6 @@ func TestAcc_IntegrationProjectAccessWithoutExplicitTeam(t *testing.T) { func testAccIntegrationProjectAccess(name, team, integration string) string { return fmt.Sprintf(` -provider "vercel" { - team = "%[4]s" -} - data "vercel_endpoint_verification" "test" { %[2]s } @@ -108,6 +104,7 @@ resource "vercel_integration_project_access" "test_integration_access" { } func testAccIntegrationProjectAccessUsingProvider(name, team, integration string) string { + //lintignore:AT004 return fmt.Sprintf(` provider "vercel" { team = "%[2]s" From 38cfc1095b27d627c9788efb75a4e288c9fb6be4 Mon Sep 17 00:00:00 2001 From: Jeffrey Arneson Date: Thu, 13 Feb 2025 10:13:56 -0600 Subject: [PATCH 3/4] move TeamID computation to client --- client/integrations.go | 41 ++++++++++--- vercel/resource_integration_project_access.go | 57 +++---------------- ...esource_integration_project_access_test.go | 8 +-- 3 files changed, 45 insertions(+), 61 deletions(-) diff --git a/client/integrations.go b/client/integrations.go index 89c9c03b..2e06f02b 100644 --- a/client/integrations.go +++ b/client/integrations.go @@ -7,7 +7,12 @@ import ( "github.com/hashicorp/terraform-plugin-log/tflog" ) -func (c *Client) GetIntegrationProjectAccess(ctx context.Context, integrationID, projectID, teamID string) (bool, error) { +type IntegrationProjectAccess struct { + Allowed bool + TeamID string +} + +func (c *Client) GetIntegrationProjectAccess(ctx context.Context, integrationID, projectID, teamID string) (IntegrationProjectAccess, error) { url := fmt.Sprintf("%s/v1/integrations/configuration/%s/project/%s", c.baseURL, integrationID, projectID) if c.teamID(teamID) != "" { url = fmt.Sprintf("%s?teamId=%s", url, c.teamID(teamID)) @@ -28,12 +33,18 @@ func (c *Client) GetIntegrationProjectAccess(ctx context.Context, integrationID, url: url, body: "", }, &e); err != nil { - return false, err + return IntegrationProjectAccess{ + Allowed: false, + TeamID: c.teamID(teamID), + }, err } - return e.Allowed, nil + return IntegrationProjectAccess{ + Allowed: e.Allowed, + TeamID: c.teamID(teamID), + }, nil } -func (c *Client) GrantIntegrationProjectAccess(ctx context.Context, integrationID, projectID, teamID string) (bool, error) { +func (c *Client) GrantIntegrationProjectAccess(ctx context.Context, integrationID, projectID, teamID string) (IntegrationProjectAccess, error) { url := fmt.Sprintf("%s/v1/integrations/configuration/%s/project/%s", c.baseURL, integrationID, projectID) if c.teamID(teamID) != "" { url = fmt.Sprintf("%s?teamId=%s", url, c.teamID(teamID)) @@ -54,12 +65,18 @@ func (c *Client) GrantIntegrationProjectAccess(ctx context.Context, integrationI url: url, body: `{ "allowed": true }`, }, &e); err != nil { - return false, err + return IntegrationProjectAccess{ + Allowed: false, + TeamID: c.teamID(teamID), + }, err } - return true, nil + return IntegrationProjectAccess{ + Allowed: true, + TeamID: c.teamID(teamID), + }, nil } -func (c *Client) RevokeIntegrationProjectAccess(ctx context.Context, integrationID, projectID, teamID string) (bool, error) { +func (c *Client) RevokeIntegrationProjectAccess(ctx context.Context, integrationID, projectID, teamID string) (IntegrationProjectAccess, error) { url := fmt.Sprintf("%s/v1/integrations/configuration/%s/project/%s", c.baseURL, integrationID, projectID) if c.teamID(teamID) != "" { url = fmt.Sprintf("%s?teamId=%s", url, c.teamID(teamID)) @@ -80,7 +97,13 @@ func (c *Client) RevokeIntegrationProjectAccess(ctx context.Context, integration url: url, body: `{ "allowed": false }`, }, &e); err != nil { - return false, err + return IntegrationProjectAccess{ + Allowed: false, + TeamID: c.teamID(teamID), + }, err } - return false, nil + return IntegrationProjectAccess{ + Allowed: false, + TeamID: c.teamID(teamID), + }, nil } diff --git a/vercel/resource_integration_project_access.go b/vercel/resource_integration_project_access.go index e6585780..c66fcb78 100644 --- a/vercel/resource_integration_project_access.go +++ b/vercel/resource_integration_project_access.go @@ -88,20 +88,7 @@ func (r *integrationProjectAccessResource) Create(ctx context.Context, req resou return } - teamID := plan.TeamID - if teamID.ValueString() == "" { - t, err := r.client.Team(ctx, "") - if err != nil { - resp.Diagnostics.AddError( - "Error getting team from provider", - "Could not read team from provider, unexpected error: "+err.Error(), - ) - return - } - teamID = types.StringValue(t.ID) - } - - _, err := r.client.GrantIntegrationProjectAccess(ctx, plan.IntegrationID.ValueString(), plan.ProjectID.ValueString(), plan.TeamID.ValueString()) + ipa, err := r.client.GrantIntegrationProjectAccess(ctx, plan.IntegrationID.ValueString(), plan.ProjectID.ValueString(), plan.TeamID.ValueString()) if err != nil { resp.Diagnostics.AddError( "Error granting integration project access", @@ -111,7 +98,7 @@ func (r *integrationProjectAccessResource) Create(ctx context.Context, req resou } result := IntegrationProjectAccess{ - TeamID: teamID, + TeamID: types.StringValue(ipa.TeamID), IntegrationID: plan.IntegrationID, ProjectID: plan.ProjectID, } @@ -137,20 +124,7 @@ func (r *integrationProjectAccessResource) Read(ctx context.Context, req resourc return } - teamID := state.TeamID - if teamID.ValueString() == "" { - t, err := r.client.Team(ctx, "") - if err != nil { - resp.Diagnostics.AddError( - "Error getting team from provider", - "Could not read team from provider, unexpected error: "+err.Error(), - ) - return - } - teamID = types.StringValue(t.ID) - } - - allowed, err := r.client.GetIntegrationProjectAccess(ctx, state.IntegrationID.ValueString(), state.ProjectID.ValueString(), state.TeamID.ValueString()) + ipa, err := r.client.GetIntegrationProjectAccess(ctx, state.IntegrationID.ValueString(), state.ProjectID.ValueString(), state.TeamID.ValueString()) if err != nil { resp.Diagnostics.AddError( "Error granting integration project access", @@ -160,7 +134,7 @@ func (r *integrationProjectAccessResource) Read(ctx context.Context, req resourc } result := IntegrationProjectAccess{ - TeamID: teamID, + TeamID: types.StringValue(ipa.TeamID), IntegrationID: state.IntegrationID, ProjectID: state.ProjectID, } @@ -168,10 +142,10 @@ func (r *integrationProjectAccessResource) Read(ctx context.Context, req resourc "team_id": result.TeamID.ValueString(), "integration_id": result.IntegrationID.ValueString(), "project_id": result.ProjectID.ValueString(), - "allowed": allowed, + "allowed": ipa.Allowed, }) - if allowed { + if ipa.Allowed { diags = resp.State.Set(ctx, result) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { @@ -194,20 +168,7 @@ func (r *integrationProjectAccessResource) Delete(ctx context.Context, req resou return } - teamID := plan.TeamID - if teamID.ValueString() == "" { - t, err := r.client.Team(ctx, "") - if err != nil { - resp.Diagnostics.AddError( - "Error getting team from provider", - "Could not read team from provider, unexpected error: "+err.Error(), - ) - return - } - teamID = types.StringValue(t.ID) - } - - allowed, err := r.client.RevokeIntegrationProjectAccess(ctx, plan.IntegrationID.ValueString(), plan.ProjectID.ValueString(), plan.TeamID.ValueString()) + ipa, err := r.client.RevokeIntegrationProjectAccess(ctx, plan.IntegrationID.ValueString(), plan.ProjectID.ValueString(), plan.TeamID.ValueString()) if err != nil { resp.Diagnostics.AddError( "Error revoking integration project access", @@ -217,7 +178,7 @@ func (r *integrationProjectAccessResource) Delete(ctx context.Context, req resou } result := IntegrationProjectAccess{ - TeamID: teamID, + TeamID: types.StringValue(ipa.TeamID), IntegrationID: plan.IntegrationID, ProjectID: plan.ProjectID, } @@ -226,6 +187,6 @@ func (r *integrationProjectAccessResource) Delete(ctx context.Context, req resou "team_id": result.TeamID.ValueString(), "integration_id": result.IntegrationID.ValueString(), "project_id": result.ProjectID.ValueString(), - "allowed": allowed, + "allowed": ipa.Allowed, }) } diff --git a/vercel/resource_integration_project_access_test.go b/vercel/resource_integration_project_access_test.go index a8fa3752..c48682e7 100644 --- a/vercel/resource_integration_project_access_test.go +++ b/vercel/resource_integration_project_access_test.go @@ -17,11 +17,11 @@ func testCheckIntegrationProjectAccessDestroyed(n, teamID string) resource.TestC return fmt.Errorf("not found: %s", n) } - allowed, err := testClient().GetIntegrationProjectAccess(context.TODO(), rs.Primary.Attributes["integration_id"], rs.Primary.Attributes["project_id"], teamID) + ipa, err := testClient().GetIntegrationProjectAccess(context.TODO(), rs.Primary.Attributes["integration_id"], rs.Primary.Attributes["project_id"], teamID) if err != nil { return err } - if allowed { + if ipa.Allowed { return fmt.Errorf("expected project to not allow access to integration") } @@ -36,11 +36,11 @@ func testCheckIntegrationProjectAccessExists(n, teamID string) resource.TestChec return fmt.Errorf("not found: %s", n) } - allowed, err := testClient().GetIntegrationProjectAccess(context.TODO(), rs.Primary.Attributes["integration_id"], rs.Primary.Attributes["project_id"], teamID) + ipa, err := testClient().GetIntegrationProjectAccess(context.TODO(), rs.Primary.Attributes["integration_id"], rs.Primary.Attributes["project_id"], teamID) if err != nil { return err } - if !allowed { + if !ipa.Allowed { return fmt.Errorf("expected project to allow access to integration") } From f9301509493a378bffadcc264cd82040d1974b13 Mon Sep 17 00:00:00 2001 From: Jeffrey Arneson Date: Thu, 13 Feb 2025 10:18:01 -0600 Subject: [PATCH 4/4] goimports --- client/integrations.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/client/integrations.go b/client/integrations.go index 2e06f02b..2fc3053e 100644 --- a/client/integrations.go +++ b/client/integrations.go @@ -9,7 +9,7 @@ import ( type IntegrationProjectAccess struct { Allowed bool - TeamID string + TeamID string } func (c *Client) GetIntegrationProjectAccess(ctx context.Context, integrationID, projectID, teamID string) (IntegrationProjectAccess, error) { @@ -35,12 +35,12 @@ func (c *Client) GetIntegrationProjectAccess(ctx context.Context, integrationID, }, &e); err != nil { return IntegrationProjectAccess{ Allowed: false, - TeamID: c.teamID(teamID), + TeamID: c.teamID(teamID), }, err } return IntegrationProjectAccess{ Allowed: e.Allowed, - TeamID: c.teamID(teamID), + TeamID: c.teamID(teamID), }, nil } @@ -67,12 +67,12 @@ func (c *Client) GrantIntegrationProjectAccess(ctx context.Context, integrationI }, &e); err != nil { return IntegrationProjectAccess{ Allowed: false, - TeamID: c.teamID(teamID), + TeamID: c.teamID(teamID), }, err } return IntegrationProjectAccess{ Allowed: true, - TeamID: c.teamID(teamID), + TeamID: c.teamID(teamID), }, nil } @@ -99,11 +99,11 @@ func (c *Client) RevokeIntegrationProjectAccess(ctx context.Context, integration }, &e); err != nil { return IntegrationProjectAccess{ Allowed: false, - TeamID: c.teamID(teamID), + TeamID: c.teamID(teamID), }, err } return IntegrationProjectAccess{ Allowed: false, - TeamID: c.teamID(teamID), + TeamID: c.teamID(teamID), }, nil }