From 02c785464a7deb5ac2c4d826b0989e997781f4be Mon Sep 17 00:00:00 2001 From: hminaee-tc Date: Thu, 10 Apr 2025 11:25:47 -0300 Subject: [PATCH 01/12] feat/forking-repository --- github/resource_github_repository.go | 213 +++++++++++++++------- github/resource_github_repository_test.go | 152 +++++++++++++++ 2 files changed, 300 insertions(+), 65 deletions(-) diff --git a/github/resource_github_repository.go b/github/resource_github_repository.go index f28cc4c6e8..3f990fd6a1 100644 --- a/github/resource_github_repository.go +++ b/github/resource_github_repository.go @@ -1,17 +1,17 @@ + package github import ( - "context" - "errors" - "fmt" - "log" - "net/http" - "regexp" - "strings" - - "github.com/google/go-github/v66/github" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "context" + "errors" + "fmt" + "log" + "net/http" + "regexp" + "strings" + "github.com/google/go-github/v66/github" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) func resourceGithubRepository() *schema.Resource { @@ -63,6 +63,21 @@ func resourceGithubRepository() *schema.Resource { ValidateDiagFunc: toDiagFunc(validation.StringInSlice([]string{"public", "private", "internal"}, false), "visibility"), Description: "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'.", }, + "fork": { + Type: schema.TypeBool, + Optional: true, + Description: "Set to 'true' to fork an existing repository.", + }, + "source_owner": { + Type: schema.TypeString, + Optional: true, + Description: "The owner of the source repository to fork from.", + }, + "source_repo": { + Type: schema.TypeString, + Optional: true, + Description: "The name of the source repository to fork from.", + }, "security_and_analysis": { Type: schema.TypeList, Optional: true, @@ -526,9 +541,8 @@ func resourceGithubRepositoryObject(d *schema.ResourceData) *github.Repository { func resourceGithubRepositoryCreate(d *schema.ResourceData, meta interface{}) error { client := meta.(*Owner).v3client - if branchName, hasDefaultBranch := d.GetOk("default_branch"); hasDefaultBranch && (branchName != "main") { - return fmt.Errorf("cannot set the default branch on a new repository to something other than 'main'") + return fmt.Errorf("cannot set the default branch on a new repository to something other than 'main'") } repoReq := resourceGithubRepositoryObject(d) @@ -543,80 +557,134 @@ func resourceGithubRepositoryCreate(d *schema.ResourceData, meta interface{}) er // prefer visibility to private flag since private flag is deprecated privateKeyword, ok := d.Get("private").(bool) if ok { - isPrivate = privateKeyword + isPrivate = privateKeyword } visibility, ok := d.Get("visibility").(string) if ok { - if visibility == "private" || visibility == "internal" { - isPrivate = true - } + if visibility == "private" || visibility == "internal" { + isPrivate = true + } } repoReq.Private = github.Bool(isPrivate) if template, ok := d.GetOk("template"); ok { - templateConfigBlocks := template.([]interface{}) - - for _, templateConfigBlock := range templateConfigBlocks { - templateConfigMap, ok := templateConfigBlock.(map[string]interface{}) - if !ok { - return errors.New("failed to unpack template configuration block") + templateConfigBlocks := template.([]interface{}) + + for _, templateConfigBlock := range templateConfigBlocks { + templateConfigMap, ok := templateConfigBlock.(map[string]interface{}) + if !ok { + return errors.New("failed to unpack template configuration block") + } + + templateRepo := templateConfigMap["repository"].(string) + templateRepoOwner := templateConfigMap["owner"].(string) + includeAllBranches := templateConfigMap["include_all_branches"].(bool) + + templateRepoReq := github.TemplateRepoRequest{ + Name: &repoName, + Owner: &owner, + Description: github.String(d.Get("description").(string)), + Private: github.Bool(isPrivate), + IncludeAllBranches: github.Bool(includeAllBranches), + } + + repo, _, err := client.Repositories.CreateFromTemplate(ctx, + templateRepoOwner, + templateRepo, + &templateRepoReq, + ) + if err != nil { + return err + } + + d.SetId(*repo.Name) + } + } else if d.Get("fork").(bool) { + // Handle repository forking + sourceOwner := d.Get("source_owner").(string) + sourceRepo := d.Get("source_repo").(string) + requestedName := d.Get("name").(string) + owner := meta.(*Owner).name + log.Printf("[INFO] Creating fork of %s/%s in %s", sourceOwner, sourceRepo, owner) + + if sourceOwner == "" || sourceRepo == "" { + return fmt.Errorf("source_owner and source_repo must be provided when forking a repository") } - - templateRepo := templateConfigMap["repository"].(string) - templateRepoOwner := templateConfigMap["owner"].(string) - includeAllBranches := templateConfigMap["include_all_branches"].(bool) - - templateRepoReq := github.TemplateRepoRequest{ - Name: &repoName, - Owner: &owner, - Description: github.String(d.Get("description").(string)), - Private: github.Bool(isPrivate), - IncludeAllBranches: github.Bool(includeAllBranches), + + // Create the fork using the GitHub client library + opts := &github.RepositoryCreateForkOptions{ + Name: requestedName, } - - repo, _, err := client.Repositories.CreateFromTemplate(ctx, - templateRepoOwner, - templateRepo, - &templateRepoReq, - ) + + if meta.(*Owner).IsOrganization { + opts.Organization = owner + } + + fork, resp, err := client.Repositories.CreateFork(ctx, sourceOwner, sourceRepo, opts) + if err != nil { - return err + // Handle accepted error (202) which means the fork is being created asynchronously + if _, ok := err.(*github.AcceptedError); ok { + log.Printf("[INFO] Fork is being created asynchronously") + + // The fork information is still returned despite the 202 status + if fork == nil { + return fmt.Errorf("fork information not available after accepted status") + } + log.Printf("[DEBUG] Fork name: %s", fork.GetName()) + } else { + return fmt.Errorf("failed to create fork: %v", err) + } + } else if resp != nil { + log.Printf("[DEBUG] Fork response status: %d", resp.StatusCode) + } + + if fork == nil { + return fmt.Errorf("fork creation failed - no repository returned") } - - d.SetId(*repo.Name) - } + + log.Printf("[INFO] Fork created with name: %s", fork.GetName()) + d.SetId(fork.GetName()) + log.Printf("[DEBUG] Set resource ID to just the name: %s", d.Id()) + + d.Set("name", fork.GetName()) + d.Set("full_name", fork.GetFullName()) // Add the full name for reference + d.Set("html_url", fork.GetHTMLURL()) + d.Set("ssh_clone_url", fork.GetSSHURL()) + d.Set("git_clone_url", fork.GetGitURL()) + d.Set("http_clone_url", fork.GetCloneURL()) } else { - // Create without a repository template - var repo *github.Repository - var err error - if meta.(*Owner).IsOrganization { - repo, _, err = client.Repositories.Create(ctx, owner, repoReq) - } else { - // Create repository within authenticated user's account - repo, _, err = client.Repositories.Create(ctx, "", repoReq) - } - if err != nil { - return err - } - d.SetId(repo.GetName()) + // Create without a repository template + var repo *github.Repository + var err error + if meta.(*Owner).IsOrganization { + repo, _, err = client.Repositories.Create(ctx, owner, repoReq) + } else { + // Create repository within authenticated user's account + repo, _, err = client.Repositories.Create(ctx, "", repoReq) + } + if err != nil { + return err + } + d.SetId(repo.GetName()) } topics := repoReq.Topics if len(topics) > 0 { - _, _, err := client.Repositories.ReplaceAllTopics(ctx, owner, repoName, topics) - if err != nil { - return err - } + _, _, err := client.Repositories.ReplaceAllTopics(ctx, owner, repoName, topics) + if err != nil { + return err + } } pages := expandPages(d.Get("pages").([]interface{})) if pages != nil { - _, _, err := client.Repositories.EnablePages(ctx, owner, repoName, pages) - if err != nil { - return err - } + _, _, err := client.Repositories.EnablePages(ctx, owner, repoName, pages) + if err != nil { + return err + } } return resourceGithubRepositoryUpdate(d, meta) @@ -705,6 +773,21 @@ func resourceGithubRepositoryRead(d *schema.ResourceData, meta interface{}) erro } } + // Set fork information if this is a fork + if repo.GetFork() { + d.Set("fork", true) + + // If the repository has parent information, set the source details + if repo.Parent != nil { + d.Set("source_owner", repo.Parent.GetOwner().GetLogin()) + d.Set("source_repo", repo.Parent.GetName()) + } + } else { + d.Set("fork", false) + d.Set("source_owner", "") + d.Set("source_repo", "") + } + if repo.TemplateRepository != nil { if err = d.Set("template", []interface{}{ map[string]interface{}{ diff --git a/github/resource_github_repository_test.go b/github/resource_github_repository_test.go index e09505dac9..aea4d7cb4d 100644 --- a/github/resource_github_repository_test.go +++ b/github/resource_github_repository_test.go @@ -1700,3 +1700,155 @@ func TestGithubRepositoryNameFailsValidationWithSpace(t *testing.T) { t.Error(fmt.Errorf("unexpected name validation failure; expected=%s; action=%s", expectedFailure, actualFailure)) } } + +func TestAccGithubRepository_fork(t *testing.T) { + randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum) + + t.Run("forks a repository without error", func(t *testing.T) { + config := fmt.Sprintf(` + resource "github_repository" "forked" { + name = "terraform-provider-github-%s" + description = "Terraform acceptance test - forked repository %[1]s" + fork = true + source_owner = "integrations" + source_repo = "terraform-provider-github" + } + `, randomID) + + check := resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "github_repository.forked", "fork", + "true", + ), + resource.TestCheckResourceAttrSet( + "github_repository.forked", "html_url", + ), + resource.TestCheckResourceAttrSet( + "github_repository.forked", "ssh_clone_url", + ), + resource.TestCheckResourceAttrSet( + "github_repository.forked", "git_clone_url", + ), + resource.TestCheckResourceAttrSet( + "github_repository.forked", "http_clone_url", + ), + ) + + 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 individual account", func(t *testing.T) { + testCase(t, individual) + }) + + t.Run("with an organization account", func(t *testing.T) { + testCase(t, organization) + }) + + t.Run("with an anonymous account", func(t *testing.T) { + t.Skip("anonymous account not supported for this operation") + }) + }) + + t.Run("can update forked repository properties", func(t *testing.T) { + initialConfig := fmt.Sprintf(` + resource "github_repository" "forked_update" { + name = "terraform-provider-github-update-%s" + description = "Initial description for forked repo" + fork = true + source_owner = "integrations" + source_repo = "terraform-provider-github" + has_wiki = true + has_issues = false + } + `, randomID) + + updatedConfig := fmt.Sprintf(` + resource "github_repository" "forked_update" { + name = "terraform-provider-github-update-%s" + description = "Updated description for forked repo" + fork = true + source_owner = "integrations" + source_repo = "terraform-provider-github" + has_wiki = false + has_issues = true + } + `, randomID) + + checks := map[string]resource.TestCheckFunc{ + "before": resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "github_repository.forked_update", "description", + "Initial description for forked repo", + ), + resource.TestCheckResourceAttr( + "github_repository.forked_update", "has_wiki", + "true", + ), + resource.TestCheckResourceAttr( + "github_repository.forked_update", "has_issues", + "false", + ), + ), + "after": resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "github_repository.forked_update", "description", + "Updated description for forked repo", + ), + resource.TestCheckResourceAttr( + "github_repository.forked_update", "has_wiki", + "false", + ), + resource.TestCheckResourceAttr( + "github_repository.forked_update", "has_issues", + "true", + ), + ), + } + + testCase := func(t *testing.T, mode string) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { skipUnlessMode(t, mode) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: initialConfig, + Check: checks["before"], + }, + { + Config: updatedConfig, + Check: checks["after"], + }, + { + ResourceName: "github_repository.forked_update", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ "auto_init"}, + }, + }, + }) + } + + 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) + }) + + t.Run("with an anonymous account", func(t *testing.T) { + t.Skip("anonymous account not supported for this operation") + }) + }) +} \ No newline at end of file From 2ff934d2715f08069e5163f5fe7d2ed68df32139 Mon Sep 17 00:00:00 2001 From: hminaee-tc Date: Wed, 21 May 2025 12:05:47 -0300 Subject: [PATCH 02/12] feat: forking with force renew --- github/resource_github_repository.go | 68 ++++++++++++++-------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/github/resource_github_repository.go b/github/resource_github_repository.go index 3f990fd6a1..260cefd400 100644 --- a/github/resource_github_repository.go +++ b/github/resource_github_repository.go @@ -2,16 +2,16 @@ package github import ( - "context" - "errors" - "fmt" - "log" - "net/http" - "regexp" - "strings" - "github.com/google/go-github/v66/github" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "context" + "errors" + "fmt" + "log" + "net/http" + "regexp" + "strings" + "github.com/google/go-github/v66/github" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) func resourceGithubRepository() *schema.Resource { @@ -66,16 +66,19 @@ func resourceGithubRepository() *schema.Resource { "fork": { Type: schema.TypeBool, Optional: true, + ForceNew: true, Description: "Set to 'true' to fork an existing repository.", }, "source_owner": { Type: schema.TypeString, Optional: true, + ForceNew: true, Description: "The owner of the source repository to fork from.", }, "source_repo": { Type: schema.TypeString, Optional: true, + ForceNew: true, Description: "The name of the source repository to fork from.", }, "security_and_analysis": { @@ -542,7 +545,7 @@ func resourceGithubRepositoryObject(d *schema.ResourceData) *github.Repository { func resourceGithubRepositoryCreate(d *schema.ResourceData, meta interface{}) error { client := meta.(*Owner).v3client if branchName, hasDefaultBranch := d.GetOk("default_branch"); hasDefaultBranch && (branchName != "main") { - return fmt.Errorf("cannot set the default branch on a new repository to something other than 'main'") + return fmt.Errorf("cannot set the default branch on a new repository to something other than 'main'") } repoReq := resourceGithubRepositoryObject(d) @@ -557,13 +560,13 @@ func resourceGithubRepositoryCreate(d *schema.ResourceData, meta interface{}) er // prefer visibility to private flag since private flag is deprecated privateKeyword, ok := d.Get("private").(bool) if ok { - isPrivate = privateKeyword + isPrivate = privateKeyword } visibility, ok := d.Get("visibility").(string) if ok { if visibility == "private" || visibility == "internal" { - isPrivate = true + isPrivate = true } } @@ -615,7 +618,7 @@ func resourceGithubRepositoryCreate(d *schema.ResourceData, meta interface{}) er // Create the fork using the GitHub client library opts := &github.RepositoryCreateForkOptions{ - Name: requestedName, + Name: requestedName, } if meta.(*Owner).IsOrganization { @@ -628,8 +631,7 @@ func resourceGithubRepositoryCreate(d *schema.ResourceData, meta interface{}) er // Handle accepted error (202) which means the fork is being created asynchronously if _, ok := err.(*github.AcceptedError); ok { log.Printf("[INFO] Fork is being created asynchronously") - - // The fork information is still returned despite the 202 status + // Despite the 202 status, the API should still return preliminary fork information if fork == nil { return fmt.Errorf("fork information not available after accepted status") } @@ -637,9 +639,9 @@ func resourceGithubRepositoryCreate(d *schema.ResourceData, meta interface{}) er } else { return fmt.Errorf("failed to create fork: %v", err) } - } else if resp != nil { + } else if resp != nil { log.Printf("[DEBUG] Fork response status: %d", resp.StatusCode) - } + } if fork == nil { return fmt.Errorf("fork creation failed - no repository returned") @@ -657,18 +659,18 @@ func resourceGithubRepositoryCreate(d *schema.ResourceData, meta interface{}) er d.Set("http_clone_url", fork.GetCloneURL()) } else { // Create without a repository template - var repo *github.Repository - var err error - if meta.(*Owner).IsOrganization { - repo, _, err = client.Repositories.Create(ctx, owner, repoReq) - } else { - // Create repository within authenticated user's account - repo, _, err = client.Repositories.Create(ctx, "", repoReq) - } - if err != nil { - return err - } - d.SetId(repo.GetName()) + var repo *github.Repository + var err error + if meta.(*Owner).IsOrganization { + repo, _, err = client.Repositories.Create(ctx, owner, repoReq) + } else { + // Create repository within authenticated user's account + repo, _, err = client.Repositories.Create(ctx, "", repoReq) + } + if err != nil { + return err + } + d.SetId(repo.GetName()) } topics := repoReq.Topics @@ -681,9 +683,9 @@ func resourceGithubRepositoryCreate(d *schema.ResourceData, meta interface{}) er pages := expandPages(d.Get("pages").([]interface{})) if pages != nil { - _, _, err := client.Repositories.EnablePages(ctx, owner, repoName, pages) - if err != nil { - return err + _, _, err := client.Repositories.EnablePages(ctx, owner, repoName, pages) + if err != nil { + return err } } From 32dd2b6b1e6c2b6cacafaa6d90792287fdd4f10a Mon Sep 17 00:00:00 2001 From: hminaee-tc Date: Wed, 21 May 2025 20:27:51 -0300 Subject: [PATCH 03/12] fix: formatting --- github/resource_github_repository.go | 34 ++++++++++++++-------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/github/resource_github_repository.go b/github/resource_github_repository.go index 260cefd400..e27615fda7 100644 --- a/github/resource_github_repository.go +++ b/github/resource_github_repository.go @@ -2,16 +2,16 @@ package github import ( - "context" - "errors" - "fmt" - "log" - "net/http" - "regexp" - "strings" - "github.com/google/go-github/v66/github" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "context" + "errors" + "fmt" + "log" + "net/http" + "regexp" + "strings" + "github.com/google/go-github/v66/github" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) func resourceGithubRepository() *schema.Resource { @@ -565,9 +565,9 @@ func resourceGithubRepositoryCreate(d *schema.ResourceData, meta interface{}) er visibility, ok := d.Get("visibility").(string) if ok { - if visibility == "private" || visibility == "internal" { + if visibility == "private" || visibility == "internal" { isPrivate = true - } + } } repoReq.Private = github.Bool(isPrivate) @@ -658,7 +658,7 @@ func resourceGithubRepositoryCreate(d *schema.ResourceData, meta interface{}) er d.Set("git_clone_url", fork.GetGitURL()) d.Set("http_clone_url", fork.GetCloneURL()) } else { - // Create without a repository template + // Create without a repository template var repo *github.Repository var err error if meta.(*Owner).IsOrganization { @@ -675,10 +675,10 @@ func resourceGithubRepositoryCreate(d *schema.ResourceData, meta interface{}) er topics := repoReq.Topics if len(topics) > 0 { - _, _, err := client.Repositories.ReplaceAllTopics(ctx, owner, repoName, topics) - if err != nil { - return err - } + _, _, err := client.Repositories.ReplaceAllTopics(ctx, owner, repoName, topics) + if err != nil { + return err + } } pages := expandPages(d.Get("pages").([]interface{})) From f38bd079a9743c94cb54be5395089c5d1a74559b Mon Sep 17 00:00:00 2001 From: hminaee-tc Date: Wed, 21 May 2025 20:28:22 -0300 Subject: [PATCH 04/12] fix: formatting --- github/resource_github_repository.go | 1 + 1 file changed, 1 insertion(+) diff --git a/github/resource_github_repository.go b/github/resource_github_repository.go index e27615fda7..8882fb01f6 100644 --- a/github/resource_github_repository.go +++ b/github/resource_github_repository.go @@ -9,6 +9,7 @@ import ( "net/http" "regexp" "strings" + "github.com/google/go-github/v66/github" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" From e66319adde25396dfc9417dd0ac9238c209ff53c Mon Sep 17 00:00:00 2001 From: hminaee-tc Date: Wed, 21 May 2025 20:28:48 -0300 Subject: [PATCH 05/12] fix: formatting --- github/resource_github_repository.go | 1 - 1 file changed, 1 deletion(-) diff --git a/github/resource_github_repository.go b/github/resource_github_repository.go index 8882fb01f6..e27615fda7 100644 --- a/github/resource_github_repository.go +++ b/github/resource_github_repository.go @@ -9,7 +9,6 @@ import ( "net/http" "regexp" "strings" - "github.com/google/go-github/v66/github" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" From 5261c09636566928b429e700965e2b97e3520740 Mon Sep 17 00:00:00 2001 From: hminaee-tc Date: Wed, 21 May 2025 20:29:11 -0300 Subject: [PATCH 06/12] fix: formatting --- github/resource_github_repository.go | 1 - 1 file changed, 1 deletion(-) diff --git a/github/resource_github_repository.go b/github/resource_github_repository.go index e27615fda7..74242153d2 100644 --- a/github/resource_github_repository.go +++ b/github/resource_github_repository.go @@ -1,4 +1,3 @@ - package github import ( From 24c57d9e2bfd495c62facc2a1768e9979cdd7f30 Mon Sep 17 00:00:00 2001 From: hminaee-tc Date: Wed, 21 May 2025 20:29:34 -0300 Subject: [PATCH 07/12] fix: formatting --- github/resource_github_repository.go | 1 + 1 file changed, 1 insertion(+) diff --git a/github/resource_github_repository.go b/github/resource_github_repository.go index 74242153d2..0b35cfb85e 100644 --- a/github/resource_github_repository.go +++ b/github/resource_github_repository.go @@ -8,6 +8,7 @@ import ( "net/http" "regexp" "strings" + "github.com/google/go-github/v66/github" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" From 9f80bd780b481e07c04ea76479d803fac26a541d Mon Sep 17 00:00:00 2001 From: hminaee-tc Date: Wed, 21 May 2025 20:30:25 -0300 Subject: [PATCH 08/12] fix: formatting --- github/resource_github_repository.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/github/resource_github_repository.go b/github/resource_github_repository.go index 0b35cfb85e..819e324419 100644 --- a/github/resource_github_repository.go +++ b/github/resource_github_repository.go @@ -8,7 +8,6 @@ import ( "net/http" "regexp" "strings" - "github.com/google/go-github/v66/github" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -544,6 +543,7 @@ func resourceGithubRepositoryObject(d *schema.ResourceData) *github.Repository { func resourceGithubRepositoryCreate(d *schema.ResourceData, meta interface{}) error { client := meta.(*Owner).v3client + if branchName, hasDefaultBranch := d.GetOk("default_branch"); hasDefaultBranch && (branchName != "main") { return fmt.Errorf("cannot set the default branch on a new repository to something other than 'main'") } From a7e35fdfd2a91e567185536bea0b679f893eea46 Mon Sep 17 00:00:00 2001 From: hminaee-tc Date: Wed, 21 May 2025 20:31:18 -0300 Subject: [PATCH 09/12] fix: formatting --- github/resource_github_repository.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/github/resource_github_repository.go b/github/resource_github_repository.go index 819e324419..9e980169f6 100644 --- a/github/resource_github_repository.go +++ b/github/resource_github_repository.go @@ -543,7 +543,7 @@ func resourceGithubRepositoryObject(d *schema.ResourceData) *github.Repository { func resourceGithubRepositoryCreate(d *schema.ResourceData, meta interface{}) error { client := meta.(*Owner).v3client - + if branchName, hasDefaultBranch := d.GetOk("default_branch"); hasDefaultBranch && (branchName != "main") { return fmt.Errorf("cannot set the default branch on a new repository to something other than 'main'") } @@ -686,7 +686,7 @@ func resourceGithubRepositoryCreate(d *schema.ResourceData, meta interface{}) er _, _, err := client.Repositories.EnablePages(ctx, owner, repoName, pages) if err != nil { return err - } + } } return resourceGithubRepositoryUpdate(d, meta) From 6e44b9e5364da3d54a72587566d19741717e433e Mon Sep 17 00:00:00 2001 From: hminaee-tc Date: Wed, 21 May 2025 20:34:03 -0300 Subject: [PATCH 10/12] fix: formatting --- github/resource_github_repository.go | 1 + 1 file changed, 1 insertion(+) diff --git a/github/resource_github_repository.go b/github/resource_github_repository.go index 9e980169f6..6af9b173d7 100644 --- a/github/resource_github_repository.go +++ b/github/resource_github_repository.go @@ -8,6 +8,7 @@ import ( "net/http" "regexp" "strings" + "github.com/google/go-github/v66/github" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" From 594af5cb8e94e41475726689b8d80c28560b751d Mon Sep 17 00:00:00 2001 From: hminaee-tc Date: Thu, 29 May 2025 12:34:59 -0300 Subject: [PATCH 11/12] feat/IDP-30: add documentation --- website/docs/r/repository.html.markdown | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/website/docs/r/repository.html.markdown b/website/docs/r/repository.html.markdown index dc18add1d6..e091a64479 100644 --- a/website/docs/r/repository.html.markdown +++ b/website/docs/r/repository.html.markdown @@ -47,6 +47,18 @@ resource "github_repository" "example" { } ``` +## Example Usage with Repository Forking + +```hcl +resource "github_repository" "forked_repo" { + name = "forked-repository" + description = "This is a fork of another repository" + fork = true + source_owner = "some-org" + source_repo = "original-repository" +} +``` + ## Argument Reference The following arguments are supported: @@ -57,6 +69,12 @@ The following arguments are supported: * `homepage_url` - (Optional) URL of a page describing the project. +* `fork` - (Optional) Set to `true` to create a fork of another repository. When set to `true`, `source_owner` and `source_repo` must be specified. + +* `source_owner` - (Optional) The owner 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. Repositories are created as public (e.g. open source) by default. From 930c0b7012b6eca9ce75fdebc9de64881bd0d544 Mon Sep 17 00:00:00 2001 From: hminaee-tc Date: Thu, 29 May 2025 15:00:22 -0300 Subject: [PATCH 12/12] feat/IDP-30: address feedback --- website/docs/r/repository.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/r/repository.html.markdown b/website/docs/r/repository.html.markdown index e091a64479..e9ec145d20 100644 --- a/website/docs/r/repository.html.markdown +++ b/website/docs/r/repository.html.markdown @@ -69,9 +69,9 @@ The following arguments are supported: * `homepage_url` - (Optional) URL of a page describing the project. -* `fork` - (Optional) Set to `true` to create a fork of another repository. When set to `true`, `source_owner` and `source_repo` must 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 owner of the repository to fork. 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`.