diff --git a/github/data_source_github_actions_organization_remove_token.go b/github/data_source_github_actions_organization_remove_token.go new file mode 100644 index 000000000..109ef8313 --- /dev/null +++ b/github/data_source_github_actions_organization_remove_token.go @@ -0,0 +1,55 @@ +package github + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// dataSourceGithubActionsOrganizationRemoveToken is a data source that creates a token that can be +// used to remove a self-hosted runner from an organization. +// https://docs.github.com/en/enterprise-cloud@latest/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-remove-token-for-an-organization +func dataSourceGithubActionsOrganizationRemoveToken() *schema.Resource { + return &schema.Resource{ + Read: dataSourceGithubActionsOrganizationRemoveTokenRead, + + Schema: map[string]*schema.Schema{ + "token": { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "Token used to remove a self-hosted runner from an organization.", + }, + "expires_at": { + Type: schema.TypeInt, + Computed: true, + Description: "The token expiration date.", + }, + }, + } +} + +func dataSourceGithubActionsOrganizationRemoveTokenRead(d *schema.ResourceData, meta any) error { + client := meta.(*Owner).v3client + owner := meta.(*Owner).name + + log.Printf("[DEBUG] Creating a GitHub Actions organization remove token for %s", owner) + token, _, err := client.Actions.CreateOrganizationRemoveToken(context.TODO(), owner) + if err != nil { + return fmt.Errorf("error creating a GitHub Actions organization remove token for %s: %w", owner, err) + } + + d.SetId(owner) + err = d.Set("token", token.Token) + if err != nil { + return err + } + err = d.Set("expires_at", token.ExpiresAt.Unix()) + if err != nil { + return err + } + + return nil +} diff --git a/github/data_source_github_actions_organization_remove_token_test.go b/github/data_source_github_actions_organization_remove_token_test.go new file mode 100644 index 000000000..bdfa772be --- /dev/null +++ b/github/data_source_github_actions_organization_remove_token_test.go @@ -0,0 +1,46 @@ +package github + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccGithubActionsOrganizationRemoveTokenDataSource(t *testing.T) { + t.Run("get an organization remove token without error", func(t *testing.T) { + config := ` + data "github_actions_organization_remove_token" "test" { + } + ` + + check := resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.github_actions_organization_remove_token.test", "token"), + resource.TestCheckResourceAttrSet("data.github_actions_organization_remove_token.test", "expires_at"), + ) + + testCase := func(t *testing.T, mode string) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { skipUnlessMode(t, mode) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: config, + Check: check, + }, + }, + }) + } + + t.Run("with an anonymous account", func(t *testing.T) { + t.Skip("anonymous account not supported for this operation") + }) + + t.Run("with an individual account", func(t *testing.T) { + testCase(t, individual) + }) + + t.Run("with an organization account", func(t *testing.T) { + testCase(t, organization) + }) + }) +} diff --git a/github/data_source_github_actions_registration_token_test.go b/github/data_source_github_actions_registration_token_test.go index 742b5c48d..a9d862ee1 100644 --- a/github/data_source_github_actions_registration_token_test.go +++ b/github/data_source_github_actions_registration_token_test.go @@ -16,6 +16,7 @@ func TestAccGithubActionsRegistrationTokenDataSource(t *testing.T) { resource "github_repository" "test" { name = "tf-acc-test-%[1]s" auto_init = true + vulnerability_alerts = true } data "github_actions_registration_token" "test" { diff --git a/github/data_source_github_actions_remove_token.go b/github/data_source_github_actions_remove_token.go new file mode 100644 index 000000000..f4d6b1024 --- /dev/null +++ b/github/data_source_github_actions_remove_token.go @@ -0,0 +1,62 @@ +package github + +import ( + "context" + "fmt" + "log" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +// dataSourceGithubActionsRemoveToken is a data source that creates a token that can be +// used to remove a self-hosted runner from a repository. +// https://docs.github.com/en/enterprise-cloud@latest/rest/actions/self-hosted-runners?apiVersion=2022-11-28#create-a-remove-token-for-a-repository +func dataSourceGithubActionsRemoveToken() *schema.Resource { + return &schema.Resource{ + Read: dataSourceGithubActionsRemoveTokenRead, + + Schema: map[string]*schema.Schema{ + "repository": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "Repository to remove the self-hosted runner from.", + }, + "token": { + Type: schema.TypeString, + Computed: true, + Sensitive: true, + Description: "Token used to remove a self-hosted runner from a repository.", + }, + "expires_at": { + Type: schema.TypeInt, + Computed: true, + Description: "The token expiration date.", + }, + }, + } +} + +func dataSourceGithubActionsRemoveTokenRead(d *schema.ResourceData, meta any) error { + client := meta.(*Owner).v3client + owner := meta.(*Owner).name + repoName := d.Get("repository").(string) + + log.Printf("[DEBUG] Creating a GitHub Actions repository remove token for %s/%s", owner, repoName) + token, _, err := client.Actions.CreateRemoveToken(context.TODO(), owner, repoName) + if err != nil { + return fmt.Errorf("error creating a GitHub Actions repository remove token for %s/%s: %w", owner, repoName, err) + } + + d.SetId(fmt.Sprintf("%s/%s", owner, repoName)) + err = d.Set("token", token.Token) + if err != nil { + return err + } + err = d.Set("expires_at", token.ExpiresAt.Unix()) + if err != nil { + return err + } + + return nil +} diff --git a/github/data_source_github_actions_remove_token_test.go b/github/data_source_github_actions_remove_token_test.go new file mode 100644 index 000000000..e2f553514 --- /dev/null +++ b/github/data_source_github_actions_remove_token_test.go @@ -0,0 +1,58 @@ +package github + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccGithubActionsRemoveTokenDataSource(t *testing.T) { + randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum) + + t.Run("get a repository remove token without error", func(t *testing.T) { + config := fmt.Sprintf(` + resource "github_repository" "test" { + name = "tf-acc-test-%[1]s" + auto_init = true + vulnerability_alerts = true + } + + data "github_actions_remove_token" "test" { + repository = github_repository.test.id + } + `, randomID) + + check := resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.github_actions_remove_token.test", "repository", fmt.Sprintf("tf-acc-test-%s", randomID)), + resource.TestCheckResourceAttrSet("data.github_actions_remove_token.test", "token"), + resource.TestCheckResourceAttrSet("data.github_actions_remove_token.test", "expires_at"), + ) + + testCase := func(t *testing.T, mode string) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { skipUnlessMode(t, mode) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: config, + Check: check, + }, + }, + }) + } + + t.Run("with an anonymous account", func(t *testing.T) { + t.Skip("anonymous account not supported for this operation") + }) + + t.Run("with an individual account", func(t *testing.T) { + testCase(t, individual) + }) + + t.Run("with an organization account", func(t *testing.T) { + testCase(t, organization) + }) + }) +} diff --git a/github/provider.go b/github/provider.go index 57f1da449..486e307b2 100644 --- a/github/provider.go +++ b/github/provider.go @@ -221,10 +221,12 @@ func Provider() *schema.Provider { "github_actions_organization_oidc_subject_claim_customization_template": dataSourceGithubActionsOrganizationOIDCSubjectClaimCustomizationTemplate(), "github_actions_organization_public_key": dataSourceGithubActionsOrganizationPublicKey(), "github_actions_organization_registration_token": dataSourceGithubActionsOrganizationRegistrationToken(), + "github_actions_organization_remove_token": dataSourceGithubActionsOrganizationRemoveToken(), "github_actions_organization_secrets": dataSourceGithubActionsOrganizationSecrets(), "github_actions_organization_variables": dataSourceGithubActionsOrganizationVariables(), "github_actions_public_key": dataSourceGithubActionsPublicKey(), "github_actions_registration_token": dataSourceGithubActionsRegistrationToken(), + "github_actions_remove_token": dataSourceGithubActionsRemoveToken(), "github_actions_repository_oidc_subject_claim_customization_template": dataSourceGithubActionsRepositoryOIDCSubjectClaimCustomizationTemplate(), "github_actions_secrets": dataSourceGithubActionsSecrets(), "github_actions_variables": dataSourceGithubActionsVariables(), diff --git a/github/resource_github_team.go b/github/resource_github_team.go index 482b9bc86..e6201a648 100644 --- a/github/resource_github_team.go +++ b/github/resource_github_team.go @@ -328,14 +328,15 @@ func resourceGithubTeamDelete(d *schema.ResourceData, meta any) error { ctx := context.WithValue(context.Background(), ctxId, d.Id()) _, err = client.Teams.DeleteTeamByID(ctx, orgId, id) - /* - When deleting a team and it failed, we need to check if it has already been deleted meanwhile. - This could be the case when deleting nested teams via Terraform by looping through a module - or resource and the parent team might have been deleted already. If the parent team had - been deleted already (via parallel runs), the child team is also already gone (deleted by - GitHub automatically). - So we're checking if it still exists and if not, simply remove it from TF state. - */if err != nil { + // When deleting a team and it failed, we need to check if it has already been deleted meanwhile. + // This could be the case when deleting nested teams via Terraform by looping through a module + // or resource and the parent team might have been deleted already. If the parent team had + // been deleted already (via parallel runs), the child team is also already gone (deleted by + // GitHub automatically). + // So we're checking if it still exists and if not, simply remove it from TF state. + // + // https://docs.github.com/en/enterprise-cloud@latest/rest/teams/teams?apiVersion=2022-11-28#delete-a-team + if err != nil { // Fetch the team in order to see if it exists or not (http 404) _, _, err = client.Teams.GetTeamByID(ctx, orgId, id) if err != nil { diff --git a/website/docs/d/actions_organization_remove_token.html.markdown b/website/docs/d/actions_organization_remove_token.html.markdown new file mode 100644 index 000000000..18958133b --- /dev/null +++ b/website/docs/d/actions_organization_remove_token.html.markdown @@ -0,0 +1,24 @@ +--- +layout: "github" +page_title: "GitHub: github_actions_organization_remove_token" +description: |- + Get a GitHub Actions organization remove token. +--- + +# actions_remove_token + +Use this data source to retrieve a GitHub Actions organization remove token. This token can then be used to remove a self-hosted runner. + +## Example Usage + +```hcl +data "github_actions_organization_remove_token" "example" { +} +``` + +## Argument Reference + +## Attributes Reference + + * `token` - The token that has been retrieved. + * `expires_at` - The token expiration date. diff --git a/website/docs/d/actions_remove_token.html.markdown b/website/docs/d/actions_remove_token.html.markdown new file mode 100644 index 000000000..8d4b20855 --- /dev/null +++ b/website/docs/d/actions_remove_token.html.markdown @@ -0,0 +1,27 @@ +--- +layout: "github" +page_title: "GitHub: github_actions_remove_token" +description: |- + Get a GitHub Actions repository remove token. +--- + +# actions_remove_token + +Use this data source to retrieve a GitHub Actions repository remove token. This token can then be used to remove a self-hosted runner. + +## Example Usage + +```hcl +data "github_actions_remove_token" "example" { + repository = "example_repo" +} +``` + +## Argument Reference + + * `repository` - (Required) Name of the repository to get a GitHub Actions remove token for. + +## Attributes Reference + + * `token` - The token that has been retrieved. + * `expires_at` - The token expiration date.