From f214d235d055bdf5812a1372fe934bda6d441748 Mon Sep 17 00:00:00 2001 From: Timo Sand Date: Sat, 21 Feb 2026 19:51:42 +0200 Subject: [PATCH 01/10] Refactor to use Context-aware functions Signed-off-by: Timo Sand --- github/resource_github_branch_default.go | 44 ++++++++++-------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/github/resource_github_branch_default.go b/github/resource_github_branch_default.go index a3b139cade..174b185473 100644 --- a/github/resource_github_branch_default.go +++ b/github/resource_github_branch_default.go @@ -7,15 +7,16 @@ import ( "net/http" "github.com/google/go-github/v83/github" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) func resourceGithubBranchDefault() *schema.Resource { return &schema.Resource{ - Create: resourceGithubBranchDefaultCreate, - Read: resourceGithubBranchDefaultRead, - Delete: resourceGithubBranchDefaultDelete, - Update: resourceGithubBranchDefaultUpdate, + CreateContext: resourceGithubBranchDefaultCreate, + ReadContext: resourceGithubBranchDefaultRead, + DeleteContext: resourceGithubBranchDefaultDelete, + UpdateContext: resourceGithubBranchDefaultUpdate, Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, @@ -51,24 +52,22 @@ func resourceGithubBranchDefault() *schema.Resource { } } -func resourceGithubBranchDefaultCreate(d *schema.ResourceData, meta any) error { +func resourceGithubBranchDefaultCreate(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { client := meta.(*Owner).v3client owner := meta.(*Owner).name repoName := d.Get("repository").(string) defaultBranch := d.Get("branch").(string) rename := d.Get("rename").(bool) - ctx := context.Background() - repository, _, err := client.Repositories.Get(ctx, owner, repoName) if err != nil { - return err + return diag.FromErr(err) } if *repository.DefaultBranch != defaultBranch { if rename { if _, _, err := client.Repositories.RenameBranch(ctx, owner, repoName, *repository.DefaultBranch, defaultBranch); err != nil { - return err + return diag.FromErr(err) } } else { repository := &github.Repository{ @@ -76,22 +75,21 @@ func resourceGithubBranchDefaultCreate(d *schema.ResourceData, meta any) error { } if _, _, err := client.Repositories.Edit(ctx, owner, repoName, repository); err != nil { - return err + return diag.FromErr(err) } } } d.SetId(repoName) - return resourceGithubBranchDefaultRead(d, meta) + return resourceGithubBranchDefaultRead(ctx, d, meta) } -func resourceGithubBranchDefaultRead(d *schema.ResourceData, meta any) error { +func resourceGithubBranchDefaultRead(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { client := meta.(*Owner).v3client owner := meta.(*Owner).name repoName := d.Id() - ctx := context.WithValue(context.Background(), ctxId, d.Id()) if !d.IsNewResource() { ctx = context.WithValue(ctx, ctxEtag, d.Get("etag").(string)) } @@ -110,7 +108,7 @@ func resourceGithubBranchDefaultRead(d *schema.ResourceData, meta any) error { return nil } } - return err + return diag.FromErr(err) } if repository.DefaultBranch == nil { @@ -124,7 +122,7 @@ func resourceGithubBranchDefaultRead(d *schema.ResourceData, meta any) error { return nil } -func resourceGithubBranchDefaultDelete(d *schema.ResourceData, meta any) error { +func resourceGithubBranchDefaultDelete(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { client := meta.(*Owner).v3client owner := meta.(*Owner).name repoName := d.Id() @@ -133,28 +131,24 @@ func resourceGithubBranchDefaultDelete(d *schema.ResourceData, meta any) error { DefaultBranch: nil, } - ctx := context.Background() - _, _, err := client.Repositories.Edit(ctx, owner, repoName, repository) - return err + return diag.FromErr(err) } -func resourceGithubBranchDefaultUpdate(d *schema.ResourceData, meta any) error { +func resourceGithubBranchDefaultUpdate(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { client := meta.(*Owner).v3client owner := meta.(*Owner).name repoName := d.Id() defaultBranch := d.Get("branch").(string) rename := d.Get("rename").(bool) - ctx := context.Background() - if rename { repository, _, err := client.Repositories.Get(ctx, owner, repoName) if err != nil { - return err + return diag.FromErr(err) } if _, _, err := client.Repositories.RenameBranch(ctx, owner, repoName, *repository.DefaultBranch, defaultBranch); err != nil { - return err + return diag.FromErr(err) } } else { repository := &github.Repository{ @@ -162,9 +156,9 @@ func resourceGithubBranchDefaultUpdate(d *schema.ResourceData, meta any) error { } if _, _, err := client.Repositories.Edit(ctx, owner, repoName, repository); err != nil { - return err + return diag.FromErr(err) } } - return resourceGithubBranchDefaultRead(d, meta) + return resourceGithubBranchDefaultRead(ctx, d, meta) } From c0c64adbb338edf11fda1f020a04b4af173db5fd Mon Sep 17 00:00:00 2001 From: Timo Sand Date: Sat, 21 Feb 2026 19:52:14 +0200 Subject: [PATCH 02/10] Sort CRUD functions Signed-off-by: Timo Sand --- github/resource_github_branch_default.go | 28 ++++++++++++------------ 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/github/resource_github_branch_default.go b/github/resource_github_branch_default.go index 174b185473..2397e8ebd2 100644 --- a/github/resource_github_branch_default.go +++ b/github/resource_github_branch_default.go @@ -15,8 +15,8 @@ func resourceGithubBranchDefault() *schema.Resource { return &schema.Resource{ CreateContext: resourceGithubBranchDefaultCreate, ReadContext: resourceGithubBranchDefaultRead, - DeleteContext: resourceGithubBranchDefaultDelete, UpdateContext: resourceGithubBranchDefaultUpdate, + DeleteContext: resourceGithubBranchDefaultDelete, Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, @@ -122,19 +122,6 @@ func resourceGithubBranchDefaultRead(ctx context.Context, d *schema.ResourceData return nil } -func resourceGithubBranchDefaultDelete(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { - client := meta.(*Owner).v3client - owner := meta.(*Owner).name - repoName := d.Id() - - repository := &github.Repository{ - DefaultBranch: nil, - } - - _, _, err := client.Repositories.Edit(ctx, owner, repoName, repository) - return diag.FromErr(err) -} - func resourceGithubBranchDefaultUpdate(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { client := meta.(*Owner).v3client owner := meta.(*Owner).name @@ -162,3 +149,16 @@ func resourceGithubBranchDefaultUpdate(ctx context.Context, d *schema.ResourceDa return resourceGithubBranchDefaultRead(ctx, d, meta) } + +func resourceGithubBranchDefaultDelete(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + client := meta.(*Owner).v3client + owner := meta.(*Owner).name + repoName := d.Id() + + repository := &github.Repository{ + DefaultBranch: nil, + } + + _, _, err := client.Repositories.Edit(ctx, owner, repoName, repository) + return diag.FromErr(err) +} From f3facc3d31fe9128b26fd622565ae23ee848562b Mon Sep 17 00:00:00 2001 From: Timo Sand Date: Sat, 21 Feb 2026 20:08:26 +0200 Subject: [PATCH 03/10] Updates naming and error handling Signed-off-by: Timo Sand --- github/resource_github_branch_default.go | 75 +++++++++++++++++------- 1 file changed, 55 insertions(+), 20 deletions(-) diff --git a/github/resource_github_branch_default.go b/github/resource_github_branch_default.go index 2397e8ebd2..dd535f26d0 100644 --- a/github/resource_github_branch_default.go +++ b/github/resource_github_branch_default.go @@ -19,6 +19,7 @@ func resourceGithubBranchDefault() *schema.Resource { DeleteContext: resourceGithubBranchDefaultDelete, Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, + // StateContext: resourceGithubBranchDefaultImport, }, Schema: map[string]*schema.Schema{ @@ -33,6 +34,7 @@ func resourceGithubBranchDefault() *schema.Resource { ForceNew: true, Description: "The GitHub repository.", }, + // TODO add repository_id and diffRepository to handle repository renames "rename": { Type: schema.TypeBool, Optional: true, @@ -52,9 +54,11 @@ func resourceGithubBranchDefault() *schema.Resource { } } -func resourceGithubBranchDefaultCreate(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { - client := meta.(*Owner).v3client - owner := meta.(*Owner).name +func resourceGithubBranchDefaultCreate(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics { + meta := m.(*Owner) + client := meta.v3client + owner := meta.name + repoName := d.Get("repository").(string) defaultBranch := d.Get("branch").(string) rename := d.Get("rename").(bool) @@ -64,14 +68,14 @@ func resourceGithubBranchDefaultCreate(ctx context.Context, d *schema.ResourceDa return diag.FromErr(err) } - if *repository.DefaultBranch != defaultBranch { + if repository.GetDefaultBranch() != defaultBranch { if rename { - if _, _, err := client.Repositories.RenameBranch(ctx, owner, repoName, *repository.DefaultBranch, defaultBranch); err != nil { + if _, _, err := client.Repositories.RenameBranch(ctx, owner, repoName, repository.GetDefaultBranch(), defaultBranch); err != nil { return diag.FromErr(err) } } else { repository := &github.Repository{ - DefaultBranch: &defaultBranch, + DefaultBranch: github.Ptr(defaultBranch), } if _, _, err := client.Repositories.Edit(ctx, owner, repoName, repository); err != nil { @@ -85,9 +89,12 @@ func resourceGithubBranchDefaultCreate(ctx context.Context, d *schema.ResourceDa return resourceGithubBranchDefaultRead(ctx, d, meta) } -func resourceGithubBranchDefaultRead(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { - client := meta.(*Owner).v3client - owner := meta.(*Owner).name +func resourceGithubBranchDefaultRead(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics { + meta := m.(*Owner) + client := meta.v3client + owner := meta.name + + // repoName := d.Get("repository").(string) repoName := d.Id() if !d.IsNewResource() { @@ -116,15 +123,24 @@ func resourceGithubBranchDefaultRead(ctx context.Context, d *schema.ResourceData return nil } - _ = d.Set("etag", resp.Header.Get("ETag")) - _ = d.Set("branch", *repository.DefaultBranch) - _ = d.Set("repository", *repository.Name) + if err := d.Set("etag", resp.Header.Get("ETag")); err != nil { + return diag.FromErr(err) + } + if err := d.Set("branch", repository.GetDefaultBranch()); err != nil { + return diag.FromErr(err) + } + if err := d.Set("repository", repository.GetName()); err != nil { + return diag.FromErr(err) + } return nil } -func resourceGithubBranchDefaultUpdate(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { - client := meta.(*Owner).v3client - owner := meta.(*Owner).name +func resourceGithubBranchDefaultUpdate(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics { + meta := m.(*Owner) + client := meta.v3client + owner := meta.name + + // repoName := d.Get("repository").(string) repoName := d.Id() defaultBranch := d.Get("branch").(string) rename := d.Get("rename").(bool) @@ -134,12 +150,12 @@ func resourceGithubBranchDefaultUpdate(ctx context.Context, d *schema.ResourceDa if err != nil { return diag.FromErr(err) } - if _, _, err := client.Repositories.RenameBranch(ctx, owner, repoName, *repository.DefaultBranch, defaultBranch); err != nil { + if _, _, err := client.Repositories.RenameBranch(ctx, owner, repoName, repository.GetDefaultBranch(), defaultBranch); err != nil { return diag.FromErr(err) } } else { repository := &github.Repository{ - DefaultBranch: &defaultBranch, + DefaultBranch: github.Ptr(defaultBranch), } if _, _, err := client.Repositories.Edit(ctx, owner, repoName, repository); err != nil { @@ -150,9 +166,11 @@ func resourceGithubBranchDefaultUpdate(ctx context.Context, d *schema.ResourceDa return resourceGithubBranchDefaultRead(ctx, d, meta) } -func resourceGithubBranchDefaultDelete(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { - client := meta.(*Owner).v3client - owner := meta.(*Owner).name +func resourceGithubBranchDefaultDelete(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics { + meta := m.(*Owner) + client := meta.v3client + owner := meta.name + // repoName := d.Get("repository").(string) repoName := d.Id() repository := &github.Repository{ @@ -162,3 +180,20 @@ func resourceGithubBranchDefaultDelete(ctx context.Context, d *schema.ResourceDa _, _, err := client.Repositories.Edit(ctx, owner, repoName, repository) return diag.FromErr(err) } + +// func resourceGithubBranchDefaultImport(ctx context.Context, d *schema.ResourceData, m any) ([]*schema.ResourceData, error) { +// repoName, defaultBranch, err := parseID2(d.Id()) +// if err != nil { +// return nil, err +// } + +// d.SetId(repoName) +// if err := d.Set("branch", defaultBranch); err != nil { +// return nil, err +// } +// if err := d.Set("repository", repoName); err != nil { +// return nil, err +// } + +// return []*schema.ResourceData{d}, nil +// } From b755a0a92b2d9370031fc236948a3aee2f5f04c3 Mon Sep 17 00:00:00 2001 From: Timo Sand Date: Sat, 21 Feb 2026 21:16:30 +0200 Subject: [PATCH 04/10] Adds test cases for Update and Import functionality Signed-off-by: Timo Sand --- github/resource_github_branch_default_test.go | 178 ++++++++++++++++-- 1 file changed, 158 insertions(+), 20 deletions(-) diff --git a/github/resource_github_branch_default_test.go b/github/resource_github_branch_default_test.go index 47855e32b4..a512a18485 100644 --- a/github/resource_github_branch_default_test.go +++ b/github/resource_github_branch_default_test.go @@ -4,14 +4,19 @@ import ( "fmt" "testing" + "github.com/hashicorp/terraform-plugin-testing/compare" "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" ) func TestAccGithubBranchDefault(t *testing.T) { - t.Run("creates and manages branch defaults", func(t *testing.T) { - randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum) - repoName := fmt.Sprintf("%srepo-branch-def-%s", testResourcePrefix, randomID) + t.Run("creates_as_import_without_error", func(t *testing.T) { + randomID := acctest.RandString(5) + repoName := fmt.Sprintf("%sbranch-def-%s", testResourcePrefix, randomID) config := fmt.Sprintf(` resource "github_repository" "test" { @@ -48,9 +53,9 @@ func TestAccGithubBranchDefault(t *testing.T) { }) }) - t.Run("replaces the default_branch of a repository", func(t *testing.T) { - randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum) - repoName := fmt.Sprintf("%srepo-branch-def-%s", testResourcePrefix, randomID) + t.Run("creates_default_branch_without_error", func(t *testing.T) { + randomID := acctest.RandString(5) + repoName := fmt.Sprintf("%sbranch-def-%s", testResourcePrefix, randomID) config := fmt.Sprintf(` resource "github_repository" "test" { name = "%s" @@ -69,20 +74,15 @@ func TestAccGithubBranchDefault(t *testing.T) { `, repoName) - check := resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "github_branch_default.test", "branch", - "test", - ), - ) - resource.Test(t, resource.TestCase{ PreCheck: func() { skipUnauthenticated(t) }, ProviderFactories: providerFactories, Steps: []resource.TestStep{ { Config: config, - Check: check, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("github_branch_default.test", "branch", "test"), + ), }, { Config: ` @@ -96,9 +96,9 @@ func TestAccGithubBranchDefault(t *testing.T) { }) }) - t.Run("creates and manages branch defaults even if rename is set", func(t *testing.T) { - randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum) - repoName := fmt.Sprintf("%srepo-branch-def-%s", testResourcePrefix, randomID) + t.Run("creates_as_import_with_rename_without_error", func(t *testing.T) { + randomID := acctest.RandString(5) + repoName := fmt.Sprintf("%sbranch-def-%s", testResourcePrefix, randomID) config := fmt.Sprintf(` resource "github_repository" "test" { name = "%s" @@ -135,9 +135,9 @@ func TestAccGithubBranchDefault(t *testing.T) { }) }) - t.Run("replaces the default_branch of a repository without creating a branch resource prior to", func(t *testing.T) { - randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum) - repoName := fmt.Sprintf("%srepo-branch-def-%s", testResourcePrefix, randomID) + t.Run("creates_with_rename_without_error", func(t *testing.T) { + randomID := acctest.RandString(5) + repoName := fmt.Sprintf("%sbranch-def-%s", testResourcePrefix, randomID) config := fmt.Sprintf(` resource "github_repository" "test" { name = "%s" @@ -162,4 +162,142 @@ func TestAccGithubBranchDefault(t *testing.T) { }, }) }) + + t.Run("updates_default_branch_without_error", func(t *testing.T) { + randomID := acctest.RandString(5) + repoName := fmt.Sprintf("%sbranch-def-%s", testResourcePrefix, randomID) + + config := ` + resource "github_repository" "test" { + name = "%s" + auto_init = true + } + resource "github_branch" "test" { + repository = github_repository.test.name + branch = "test" + } + + resource "github_branch_default" "test" { + repository = github_repository.test.name + branch = "%s" + } + ` + + resource.Test(t, resource.TestCase{ + PreCheck: func() { skipUnauthenticated(t) }, + ProviderFactories: providerFactories, + Steps: []resource.TestStep{ + { + Config: fmt.Sprintf(config, repoName, "main"), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.CompareValuePairs( + "github_branch_default.test", tfjsonpath.New("branch"), + "github_repository.test", tfjsonpath.New("default_branch"), + compare.ValuesSame(), + ), + }, + }, + { + Config: fmt.Sprintf(config, repoName, "test"), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction("github_branch_default.test", plancheck.ResourceActionUpdate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue("github_branch_default.test", tfjsonpath.New("branch"), knownvalue.StringExact("test")), + }, + }, + { + Config: ` + removed { + from = github_branch.test + lifecycle { destroy = false } + } + `, + }, + }, + }) + }) + + t.Run("updates_default_branch_with_rename_without_error", func(t *testing.T) { + randomID := acctest.RandString(5) + repoName := fmt.Sprintf("%sbranch-def-%s", testResourcePrefix, randomID) + + config := ` + resource "github_repository" "test" { + name = "%s" + auto_init = true + } + + resource "github_branch_default" "test" { + repository = github_repository.test.name + branch = "%s" + rename = true + } + ` + + resource.Test(t, resource.TestCase{ + PreCheck: func() { skipUnauthenticated(t) }, + ProviderFactories: providerFactories, + Steps: []resource.TestStep{ + { + Config: fmt.Sprintf(config, repoName, "main"), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.CompareValuePairs( + "github_branch_default.test", tfjsonpath.New("branch"), + "github_repository.test", tfjsonpath.New("default_branch"), + compare.ValuesSame(), + ), + }, + }, + { + Config: fmt.Sprintf(config, repoName, "development"), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction("github_branch_default.test", plancheck.ResourceActionUpdate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue("github_branch_default.test", tfjsonpath.New("branch"), knownvalue.StringExact("development")), + }, + }, + }, + }) + }) + t.Run("imports_with_rename_without_error", func(t *testing.T) { + randomID := acctest.RandString(5) + repoName := fmt.Sprintf("%sbranch-def-%s", testResourcePrefix, randomID) + config := fmt.Sprintf(` + resource "github_repository" "test" { + name = "%s" + auto_init = true + } + + resource "github_branch_default" "test"{ + repository = github_repository.test.name + branch = "development" + rename = true + } + `, repoName) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { skipUnauthenticated(t) }, + ProviderFactories: providerFactories, + Steps: []resource.TestStep{ + { + Config: config, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue("github_branch_default.test", tfjsonpath.New("branch"), knownvalue.StringExact("development")), + }, + }, + { + ResourceName: "github_branch_default.test", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"rename", "etag"}, + }, + }, + }) + }) } From 667636f6c71ff20e68dab7591ce5d8c3040251f5 Mon Sep 17 00:00:00 2001 From: Timo Sand Date: Sat, 21 Feb 2026 21:27:52 +0200 Subject: [PATCH 05/10] Refactor to use `tflog` Signed-off-by: Timo Sand --- github/resource_github_branch_default.go | 60 ++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 4 deletions(-) diff --git a/github/resource_github_branch_default.go b/github/resource_github_branch_default.go index dd535f26d0..0b8ab2cf7c 100644 --- a/github/resource_github_branch_default.go +++ b/github/resource_github_branch_default.go @@ -3,10 +3,10 @@ package github import ( "context" "errors" - "log" "net/http" "github.com/google/go-github/v83/github" + "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -63,17 +63,30 @@ func resourceGithubBranchDefaultCreate(ctx context.Context, d *schema.ResourceDa defaultBranch := d.Get("branch").(string) rename := d.Get("rename").(bool) + tflog.Trace(ctx, "Creating default branch resource", map[string]any{ + "owner": owner, + "repository": repoName, + "branch": defaultBranch, + "rename": rename, + }) + repository, _, err := client.Repositories.Get(ctx, owner, repoName) if err != nil { return diag.FromErr(err) } + tflog.Debug(ctx, "Fetched repository", map[string]any{ + "current_default_branch": repository.GetDefaultBranch(), + }) + if repository.GetDefaultBranch() != defaultBranch { if rename { + tflog.Debug(ctx, "Renaming branch to new default") if _, _, err := client.Repositories.RenameBranch(ctx, owner, repoName, repository.GetDefaultBranch(), defaultBranch); err != nil { return diag.FromErr(err) } } else { + tflog.Debug(ctx, "Setting new default branch") repository := &github.Repository{ DefaultBranch: github.Ptr(defaultBranch), } @@ -82,14 +95,20 @@ func resourceGithubBranchDefaultCreate(ctx context.Context, d *schema.ResourceDa return diag.FromErr(err) } } + } else { + tflog.Debug(ctx, "Default branch already set to desired branch, skipping update") } d.SetId(repoName) + tflog.Trace(ctx, "Finished creating default branch resource", map[string]any{ + "resource_id": d.Id(), + }) return resourceGithubBranchDefaultRead(ctx, d, meta) } func resourceGithubBranchDefaultRead(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics { + ctx = tflog.SetField(ctx, "resource_id", d.Id()) meta := m.(*Owner) client := meta.v3client owner := meta.name @@ -97,6 +116,11 @@ func resourceGithubBranchDefaultRead(ctx context.Context, d *schema.ResourceData // repoName := d.Get("repository").(string) repoName := d.Id() + tflog.Trace(ctx, "Reading default branch resource", map[string]any{ + "owner": owner, + "repository": repoName, + }) + if !d.IsNewResource() { ctx = context.WithValue(ctx, ctxEtag, d.Get("etag").(string)) } @@ -106,11 +130,14 @@ func resourceGithubBranchDefaultRead(ctx context.Context, d *schema.ResourceData var ghErr *github.ErrorResponse if errors.As(err, &ghErr) { if ghErr.Response.StatusCode == http.StatusNotModified { + tflog.Debug(ctx, "Repository not modified, skipping read") return nil } if ghErr.Response.StatusCode == http.StatusNotFound { - log.Printf("[INFO] Removing repository %s/%s from state because it no longer exists in GitHub", - owner, repoName) + tflog.Info(ctx, "Removing repository from state because it no longer exists in GitHub", map[string]any{ + "owner": owner, + "repository": repoName, + }) d.SetId("") return nil } @@ -119,6 +146,7 @@ func resourceGithubBranchDefaultRead(ctx context.Context, d *schema.ResourceData } if repository.DefaultBranch == nil { + tflog.Warn(ctx, "Default branch is nil, removing resource from state") d.SetId("") return nil } @@ -132,10 +160,13 @@ func resourceGithubBranchDefaultRead(ctx context.Context, d *schema.ResourceData if err := d.Set("repository", repository.GetName()); err != nil { return diag.FromErr(err) } + + tflog.Trace(ctx, "Finished reading default branch resource") return nil } func resourceGithubBranchDefaultUpdate(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics { + ctx = tflog.SetField(ctx, "resource_id", d.Id()) meta := m.(*Owner) client := meta.v3client owner := meta.name @@ -145,7 +176,15 @@ func resourceGithubBranchDefaultUpdate(ctx context.Context, d *schema.ResourceDa defaultBranch := d.Get("branch").(string) rename := d.Get("rename").(bool) + tflog.Trace(ctx, "Updating default branch resource", map[string]any{ + "owner": owner, + "repository": repoName, + "branch": defaultBranch, + "rename": rename, + }) + if rename { + tflog.Debug(ctx, "Renaming branch to new default") repository, _, err := client.Repositories.Get(ctx, owner, repoName) if err != nil { return diag.FromErr(err) @@ -154,6 +193,7 @@ func resourceGithubBranchDefaultUpdate(ctx context.Context, d *schema.ResourceDa return diag.FromErr(err) } } else { + tflog.Debug(ctx, "Setting new default branch") repository := &github.Repository{ DefaultBranch: github.Ptr(defaultBranch), } @@ -163,22 +203,34 @@ func resourceGithubBranchDefaultUpdate(ctx context.Context, d *schema.ResourceDa } } + tflog.Trace(ctx, "Finished updating default branch resource") return resourceGithubBranchDefaultRead(ctx, d, meta) } func resourceGithubBranchDefaultDelete(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics { + ctx = tflog.SetField(ctx, "resource_id", d.Id()) meta := m.(*Owner) client := meta.v3client owner := meta.name // repoName := d.Get("repository").(string) repoName := d.Id() + tflog.Trace(ctx, "Deleting default branch resource", map[string]any{ + "owner": owner, + "repository": repoName, + }) + repository := &github.Repository{ DefaultBranch: nil, } _, _, err := client.Repositories.Edit(ctx, owner, repoName, repository) - return diag.FromErr(err) + if err != nil { + return diag.FromErr(err) + } + + tflog.Trace(ctx, "Finished deleting default branch resource") + return nil } // func resourceGithubBranchDefaultImport(ctx context.Context, d *schema.ResourceData, m any) ([]*schema.ResourceData, error) { From de077b7b7a315998ffa3abfb88a9ff0e4cdcb909 Mon Sep 17 00:00:00 2001 From: Timo Sand Date: Sat, 21 Feb 2026 21:35:00 +0200 Subject: [PATCH 06/10] Remove `Read` calls from `Update` and `Create` Signed-off-by: Timo Sand --- github/resource_github_branch_default.go | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/github/resource_github_branch_default.go b/github/resource_github_branch_default.go index 0b8ab2cf7c..0d3870166a 100644 --- a/github/resource_github_branch_default.go +++ b/github/resource_github_branch_default.go @@ -70,7 +70,7 @@ func resourceGithubBranchDefaultCreate(ctx context.Context, d *schema.ResourceDa "rename": rename, }) - repository, _, err := client.Repositories.Get(ctx, owner, repoName) + repository, resp, err := client.Repositories.Get(ctx, owner, repoName) if err != nil { return diag.FromErr(err) } @@ -101,10 +101,15 @@ func resourceGithubBranchDefaultCreate(ctx context.Context, d *schema.ResourceDa d.SetId(repoName) + if err := d.Set("etag", resp.Header.Get("ETag")); err != nil { + return diag.FromErr(err) + } + tflog.Trace(ctx, "Finished creating default branch resource", map[string]any{ "resource_id": d.Id(), }) - return resourceGithubBranchDefaultRead(ctx, d, meta) + + return nil } func resourceGithubBranchDefaultRead(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics { @@ -183,12 +188,15 @@ func resourceGithubBranchDefaultUpdate(ctx context.Context, d *schema.ResourceDa "rename": rename, }) + var etag string + if rename { tflog.Debug(ctx, "Renaming branch to new default") - repository, _, err := client.Repositories.Get(ctx, owner, repoName) + repository, resp, err := client.Repositories.Get(ctx, owner, repoName) if err != nil { return diag.FromErr(err) } + etag = resp.Header.Get("ETag") if _, _, err := client.Repositories.RenameBranch(ctx, owner, repoName, repository.GetDefaultBranch(), defaultBranch); err != nil { return diag.FromErr(err) } @@ -198,13 +206,18 @@ func resourceGithubBranchDefaultUpdate(ctx context.Context, d *schema.ResourceDa DefaultBranch: github.Ptr(defaultBranch), } - if _, _, err := client.Repositories.Edit(ctx, owner, repoName, repository); err != nil { + if _, resp, err := client.Repositories.Edit(ctx, owner, repoName, repository); err != nil { return diag.FromErr(err) + } else { + etag = resp.Header.Get("ETag") } } + if err := d.Set("etag", etag); err != nil { + return diag.FromErr(err) + } tflog.Trace(ctx, "Finished updating default branch resource") - return resourceGithubBranchDefaultRead(ctx, d, meta) + return nil } func resourceGithubBranchDefaultDelete(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics { From 818d57f0b3e3d5281b76f9b7dffd7f84867f3153 Mon Sep 17 00:00:00 2001 From: Timo Sand Date: Sat, 21 Feb 2026 21:57:23 +0200 Subject: [PATCH 07/10] Update tests to use `ConfigStateChecks` Signed-off-by: Timo Sand --- github/resource_github_branch_default_test.go | 52 +++++++++---------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/github/resource_github_branch_default_test.go b/github/resource_github_branch_default_test.go index a512a18485..0b993912cb 100644 --- a/github/resource_github_branch_default_test.go +++ b/github/resource_github_branch_default_test.go @@ -30,24 +30,18 @@ func TestAccGithubBranchDefault(t *testing.T) { } `, repoName) - check := resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "github_branch_default.test", "branch", - "main", - ), - resource.TestCheckResourceAttr( - "github_branch_default.test", "repository", - repoName, - ), - ) - resource.Test(t, resource.TestCase{ PreCheck: func() { skipUnauthenticated(t) }, ProviderFactories: providerFactories, Steps: []resource.TestStep{ { Config: config, - Check: check, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.CompareValuePairs("github_branch_default.test", tfjsonpath.New("repository"), "github_repository.test", tfjsonpath.New("name"), compare.ValuesSame()), + statecheck.CompareValuePairs("github_branch_default.test", tfjsonpath.New("branch"), "github_repository.test", tfjsonpath.New("default_branch"), compare.ValuesSame()), + statecheck.ExpectKnownValue("github_branch_default.test", tfjsonpath.New("repository_id"), knownvalue.NotNull()), + statecheck.ExpectKnownValue("github_branch_default.test", tfjsonpath.New("etag"), knownvalue.NotNull()), + }, }, }, }) @@ -80,9 +74,12 @@ func TestAccGithubBranchDefault(t *testing.T) { Steps: []resource.TestStep{ { Config: config, - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("github_branch_default.test", "branch", "test"), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.CompareValuePairs("github_branch_default.test", tfjsonpath.New("repository"), "github_repository.test", tfjsonpath.New("name"), compare.ValuesSame()), + statecheck.CompareValuePairs("github_branch_default.test", tfjsonpath.New("branch"), "github_branch.test", tfjsonpath.New("branch"), compare.ValuesSame()), + statecheck.ExpectKnownValue("github_branch_default.test", tfjsonpath.New("repository_id"), knownvalue.NotNull()), + statecheck.ExpectKnownValue("github_branch_default.test", tfjsonpath.New("etag"), knownvalue.NotNull()), + }, }, { Config: ` @@ -112,24 +109,18 @@ func TestAccGithubBranchDefault(t *testing.T) { } `, repoName) - check := resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - "github_branch_default.test", "branch", - "main", - ), - resource.TestCheckResourceAttr( - "github_branch_default.test", "repository", - repoName, - ), - ) - resource.Test(t, resource.TestCase{ PreCheck: func() { skipUnauthenticated(t) }, ProviderFactories: providerFactories, Steps: []resource.TestStep{ { Config: config, - Check: check, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.CompareValuePairs("github_branch_default.test", tfjsonpath.New("repository"), "github_repository.test", tfjsonpath.New("name"), compare.ValuesSame()), + statecheck.CompareValuePairs("github_branch_default.test", tfjsonpath.New("branch"), "github_repository.test", tfjsonpath.New("default_branch"), compare.ValuesSame()), + statecheck.ExpectKnownValue("github_branch_default.test", tfjsonpath.New("repository_id"), knownvalue.NotNull()), + statecheck.ExpectKnownValue("github_branch_default.test", tfjsonpath.New("etag"), knownvalue.NotNull()), + }, }, }, }) @@ -157,7 +148,12 @@ func TestAccGithubBranchDefault(t *testing.T) { Steps: []resource.TestStep{ { Config: config, - Check: resource.ComposeTestCheckFunc(resource.TestCheckResourceAttr("github_branch_default.test", "branch", "development")), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.CompareValuePairs("github_branch_default.test", tfjsonpath.New("repository"), "github_repository.test", tfjsonpath.New("name"), compare.ValuesSame()), + statecheck.ExpectKnownValue("github_branch_default.test", tfjsonpath.New("branch"), knownvalue.StringExact("development")), + statecheck.ExpectKnownValue("github_branch_default.test", tfjsonpath.New("repository_id"), knownvalue.NotNull()), + statecheck.ExpectKnownValue("github_branch_default.test", tfjsonpath.New("etag"), knownvalue.NotNull()), + }, }, }, }) From 4be1e20d288328f63fc40d7f11df975ad46ba299 Mon Sep 17 00:00:00 2001 From: Timo Sand Date: Sat, 21 Feb 2026 21:58:28 +0200 Subject: [PATCH 08/10] Adds `repository_id` field Signed-off-by: Timo Sand --- github/resource_github_branch_default.go | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/github/resource_github_branch_default.go b/github/resource_github_branch_default.go index 0d3870166a..4d4d92caa2 100644 --- a/github/resource_github_branch_default.go +++ b/github/resource_github_branch_default.go @@ -22,6 +22,8 @@ func resourceGithubBranchDefault() *schema.Resource { // StateContext: resourceGithubBranchDefaultImport, }, + CustomizeDiff: diffRepository, + Schema: map[string]*schema.Schema{ "branch": { Type: schema.TypeString, @@ -31,10 +33,13 @@ func resourceGithubBranchDefault() *schema.Resource { "repository": { Type: schema.TypeString, Required: true, - ForceNew: true, Description: "The GitHub repository.", }, - // TODO add repository_id and diffRepository to handle repository renames + "repository_id": { + Type: schema.TypeInt, + Computed: true, + Description: "The GitHub repository ID.", + }, "rename": { Type: schema.TypeBool, Optional: true, @@ -101,6 +106,9 @@ func resourceGithubBranchDefaultCreate(ctx context.Context, d *schema.ResourceDa d.SetId(repoName) + if err := d.Set("repository_id", int(repository.GetID())); err != nil { + return diag.FromErr(err) + } if err := d.Set("etag", resp.Header.Get("ETag")); err != nil { return diag.FromErr(err) } @@ -156,13 +164,15 @@ func resourceGithubBranchDefaultRead(ctx context.Context, d *schema.ResourceData return nil } - if err := d.Set("etag", resp.Header.Get("ETag")); err != nil { + if err := d.Set("repository_id", int(repository.GetID())); err != nil { return diag.FromErr(err) } - if err := d.Set("branch", repository.GetDefaultBranch()); err != nil { + + if err := d.Set("etag", resp.Header.Get("ETag")); err != nil { return diag.FromErr(err) } - if err := d.Set("repository", repository.GetName()); err != nil { + + if err := d.Set("branch", repository.GetDefaultBranch()); err != nil { return diag.FromErr(err) } From cb160ad90a433882bd1f54c52030a3d502f2f9ad Mon Sep 17 00:00:00 2001 From: Timo Sand Date: Sat, 21 Feb 2026 21:59:36 +0200 Subject: [PATCH 09/10] Adds custom `Import` function Signed-off-by: Timo Sand --- github/resource_github_branch_default.go | 37 +++++++++--------------- 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/github/resource_github_branch_default.go b/github/resource_github_branch_default.go index 4d4d92caa2..f3cea8f5f6 100644 --- a/github/resource_github_branch_default.go +++ b/github/resource_github_branch_default.go @@ -18,8 +18,7 @@ func resourceGithubBranchDefault() *schema.Resource { UpdateContext: resourceGithubBranchDefaultUpdate, DeleteContext: resourceGithubBranchDefaultDelete, Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, - // StateContext: resourceGithubBranchDefaultImport, + StateContext: resourceGithubBranchDefaultImport, }, CustomizeDiff: diffRepository, @@ -126,8 +125,7 @@ func resourceGithubBranchDefaultRead(ctx context.Context, d *schema.ResourceData client := meta.v3client owner := meta.name - // repoName := d.Get("repository").(string) - repoName := d.Id() + repoName := d.Get("repository").(string) tflog.Trace(ctx, "Reading default branch resource", map[string]any{ "owner": owner, @@ -186,8 +184,7 @@ func resourceGithubBranchDefaultUpdate(ctx context.Context, d *schema.ResourceDa client := meta.v3client owner := meta.name - // repoName := d.Get("repository").(string) - repoName := d.Id() + repoName := d.Get("repository").(string) defaultBranch := d.Get("branch").(string) rename := d.Get("rename").(bool) @@ -235,8 +232,7 @@ func resourceGithubBranchDefaultDelete(ctx context.Context, d *schema.ResourceDa meta := m.(*Owner) client := meta.v3client owner := meta.name - // repoName := d.Get("repository").(string) - repoName := d.Id() + repoName := d.Get("repository").(string) tflog.Trace(ctx, "Deleting default branch resource", map[string]any{ "owner": owner, @@ -256,19 +252,12 @@ func resourceGithubBranchDefaultDelete(ctx context.Context, d *schema.ResourceDa return nil } -// func resourceGithubBranchDefaultImport(ctx context.Context, d *schema.ResourceData, m any) ([]*schema.ResourceData, error) { -// repoName, defaultBranch, err := parseID2(d.Id()) -// if err != nil { -// return nil, err -// } - -// d.SetId(repoName) -// if err := d.Set("branch", defaultBranch); err != nil { -// return nil, err -// } -// if err := d.Set("repository", repoName); err != nil { -// return nil, err -// } - -// return []*schema.ResourceData{d}, nil -// } +func resourceGithubBranchDefaultImport(ctx context.Context, d *schema.ResourceData, m any) ([]*schema.ResourceData, error) { + repoName := d.Id() + + if err := d.Set("repository", repoName); err != nil { + return nil, err + } + + return []*schema.ResourceData{d}, nil +} From 0e6383753fb17dacc58da1702d00d909d2e76067 Mon Sep 17 00:00:00 2001 From: Timo Sand Date: Sat, 21 Feb 2026 22:00:03 +0200 Subject: [PATCH 10/10] Updates docs Signed-off-by: Timo Sand --- website/docs/r/branch_default.html.markdown | 22 +++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/website/docs/r/branch_default.html.markdown b/website/docs/r/branch_default.html.markdown index e7d4361046..f5763d299c 100644 --- a/website/docs/r/branch_default.html.markdown +++ b/website/docs/r/branch_default.html.markdown @@ -9,9 +9,9 @@ description: |- Provides a GitHub branch default resource. -This resource allows you to set the default branch for a given repository. +This resource allows you to set the default branch for a given repository. -Note that use of this resource is incompatible with the `default_branch` option of the `github_repository` resource. Using both will result in plans always showing a diff. +Note that use of this resource is incompatible with the `default_branch` option of the `github_repository` resource. Using both will result in plans always showing a diff. ## Example Usage @@ -55,14 +55,20 @@ resource "github_branch_default" "default"{ The following arguments are supported: -* `repository` - (Required) The GitHub repository -* `branch` - (Required) The branch (e.g. `main`) -* `rename` - (Optional) Indicate if it should rename the branch rather than use an existing branch. Defaults to `false`. +- `repository` - (Required) The GitHub repository +- `branch` - (Required) The branch (e.g. `main`) +- `rename` - (Optional) Indicate if it should rename the branch rather than use an existing branch. Defaults to `false`. + +## Attribute Reference + +The following attributes are exported: + +- `repository_id` - The GitHub repository ID. ## Import -GitHub Branch Defaults can be imported using an ID made up of `repository`, e.g. +GitHub Branch Defaults can be imported using the repository name, e.g. -``` -$ terraform import github_branch_default.branch_default my-repo +```text +terraform import github_branch_default.branch_default my-repo ```