diff --git a/github/resource_github_repository.go b/github/resource_github_repository.go index 2419dee190..c3c8e9c07a 100644 --- a/github/resource_github_repository.go +++ b/github/resource_github_repository.go @@ -10,6 +10,7 @@ import ( "strings" "github.com/google/go-github/v81/github" + "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -321,7 +322,7 @@ func resourceGithubRepository() *schema.Resource { Type: schema.TypeBool, Optional: true, Default: false, - Description: "Specifies if the repository should be archived. Defaults to 'false'. NOTE Currently, the API does not support unarchiving.", + Description: "Specifies if the repository should be archived. Defaults to 'false'. Unarchiving is supported by setting this back to 'false'.", }, "archive_on_destroy": { Type: schema.TypeBool, @@ -686,7 +687,7 @@ func resourceGithubRepositoryCreate(ctx context.Context, d *schema.ResourceData, return diag.FromErr(err) } - d.SetId(*repo.Name) + d.SetId(repo.GetName()) } } else if d.Get("fork").(string) == "true" { // Handle repository forking @@ -757,6 +758,25 @@ func resourceGithubRepositoryCreate(ctx context.Context, d *schema.ResourceData, d.SetId(repo.GetName()) } + archived := d.Get("archived").(bool) + // If the repository is archived on creation, we need to skip calling Update to avoid 403 errors + if archived { + tflog.Debug(ctx, "Repository archived, skipping modifying topics, pages, visibility, and vulnerability alerts", map[string]any{ + "owner": meta.(*Owner).name, + "repository": d.Id(), + "archived": archived, + }) + // Archived is not set on Repository.Create, so we need to PATCH the repository to set it + repo, _, err := client.Repositories.Edit(ctx, owner, repoName, &github.Repository{ + Archived: github.Ptr(archived), + }) + if err != nil { + return diag.FromErr(err) + } + d.SetId(repo.GetName()) + return resourceGithubRepositoryRead(ctx, d, meta) + } + topics := repoReq.Topics if len(topics) > 0 { _, _, err := client.Repositories.ReplaceAllTopics(ctx, owner, repoName, topics) @@ -773,7 +793,7 @@ func resourceGithubRepositoryCreate(ctx context.Context, d *schema.ResourceData, } } - err := updateVulnerabilityAlerts(d, client, ctx, owner, repoName) + err := updateVulnerabilityAlerts(ctx, d, client, owner, repoName) if err != nil { return diag.FromErr(err) } @@ -915,12 +935,19 @@ func resourceGithubRepositoryRead(ctx context.Context, d *schema.ResourceData, m func resourceGithubRepositoryUpdate(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { // Can only update a repository if it is not archived or the update is to - // archive the repository (unarchiving is not supported by the GitHub API) + // archive the repository if d.Get("archived").(bool) && !d.HasChange("archived") { log.Printf("[INFO] Skipping update of archived repository") return nil } + tflog.Debug(ctx, "Updating repository", map[string]any{ + "owner": meta.(*Owner).name, + "repository": d.Id(), + "archived": d.Get("archived").(bool), + "archived_change": d.HasChange("archived"), + }) + client := meta.(*Owner).v3client repoReq := resourceGithubRepositoryObject(d) @@ -970,7 +997,7 @@ func resourceGithubRepositoryUpdate(ctx context.Context, d *schema.ResourceData, if err != nil { return diag.FromErr(err) } - d.SetId(*repo.Name) + d.SetId(repo.GetName()) if d.HasChange("pages") && !d.IsNewResource() { opts := expandPagesUpdate(d.Get("pages").([]any)) @@ -998,15 +1025,15 @@ func resourceGithubRepositoryUpdate(ctx context.Context, d *schema.ResourceData, if d.HasChange("topics") { topics := repoReq.Topics - _, _, err = client.Repositories.ReplaceAllTopics(ctx, owner, *repo.Name, topics) + _, _, err = client.Repositories.ReplaceAllTopics(ctx, owner, repo.GetName(), topics) if err != nil { return diag.FromErr(err) } - d.SetId(*repo.Name) + d.SetId(repo.GetName()) if d.HasChange("topics") { topics := repoReq.Topics - _, _, err = client.Repositories.ReplaceAllTopics(ctx, owner, *repo.Name, topics) + _, _, err = client.Repositories.ReplaceAllTopics(ctx, owner, repo.GetName(), topics) if err != nil { return diag.FromErr(err) } @@ -1014,7 +1041,7 @@ func resourceGithubRepositoryUpdate(ctx context.Context, d *schema.ResourceData, } if d.HasChange("vulnerability_alerts") { - err = updateVulnerabilityAlerts(d, client, ctx, owner, repoName) + err = updateVulnerabilityAlerts(ctx, d, client, owner, repoName) if err != nil { return diag.FromErr(err) } @@ -1118,7 +1145,7 @@ func expandPagesUpdate(input []any) *github.PagesUpdate { // must include the branch name and optionally the subdirectory /docs. // e.g. "master" or "master /docs" // This is only necessary if the BuildType is "legacy". - if update.BuildType == nil || *update.BuildType == "legacy" { + if update.BuildType == nil || update.GetBuildType() == "legacy" { pagesSource := pages["source"].([]any)[0].(map[string]any) sourceBranch := pagesSource["branch"].(string) sourcePath := "" @@ -1240,7 +1267,7 @@ func resourceGithubParseFullName(resourceDataLike interface { return parts[0], parts[1], true } -func updateVulnerabilityAlerts(d *schema.ResourceData, client *github.Client, ctx context.Context, owner, repoName string) error { +func updateVulnerabilityAlerts(ctx context.Context, d *schema.ResourceData, client *github.Client, owner, repoName string) error { updateVulnerabilityAlertsSDK := client.Repositories.DisableVulnerabilityAlerts vulnerabilityAlerts, ok := d.GetOk("vulnerability_alerts") @@ -1251,7 +1278,14 @@ func updateVulnerabilityAlerts(d *schema.ResourceData, client *github.Client, ct } resp, err := updateVulnerabilityAlertsSDK(ctx, owner, repoName) - if err != nil { + if err != nil && resp != nil { + tflog.Debug(ctx, "Error updating vulnerability alerts", map[string]any{ + "owner": owner, + "repository": repoName, + "error": err.Error(), + "status_code": resp.StatusCode, + "body": resp.Body, + }) // Check if the error is because an Organization or Enterprise policy is preventing the change // This is a temporary workaround while we extract Vulnerability Alerts into a separate resource. if resp.StatusCode == http.StatusUnprocessableEntity && strings.Contains(err.Error(), "An enforced security configuration prevented modifying") && !ok { diff --git a/github/resource_github_repository_test.go b/github/resource_github_repository_test.go index b83f0c7c62..64e1d35210 100644 --- a/github/resource_github_repository_test.go +++ b/github/resource_github_repository_test.go @@ -16,6 +16,10 @@ import ( ) func TestAccGithubRepository(t *testing.T) { + baseVisibility := "public" + if testAccConf.authMode == enterprise { + baseVisibility = "private" // Enable tests to run on GHEC EMU + } t.Run("creates and updates repositories without error", func(t *testing.T) { randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum) testRepoName := fmt.Sprintf("%screate-%s", testResourcePrefix, randomID) @@ -36,8 +40,9 @@ func TestAccGithubRepository(t *testing.T) { merge_commit_message = "PR_TITLE" auto_init = false web_commit_signoff_required = true + visibility = "%s" } - `, testRepoName) + `, testRepoName, baseVisibility) check := resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -83,8 +88,9 @@ func TestAccGithubRepository(t *testing.T) { resource "github_repository" "test" { name = "%[1]s" description = "Terraform acceptance tests %[2]s" + visibility = "%s" } - `, oldName, randomID) + `, oldName, randomID, baseVisibility) checks := map[string]resource.TestCheckFunc{ "before": resource.ComposeTestCheckFunc( @@ -137,8 +143,9 @@ func TestAccGithubRepository(t *testing.T) { name = "%s" description = "Terraform acceptance tests %[1]s" auto_init = false + visibility = "%s" } - `, testRepoName) + `, testRepoName, baseVisibility) check := resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("github_repository.test", "name"), @@ -169,8 +176,9 @@ func TestAccGithubRepository(t *testing.T) { name = "%s" description = "Terraform acceptance tests %[1]s" archived = false + visibility = "%s" } - `, testRepoName) + `, testRepoName, baseVisibility) checks := map[string]resource.TestCheckFunc{ "before": resource.ComposeTestCheckFunc( @@ -204,6 +212,83 @@ func TestAccGithubRepository(t *testing.T) { }, }) }) + t.Run("unarchives archived repositories without error", func(t *testing.T) { + randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum) + testRepoName := fmt.Sprintf("%sunarchive-%s", testResourcePrefix, randomID) + config := fmt.Sprintf(` + resource "github_repository" "test" { + name = "%s" + description = "Terraform acceptance tests %[1]s" + archived = false + visibility = "%s" + } + `, testRepoName, baseVisibility) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { skipUnauthenticated(t) }, + ProviderFactories: providerFactories, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "github_repository.test", "archived", + "false", + ), + ), + }, + { + Config: strings.Replace(config, + `archived = false`, + `archived = true`, 1), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "github_repository.test", "archived", + "true", + ), + ), + }, + { + Config: config, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "github_repository.test", "archived", + "false", + ), + ), + }, + }, + }) + }) + + t.Run("creates_repositories_as_archived_without_error", func(t *testing.T) { + randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum) + testRepoName := fmt.Sprintf("%screate-and-archive-%s", testResourcePrefix, randomID) + config := fmt.Sprintf(` + resource "github_repository" "test" { + name = "%s" + description = "Terraform acceptance tests %[1]s" + archived = true + visibility = "%s" + } + `, testRepoName, baseVisibility) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { skipUnauthenticated(t) }, + ProviderFactories: providerFactories, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "github_repository.test", "archived", + "true", + ), + ), + }, + }, + }) + }) t.Run("manages the project feature for a repository", func(t *testing.T) { randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum) @@ -213,8 +298,9 @@ func TestAccGithubRepository(t *testing.T) { name = "%s" description = "Terraform acceptance tests %[1]s" has_projects = false + visibility = "%s" } - `, testRepoName) + `, testRepoName, baseVisibility) checks := map[string]resource.TestCheckFunc{ "before": resource.ComposeTestCheckFunc( @@ -258,13 +344,14 @@ func TestAccGithubRepository(t *testing.T) { description = "Terraform acceptance tests %[1]s" default_branch = "main" auto_init = true + visibility = "%s" } resource "github_branch" "default" { repository = github_repository.test.name branch = "default" } - `, testRepoName) + `, testRepoName, baseVisibility) checks := map[string]resource.TestCheckFunc{ "before": resource.ComposeTestCheckFunc( @@ -316,8 +403,9 @@ func TestAccGithubRepository(t *testing.T) { name = "%s" description = "Terraform acceptance tests %[1]s" default_branch = "main" + visibility = "%s" } - `, testRepoName) + `, testRepoName, baseVisibility) check := resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -356,8 +444,9 @@ func TestAccGithubRepository(t *testing.T) { description = "Terraform acceptance tests %[1]s" license_template = "ms-pl" gitignore_template = "C++" + visibility = "%s" } - `, testRepoName) + `, testRepoName, baseVisibility) check := resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -390,8 +479,9 @@ func TestAccGithubRepository(t *testing.T) { name = "%s" description = "Terraform acceptance tests %[1]s" topics = ["terraform", "testing"] + visibility = "%s" } - `, testRepoName) + `, testRepoName, baseVisibility) check := resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -419,6 +509,7 @@ func TestAccGithubRepository(t *testing.T) { resource "github_repository" "test" { name = "%s" description = "Terraform acceptance tests %[1]s" + visibility = "%s" template { owner = "%s" @@ -426,7 +517,7 @@ func TestAccGithubRepository(t *testing.T) { } } - `, testRepoName, testAccConf.testPublicTemplateRepositoryOwner, testAccConf.testPublicTemplateRepository) + `, testRepoName, baseVisibility, testAccConf.testPublicTemplateRepositoryOwner, testAccConf.testPublicTemplateRepository) check := resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -454,6 +545,7 @@ func TestAccGithubRepository(t *testing.T) { resource "github_repository" "test" { name = "%s" description = "Terraform acceptance tests %[1]s" + visibility = "%s" template { owner = "%s" @@ -461,7 +553,7 @@ func TestAccGithubRepository(t *testing.T) { } } - `, testRepoName, testAccConf.owner, testAccConf.testOrgTemplateRepository) + `, testRepoName, baseVisibility, testAccConf.owner, testAccConf.testOrgTemplateRepository) check := resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( @@ -491,8 +583,9 @@ func TestAccGithubRepository(t *testing.T) { auto_init = true archive_on_destroy = true archived = false + visibility = "%s" } - `, testRepoName) + `, testRepoName, baseVisibility) checks := map[string]resource.TestCheckFunc{ "before": resource.ComposeTestCheckFunc( @@ -548,7 +641,12 @@ func TestAccGithubRepository(t *testing.T) { `, repoName) resource.Test(t, resource.TestCase{ - PreCheck: func() { skipUnauthenticated(t) }, + PreCheck: func() { + skipUnauthenticated(t) + if testAccConf.authMode == enterprise { + t.Skip("Skipping as test mode is enterprise") + } + }, ProviderFactories: providerFactories, Steps: []resource.TestStep{ { @@ -624,7 +722,7 @@ resource "github_repository" "test" { }) }) - t.Run("configures vulnerability alerts for a private repository", func(t *testing.T) { + t.Run("configures_vulnerability_alerts_for_a_private_repository", func(t *testing.T) { randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum) repoName := fmt.Sprintf("%sprv-vuln-%s", testResourcePrefix, randomID) @@ -674,60 +772,46 @@ resource "github_repository" "test" { updatedMergeCommitTitle := "MERGE_MESSAGE" updatedMergeCommitMessage := "PR_TITLE" - configs := map[string]string{ - "before": fmt.Sprintf(` - resource "github_repository" "test" { - - name = "%[1]s" - allow_merge_commit = true - merge_commit_title = "%s" - merge_commit_message = "%s" - } - `, testRepoName, mergeCommitTitle, mergeCommitMessage), - "after": fmt.Sprintf(` - resource "github_repository" "test" { - name = "%[1]s" - allow_merge_commit = true - merge_commit_title = "%s" - merge_commit_message = "%s" - } - `, testRepoName, updatedMergeCommitTitle, updatedMergeCommitMessage), - } + config := ` +resource "github_repository" "test" { - checks := map[string]resource.TestCheckFunc{ - "before": resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "github_repository.test", "merge_commit_title", - mergeCommitTitle, - ), - resource.TestCheckResourceAttr( - "github_repository.test", "merge_commit_message", - mergeCommitMessage, - ), - ), - "after": resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "github_repository.test", "merge_commit_title", - updatedMergeCommitTitle, - ), - resource.TestCheckResourceAttr( - "github_repository.test", "merge_commit_message", - updatedMergeCommitMessage, - ), - ), - } + name = "%[1]s" + allow_merge_commit = true + merge_commit_title = "%s" + merge_commit_message = "%s" + visibility = "%s" +} +` resource.Test(t, resource.TestCase{ PreCheck: func() { skipUnauthenticated(t) }, ProviderFactories: providerFactories, Steps: []resource.TestStep{ { - Config: configs["before"], - Check: checks["before"], + Config: fmt.Sprintf(config, testRepoName, mergeCommitTitle, mergeCommitMessage, baseVisibility), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "github_repository.test", "merge_commit_title", + mergeCommitTitle, + ), + resource.TestCheckResourceAttr( + "github_repository.test", "merge_commit_message", + mergeCommitMessage, + ), + ), }, { - Config: configs["after"], - Check: checks["after"], + Config: fmt.Sprintf(config, testRepoName, updatedMergeCommitTitle, updatedMergeCommitMessage, baseVisibility), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "github_repository.test", "merge_commit_title", + updatedMergeCommitTitle, + ), + resource.TestCheckResourceAttr( + "github_repository.test", "merge_commit_message", + updatedMergeCommitMessage, + ), + ), }, }, }) @@ -742,59 +826,45 @@ resource "github_repository" "test" { updatedSquashMergeCommitTitle := "COMMIT_OR_PR_TITLE" updatedSquashMergeCommitMessage := "COMMIT_MESSAGES" - configs := map[string]string{ - "before": fmt.Sprintf(` - resource "github_repository" "test" { - name = "%s" - allow_squash_merge = true - squash_merge_commit_title = "%s" - squash_merge_commit_message = "%s" - } - `, testRepoName, squashMergeCommitTitle, squashMergeCommitMessage), - "after": fmt.Sprintf(` - resource "github_repository" "test" { - name = "%s" - allow_squash_merge = true - squash_merge_commit_title = "%s" - squash_merge_commit_message = "%s" - } - `, testRepoNameAfter, updatedSquashMergeCommitTitle, updatedSquashMergeCommitMessage), - } - - checks := map[string]resource.TestCheckFunc{ - "before": resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "github_repository.test", "squash_merge_commit_title", - squashMergeCommitTitle, - ), - resource.TestCheckResourceAttr( - "github_repository.test", "squash_merge_commit_message", - squashMergeCommitMessage, - ), - ), - "after": resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "github_repository.test", "squash_merge_commit_title", - updatedSquashMergeCommitTitle, - ), - resource.TestCheckResourceAttr( - "github_repository.test", "squash_merge_commit_message", - updatedSquashMergeCommitMessage, - ), - ), - } + config := ` +resource "github_repository" "test" { + name = "%s" + allow_squash_merge = true + squash_merge_commit_title = "%s" + squash_merge_commit_message = "%s" + visibility = "%s" +} +` resource.Test(t, resource.TestCase{ PreCheck: func() { skipUnauthenticated(t) }, ProviderFactories: providerFactories, Steps: []resource.TestStep{ { - Config: configs["before"], - Check: checks["before"], + Config: fmt.Sprintf(config, testRepoName, squashMergeCommitTitle, squashMergeCommitMessage, baseVisibility), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "github_repository.test", "squash_merge_commit_title", + squashMergeCommitTitle, + ), + resource.TestCheckResourceAttr( + "github_repository.test", "squash_merge_commit_message", + squashMergeCommitMessage, + ), + ), }, { - Config: configs["after"], - Check: checks["after"], + Config: fmt.Sprintf(config, testRepoNameAfter, updatedSquashMergeCommitTitle, updatedSquashMergeCommitMessage, baseVisibility), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "github_repository.test", "squash_merge_commit_title", + updatedSquashMergeCommitTitle, + ), + resource.TestCheckResourceAttr( + "github_repository.test", "squash_merge_commit_message", + updatedSquashMergeCommitMessage, + ), + ), }, }, }) @@ -843,6 +913,7 @@ resource "github_repository" "test" { resource "github_repository" "test" { name = "%s" auto_init = true + visibility = "%s" pages { build_type = "legacy" @@ -851,7 +922,7 @@ resource "github_repository" "test" { } } } - `, testRepoName) + `, testRepoName, baseVisibility) resource.Test(t, resource.TestCase{ PreCheck: func() { skipUnauthenticated(t) }, @@ -875,11 +946,12 @@ resource "github_repository" "test" { resource "github_repository" "test" { name = "%s" auto_init = true + visibility = "%s" pages { build_type = "workflow" } } - `, testRepoName) + `, testRepoName, baseVisibility) resource.Test(t, resource.TestCase{ PreCheck: func() { skipUnauthenticated(t) }, @@ -988,23 +1060,27 @@ resource "github_repository" "test" { } `, testRepoName) - check := resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "github_repository.test", "security_and_analysis.0.secret_scanning.0.status", - "enabled", - ), - resource.TestCheckResourceAttr( - "github_repository.test", "security_and_analysis.0.secret_scanning_push_protection.0.status", - "disabled", - ), - ) resource.Test(t, resource.TestCase{ - PreCheck: func() { skipUnauthenticated(t) }, + PreCheck: func() { + skipUnauthenticated(t) + if testAccConf.authMode == enterprise { + t.Skip("Skipping as test mode is enterprise") + } + }, ProviderFactories: providerFactories, Steps: []resource.TestStep{ { Config: config, - Check: check, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "github_repository.test", "security_and_analysis.0.secret_scanning.0.status", + "enabled", + ), + resource.TestCheckResourceAttr( + "github_repository.test", "security_and_analysis.0.secret_scanning_push_protection.0.status", + "disabled", + ), + ), }, }, }) @@ -1057,7 +1133,7 @@ resource "github_repository" "test" { ) resource.Test(t, resource.TestCase{ - PreCheck: func() { skipUnlessMode(t, enterprise) }, + PreCheck: func() { skipUnlessEnterprise(t) }, ProviderFactories: providerFactories, Steps: []resource.TestStep{ { @@ -1095,7 +1171,12 @@ resource "github_repository" "test" { } resource.Test(t, resource.TestCase{ - PreCheck: func() { skipUnauthenticated(t) }, + PreCheck: func() { + skipUnauthenticated(t) + if testAccConf.authMode == enterprise { + t.Skip("Skipping as test mode is enterprise") + } + }, ProviderFactories: providerFactories, Steps: []resource.TestStep{ { @@ -1137,7 +1218,12 @@ resource "github_repository" "test" { `, testRepoName) resource.Test(t, resource.TestCase{ - PreCheck: func() { skipUnauthenticated(t) }, + PreCheck: func() { + skipUnauthenticated(t) + if testAccConf.authMode == enterprise { + t.Skip("Skipping as test mode is enterprise") + } + }, ProviderFactories: providerFactories, Steps: []resource.TestStep{ { @@ -1195,7 +1281,12 @@ resource "github_repository" "test" { } resource.Test(t, resource.TestCase{ - PreCheck: func() { skipUnauthenticated(t) }, + PreCheck: func() { + skipUnauthenticated(t) + if testAccConf.authMode == enterprise { + t.Skip("Skipping as test mode is enterprise") + } + }, ProviderFactories: providerFactories, Steps: []resource.TestStep{ { @@ -1212,7 +1303,7 @@ resource "github_repository" "test" { }) }) - t.Run("updates repos to internal visibility", func(t *testing.T) { + t.Run("updates_repos_to_internal_visibility", func(t *testing.T) { randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum) testRepoName := fmt.Sprintf("%sinternal-vuln-%s", testResourcePrefix, randomID) config := fmt.Sprintf(` @@ -1222,38 +1313,31 @@ resource "github_repository" "test" { } `, testRepoName) - checks := map[string]resource.TestCheckFunc{ - "before": resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "github_repository.test", "vulnerability_alerts", - "false", - ), - ), - "after": resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "github_repository.test", "vulnerability_alerts", - "true", - ), - resource.TestCheckResourceAttr( - "github_repository.test", "visibility", - "private", - ), - ), - } - resource.Test(t, resource.TestCase{ - PreCheck: func() { skipUnlessMode(t, enterprise) }, + PreCheck: func() { + skipUnlessEnterprise(t) + }, ProviderFactories: providerFactories, Steps: []resource.TestStep{ { Config: config, - Check: checks["before"], + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "github_repository.test", "visibility", + "private", + ), + ), }, { Config: strings.Replace(config, - `}`, - "vulnerability_alerts = true\n}", 1), - Check: checks["after"], + `visibility = "private"`, + `visibility = "internal"`, 1), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "github_repository.test", "visibility", + "internal", + ), + ), }, }, }) diff --git a/website/docs/r/repository.html.markdown b/website/docs/r/repository.html.markdown index 92c67745de..ff54e750aa 100644 --- a/website/docs/r/repository.html.markdown +++ b/website/docs/r/repository.html.markdown @@ -63,183 +63,183 @@ resource "github_repository" "forked_repo" { The following arguments are supported: -* `name` - (Required) The name of the repository. +- `name` - (Required) The name of the repository. -* `description` - (Optional) A description of the repository. +- `description` - (Optional) A description of the repository. -* `homepage_url` - (Optional) URL of a page describing the project. +- `homepage_url` - (Optional) URL of a page describing the project. -* `fork` - (Optional) Set to `true` to create a fork of an existing repository. When set to `true`, both `source_owner` and `source_repo` must also be specified. +- `fork` - (Optional) Set to `true` to create a fork of an existing repository. When set to `true`, both `source_owner` and `source_repo` must also be specified. -* `source_owner` - (Optional) The GitHub username or organization that owns the repository being forked. Required when `fork` is `true`. +- `source_owner` - (Optional) The GitHub username or organization that owns the repository being forked. Required when `fork` is `true`. -* `source_repo` - (Optional) The name of the repository to fork. Required when `fork` is `true`. +- `source_repo` - (Optional) The name of the repository to fork. Required when `fork` is `true`. -* `private` - (Optional) Set to `true` to create a private repository. +- `private` - (Optional) Set to `true` to create a private repository. Repositories are created as public (e.g. open source) by default. -* `visibility` - (Optional) Can be `public` or `private`. If your organization is associated with an enterprise account using GitHub Enterprise Cloud or GitHub Enterprise Server 2.20+, visibility can also be `internal`. The `visibility` parameter overrides the `private` parameter. +- `visibility` - (Optional) Can be `public` or `private`. If your organization is associated with an enterprise account using GitHub Enterprise Cloud or GitHub Enterprise Server 2.20+, visibility can also be `internal`. The `visibility` parameter overrides the `private` parameter. -* `has_issues` - (Optional) Set to `true` to enable the GitHub Issues features +- `has_issues` - (Optional) Set to `true` to enable the GitHub Issues features on the repository. -* `has_discussions` - (Optional) Set to `true` to enable GitHub Discussions on the repository. Defaults to `false`. +- `has_discussions` - (Optional) Set to `true` to enable GitHub Discussions on the repository. Defaults to `false`. -* `has_projects` - (Optional) Set to `true` to enable the GitHub Projects features on the repository. Per the GitHub [documentation](https://developer.github.com/v3/repos/#create) when in an organization that has disabled repository projects it will default to `false` and will otherwise default to `true`. If you specify `true` when it has been disabled it will return an error. +- `has_projects` - (Optional) Set to `true` to enable the GitHub Projects features on the repository. Per the GitHub [documentation](https://developer.github.com/v3/repos/#create) when in an organization that has disabled repository projects it will default to `false` and will otherwise default to `true`. If you specify `true` when it has been disabled it will return an error. -* `has_wiki` - (Optional) Set to `true` to enable the GitHub Wiki features on +- `has_wiki` - (Optional) Set to `true` to enable the GitHub Wiki features on the repository. -* `is_template` - (Optional) Set to `true` to tell GitHub that this is a template repository. +- `is_template` - (Optional) Set to `true` to tell GitHub that this is a template repository. -* `allow_merge_commit` - (Optional) Set to `false` to disable merge commits on the repository. +- `allow_merge_commit` - (Optional) Set to `false` to disable merge commits on the repository. -* `allow_squash_merge` - (Optional) Set to `false` to disable squash merges on the repository. +- `allow_squash_merge` - (Optional) Set to `false` to disable squash merges on the repository. -* `allow_rebase_merge` - (Optional) Set to `false` to disable rebase merges on the repository. +- `allow_rebase_merge` - (Optional) Set to `false` to disable rebase merges on the repository. -* `allow_auto_merge` - (Optional) Set to `true` to allow auto-merging pull requests on the repository. +- `allow_auto_merge` - (Optional) Set to `true` to allow auto-merging pull requests on the repository. -* `allow_forking` - (Optional) Set to `true` to allow private forking on the repository; this is only relevant if the repository is owned by an organization and is private or internal. +- `allow_forking` - (Optional) Set to `true` to allow private forking on the repository; this is only relevant if the repository is owned by an organization and is private or internal. -* `squash_merge_commit_title` - (Optional) Can be `PR_TITLE` or `COMMIT_OR_PR_TITLE` for a default squash merge commit title. Applicable only if `allow_squash_merge` is `true`. +- `squash_merge_commit_title` - (Optional) Can be `PR_TITLE` or `COMMIT_OR_PR_TITLE` for a default squash merge commit title. Applicable only if `allow_squash_merge` is `true`. -* `squash_merge_commit_message` - (Optional) Can be `PR_BODY`, `COMMIT_MESSAGES`, or `BLANK` for a default squash merge commit message. Applicable only if `allow_squash_merge` is `true`. +- `squash_merge_commit_message` - (Optional) Can be `PR_BODY`, `COMMIT_MESSAGES`, or `BLANK` for a default squash merge commit message. Applicable only if `allow_squash_merge` is `true`. -* `merge_commit_title` - Can be `PR_TITLE` or `MERGE_MESSAGE` for a default merge commit title. Applicable only if `allow_merge_commit` is `true`. +- `merge_commit_title` - Can be `PR_TITLE` or `MERGE_MESSAGE` for a default merge commit title. Applicable only if `allow_merge_commit` is `true`. -* `merge_commit_message` - Can be `PR_BODY`, `PR_TITLE`, or `BLANK` for a default merge commit message. Applicable only if `allow_merge_commit` is `true`. +- `merge_commit_message` - Can be `PR_BODY`, `PR_TITLE`, or `BLANK` for a default merge commit message. Applicable only if `allow_merge_commit` is `true`. -* `delete_branch_on_merge` - (Optional) Automatically delete head branch after a pull request is merged. Defaults to `false`. +- `delete_branch_on_merge` - (Optional) Automatically delete head branch after a pull request is merged. Defaults to `false`. -* `web_commit_signoff_required` - (Optional) Require contributors to sign off on web-based commits. See more [here](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/managing-repository-settings/managing-the-commit-signoff-policy-for-your-repository). Defaults to `false`. +- `web_commit_signoff_required` - (Optional) Require contributors to sign off on web-based commits. See more [here](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/managing-repository-settings/managing-the-commit-signoff-policy-for-your-repository). Defaults to `false`. -* `has_downloads` - (**DEPRECATED**) (Optional) Set to `true` to enable the (deprecated) downloads features on the repository. This attribute is no longer in use, but it hasn't been removed yet. It will be removed in a future version. See [this discussion](https://github.com/orgs/community/discussions/102145#discussioncomment-8351756). +- `has_downloads` - (**DEPRECATED**) (Optional) Set to `true` to enable the (deprecated) downloads features on the repository. This attribute is no longer in use, but it hasn't been removed yet. It will be removed in a future version. See [this discussion](https://github.com/orgs/community/discussions/102145#discussioncomment-8351756). -* `auto_init` - (Optional) Set to `true` to produce an initial commit in the repository. +- `auto_init` - (Optional) Set to `true` to produce an initial commit in the repository. -* `gitignore_template` - (Optional) Use the [name of the template](https://github.com/github/gitignore) without the extension. For example, "Haskell". +- `gitignore_template` - (Optional) Use the [name of the template](https://github.com/github/gitignore) without the extension. For example, "Haskell". -* `license_template` - (Optional) Use the [name of the template](https://github.com/github/choosealicense.com/tree/gh-pages/_licenses) without the extension. For example, "mit" or "mpl-2.0". +- `license_template` - (Optional) Use the [name of the template](https://github.com/github/choosealicense.com/tree/gh-pages/_licenses) without the extension. For example, "mit" or "mpl-2.0". -* `default_branch` - (Optional) (Deprecated: Use `github_branch_default` resource instead) The name of the default branch of the repository. **NOTE:** This can only be set after a repository has already been created, +- `default_branch` - (Optional) (Deprecated: Use `github_branch_default` resource instead) The name of the default branch of the repository. **NOTE:** This can only be set after a repository has already been created, and after a correct reference has been created for the target branch inside the repository. This means a user will have to omit this parameter from the initial repository creation and create the target branch inside of the repository prior to setting this attribute. -* `archived` - (Optional) Specifies if the repository should be archived. Defaults to `false`. **NOTE** Currently, the API does not support unarchiving. +- `archived` - (Optional) Specifies if the repository should be archived. Defaults to `false`. Unarchiving is supported by setting this back to 'false'. -* `archive_on_destroy` - (Optional) Set to `true` to archive the repository instead of deleting on destroy. +- `archive_on_destroy` - (Optional) Set to `true` to archive the repository instead of deleting on destroy. -* `pages` - (Optional) The repository's GitHub Pages configuration. See [GitHub Pages Configuration](#github-pages-configuration) below for details. +- `pages` - (Optional) The repository's GitHub Pages configuration. See [GitHub Pages Configuration](#github-pages-configuration) below for details. -* `security_and_analysis` - (Optional) The repository's [security and analysis](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-security-and-analysis-settings-for-your-repository) configuration. See [Security and Analysis Configuration](#security-and-analysis-configuration) below for details. +- `security_and_analysis` - (Optional) The repository's [security and analysis](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-security-and-analysis-settings-for-your-repository) configuration. See [Security and Analysis Configuration](#security-and-analysis-configuration) below for details. -* `topics` - (Optional) The list of topics of the repository. +- `topics` - (Optional) The list of topics of the repository. ~> Note: This attribute is not compatible with the `github_repository_topics` resource. Use one of them. `github_repository_topics` is only meant to be used if the repository itself is not handled via terraform, for example if it's only read as a datasource (see [issue #1845](https://github.com/integrations/terraform-provider-github/issues/1845)). -* `template` - (Optional) Use a template repository to create this resource. See [Template Repositories](#template-repositories) below for details. +- `template` - (Optional) Use a template repository to create this resource. See [Template Repositories](#template-repositories) below for details. -* `vulnerability_alerts` (Optional) - Set to `true` to enable security alerts for vulnerable dependencies. Enabling requires alerts to be enabled on the owner level. (Note for importing: GitHub enables the alerts on public repos but disables them on private repos by default.) See [GitHub Documentation](https://help.github.com/en/github/managing-security-vulnerabilities/about-security-alerts-for-vulnerable-dependencies) for details. Note that vulnerability alerts have not been successfully tested on any GitHub Enterprise instance and may be unavailable in those settings. +- `vulnerability_alerts` (Optional) - Set to `true` to enable security alerts for vulnerable dependencies. Enabling requires alerts to be enabled on the owner level. (Note for importing: GitHub enables the alerts on public repos but disables them on private repos by default.) See [GitHub Documentation](https://help.github.com/en/github/managing-security-vulnerabilities/about-security-alerts-for-vulnerable-dependencies) for details. Note that vulnerability alerts have not been successfully tested on any GitHub Enterprise instance and may be unavailable in those settings. -* `ignore_vulnerability_alerts_during_read` (Optional) - Set to `true` to not call the vulnerability alerts endpoint so the resource can also be used without admin permissions during read. +- `ignore_vulnerability_alerts_during_read` (Optional) - Set to `true` to not call the vulnerability alerts endpoint so the resource can also be used without admin permissions during read. -* `allow_update_branch` (Optional) - Set to `true` to always suggest updating pull request branches. +- `allow_update_branch` (Optional) - Set to `true` to always suggest updating pull request branches. ### GitHub Pages Configuration The `pages` block supports the following: -* `source` - (Optional) The source branch and directory for the rendered Pages site. See [GitHub Pages Source](#github-pages-source) below for details. +- `source` - (Optional) The source branch and directory for the rendered Pages site. See [GitHub Pages Source](#github-pages-source) below for details. -* `build_type` - (Optional) The type of GitHub Pages site to build. Can be `legacy` or `workflow`. If you use `legacy` as build type you need to set the option `source`. +- `build_type` - (Optional) The type of GitHub Pages site to build. Can be `legacy` or `workflow`. If you use `legacy` as build type you need to set the option `source`. -* `cname` - (Optional) The custom domain for the repository. This can only be set after the repository has been created. +- `cname` - (Optional) The custom domain for the repository. This can only be set after the repository has been created. #### GitHub Pages Source The `source` block supports the following: -* `branch` - (Required) The repository branch used to publish the site's source files. (i.e. `main` or `gh-pages`. +- `branch` - (Required) The repository branch used to publish the site's source files. (i.e. `main` or `gh-pages`. -* `path` - (Optional) The repository directory from which the site publishes (Default: `/`). +- `path` - (Optional) The repository directory from which the site publishes (Default: `/`). ### Security and Analysis Configuration The `security_and_analysis` block supports the following: -* `advanced_security` - (Optional) The advanced security configuration for the repository. See [Advanced Security Configuration](#advanced-security-configuration) below for details. If a repository's visibility is `public`, advanced security is always enabled and cannot be changed, so this setting cannot be supplied. +- `advanced_security` - (Optional) The advanced security configuration for the repository. See [Advanced Security Configuration](#advanced-security-configuration) below for details. If a repository's visibility is `public`, advanced security is always enabled and cannot be changed, so this setting cannot be supplied. -* `code_security` - (Optional) The code security configuration for the repository. See [Code Security](#code-security-configuration) below for details. +- `code_security` - (Optional) The code security configuration for the repository. See [Code Security](#code-security-configuration) below for details. -* `secret_scanning` - (Optional) The secret scanning configuration for the repository. See [Secret Scanning Configuration](#secret-scanning-configuration) below for details. +- `secret_scanning` - (Optional) The secret scanning configuration for the repository. See [Secret Scanning Configuration](#secret-scanning-configuration) below for details. -* `secret_scanning_push_protection` - (Optional) The secret scanning push protection configuration for the repository. See [Secret Scanning Push Protection Configuration](#secret-scanning-push-protection-configuration) below for details. +- `secret_scanning_push_protection` - (Optional) The secret scanning push protection configuration for the repository. See [Secret Scanning Push Protection Configuration](#secret-scanning-push-protection-configuration) below for details. -* `secret_scanning_ai_detection` - (Optional) The secret scanning ai detection configuration for the repository. See [Secret Scanning AI Detection Configuration](#secret-scanning-ai-detection-configuration) below for details. +- `secret_scanning_ai_detection` - (Optional) The secret scanning ai detection configuration for the repository. See [Secret Scanning AI Detection Configuration](#secret-scanning-ai-detection-configuration) below for details. -* `secret_scanning_non_provider_patterns` - (Optional) The secret scanning non-provider patterns configuration for this repository. See [Secret Scanning Non-Provider Patterns Configuration](#secret-scanning-non-provider-patterns-configuration) below for more details. +- `secret_scanning_non_provider_patterns` - (Optional) The secret scanning non-provider patterns configuration for this repository. See [Secret Scanning Non-Provider Patterns Configuration](#secret-scanning-non-provider-patterns-configuration) below for more details. #### Advanced Security Configuration The `advanced_security` block supports the following: -* `status` - (Required) Set to `enabled` to enable advanced security features on the repository. Can be `enabled` or `disabled`. +- `status` - (Required) Set to `enabled` to enable advanced security features on the repository. Can be `enabled` or `disabled`. #### Code Security Configuration -* `status` - (Required) Set to `enabled` to enable GitHub Code Security on the repository. Can be `enabled` or `disabled`. If set to `enabled`, the repository's visibility must be `public`, `security_and_analysis[0].advanced_security[0].status` must also be set to `enabled`, or your Organization must have split licensing for Advanced security. +- `status` - (Required) Set to `enabled` to enable GitHub Code Security on the repository. Can be `enabled` or `disabled`. If set to `enabled`, the repository's visibility must be `public`, `security_and_analysis[0].advanced_security[0].status` must also be set to `enabled`, or your Organization must have split licensing for Advanced security. #### Secret Scanning Configuration -* `status` - (Required) Set to `enabled` to enable secret scanning on the repository. Can be `enabled` or `disabled`. If set to `enabled`, the repository's visibility must be `public`, `security_and_analysis[0].advanced_security[0].status` must also be set to `enabled`, or your Organization must have split licensing for Advanced security. +- `status` - (Required) Set to `enabled` to enable secret scanning on the repository. Can be `enabled` or `disabled`. If set to `enabled`, the repository's visibility must be `public`, `security_and_analysis[0].advanced_security[0].status` must also be set to `enabled`, or your Organization must have split licensing for Advanced security. #### Secret Scanning Push Protection Configuration -* `status` - (Required) Set to `enabled` to enable secret scanning push protection on the repository. Can be `enabled` or `disabled`. If set to `enabled`, the repository's visibility must be `public`, `security_and_analysis[0].advanced_security[0].status` must also be set to `enabled`, or your Organization must have split licensing for Advanced security. +- `status` - (Required) Set to `enabled` to enable secret scanning push protection on the repository. Can be `enabled` or `disabled`. If set to `enabled`, the repository's visibility must be `public`, `security_and_analysis[0].advanced_security[0].status` must also be set to `enabled`, or your Organization must have split licensing for Advanced security. #### Secret Scanning AI Detection -* `status` - (Required) Set to `enabled` to enable secret scanning AI detection on the repository. Can be `enabled` or `disabled`. If set to `enabled`, the repository's visibility must be `public`, `security_and_analysis[0].advanced_security[0].status` must also be set to `enabled`, or your Organization must have split licensing for Advanced security. +- `status` - (Required) Set to `enabled` to enable secret scanning AI detection on the repository. Can be `enabled` or `disabled`. If set to `enabled`, the repository's visibility must be `public`, `security_and_analysis[0].advanced_security[0].status` must also be set to `enabled`, or your Organization must have split licensing for Advanced security. #### Secret Scanning Non-Provider Patterns -* `status` - (Required) Set to `enabled` to enable secret scanning non-provider patterns on the repository. Can be `enabled` or `disabled`. If set to `enabled`, the repository's visibility must be `public`, `security_and_analysis[0].advanced_security[0].status` must also be set to `enabled`, or your Organization must have split licensing for Advanced security. +- `status` - (Required) Set to `enabled` to enable secret scanning non-provider patterns on the repository. Can be `enabled` or `disabled`. If set to `enabled`, the repository's visibility must be `public`, `security_and_analysis[0].advanced_security[0].status` must also be set to `enabled`, or your Organization must have split licensing for Advanced security. ### Template Repositories `template` supports the following arguments: -* `owner`: The GitHub organization or user the template repository is owned by. -* `repository`: The name of the template repository. -* `include_all_branches`: Whether the new repository should include all the branches from the template repository (defaults to false, which includes only the default branch from the template). +- `owner`: The GitHub organization or user the template repository is owned by. +- `repository`: The name of the template repository. +- `include_all_branches`: Whether the new repository should include all the branches from the template repository (defaults to false, which includes only the default branch from the template). ## Attributes Reference The following additional attributes are exported: -* `full_name` - A string of the form "orgname/reponame". +- `full_name` - A string of the form "orgname/reponame". -* `html_url` - URL to the repository on the web. +- `html_url` - URL to the repository on the web. -* `ssh_clone_url` - URL that can be provided to `git clone` to clone the repository via SSH. +- `ssh_clone_url` - URL that can be provided to `git clone` to clone the repository via SSH. -* `http_clone_url` - URL that can be provided to `git clone` to clone the repository via HTTPS. +- `http_clone_url` - URL that can be provided to `git clone` to clone the repository via HTTPS. -* `git_clone_url` - URL that can be provided to `git clone` to clone the repository anonymously via the git protocol. +- `git_clone_url` - URL that can be provided to `git clone` to clone the repository anonymously via the git protocol. -* `svn_url` - URL that can be provided to `svn checkout` to check out the repository via GitHub's Subversion protocol emulation. +- `svn_url` - URL that can be provided to `svn checkout` to check out the repository via GitHub's Subversion protocol emulation. -* `node_id` - GraphQL global node id for use with v4 API +- `node_id` - GraphQL global node id for use with v4 API -* `repo_id` - GitHub ID for the repository +- `repo_id` - GitHub ID for the repository -* `primary_language` - The primary language used in the repository. +- `primary_language` - The primary language used in the repository. -* `pages` - The block consisting of the repository's GitHub Pages configuration with the following additional attributes: -* `custom_404` - Whether the rendered GitHub Pages site has a custom 404 page. -* `html_url` - The absolute URL (including scheme) of the rendered GitHub Pages site e.g. `https://username.github.io`. -* `status` - The GitHub Pages site's build status e.g. `building` or `built`. +- `pages` - The block consisting of the repository's GitHub Pages configuration with the following additional attributes: +- `custom_404` - Whether the rendered GitHub Pages site has a custom 404 page. +- `html_url` - The absolute URL (including scheme) of the rendered GitHub Pages site e.g. `https://username.github.io`. +- `status` - The GitHub Pages site's build status e.g. `building` or `built`. ## Import