Skip to content

Commit 48bc34e

Browse files
committed
Adding a computed attribute for the repository owner in the github_repository resource and data source. Fixes #2503
1 parent d5dee20 commit 48bc34e

5 files changed

Lines changed: 239 additions & 1 deletion

github/data_source_github_repository.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,21 @@ func dataSourceGithubRepository() *schema.Resource {
2121
Type: schema.TypeString,
2222
Optional: true,
2323
Computed: true,
24-
ConflictsWith: []string{"name"},
24+
ConflictsWith: []string{"name", "owner"},
2525
},
2626
"name": {
2727
Type: schema.TypeString,
2828
Optional: true,
2929
Computed: true,
3030
ConflictsWith: []string{"full_name"},
3131
},
32+
"owner": {
33+
Type: schema.TypeString,
34+
Optional: true,
35+
Computed: true,
36+
ConflictsWith: []string{"full_name"},
37+
Description: "Owner of the repository. If not provided, the provider's default owner is used.",
38+
},
3239
"description": {
3340
Type: schema.TypeString,
3441
Default: nil,
@@ -354,6 +361,9 @@ func dataSourceGithubRepositoryRead(d *schema.ResourceData, meta any) error {
354361
if name, ok := d.GetOk("name"); ok {
355362
repoName = name.(string)
356363
}
364+
if ownerName, ok := d.GetOk("owner"); ok {
365+
owner = ownerName.(string)
366+
}
357367

358368
if repoName == "" {
359369
return fmt.Errorf("one of %q or %q has to be provided", "full_name", "name")

github/data_source_github_repository_test.go

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,4 +428,179 @@ EOT
428428
testCase(t, organization)
429429
})
430430
})
431+
432+
t.Run("queries a repository using owner and name", func(t *testing.T) {
433+
randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)
434+
435+
config := fmt.Sprintf(`
436+
resource "github_repository" "test" {
437+
name = "tf-acc-%s"
438+
}
439+
440+
data "github_repository" "test" {
441+
name = github_repository.test.name
442+
owner = "%s"
443+
}
444+
`, randomID, testOrganization)
445+
446+
check := resource.ComposeTestCheckFunc(
447+
resource.TestCheckResourceAttr(
448+
"data.github_repository.test", "owner",
449+
testOrganization,
450+
),
451+
)
452+
453+
testCase := func(t *testing.T, mode string) {
454+
resource.Test(t, resource.TestCase{
455+
PreCheck: func() { skipUnlessMode(t, mode) },
456+
Providers: testAccProviders,
457+
Steps: []resource.TestStep{
458+
{
459+
Config: config,
460+
Check: check,
461+
},
462+
},
463+
})
464+
}
465+
466+
t.Run("with an anonymous account", func(t *testing.T) {
467+
testCase(t, anonymous)
468+
})
469+
470+
t.Run("with an individual account", func(t *testing.T) {
471+
testCase(t, individual)
472+
})
473+
t.Run("with an organization account", func(t *testing.T) {
474+
testCase(t, organization)
475+
})
476+
})
477+
478+
t.Run("validates conflicts between full_name, name, and owner", func(t *testing.T) {
479+
randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)
480+
481+
config := fmt.Sprintf(`
482+
resource "github_repository" "test" {
483+
name = "tf-acc-%[1]s"
484+
vulnerability_alerts = true
485+
}
486+
`, randomID)
487+
488+
// Test invalid combinations
489+
invalidConfigs := []string{
490+
// full_name with name
491+
fmt.Sprintf(`
492+
resource "github_repository" "test" {
493+
name = "tf-acc-%[1]s"
494+
vulnerability_alerts = true
495+
}
496+
497+
data "github_repository" "test" {
498+
full_name = "%[2]s/tf-acc-%[1]s"
499+
name = "tf-acc-%[1]s"
500+
}
501+
`, randomID, testOrganization),
502+
// full_name with owner
503+
fmt.Sprintf(`
504+
resource "github_repository" "test" {
505+
name = "tf-acc-%[1]s"
506+
}
507+
508+
data "github_repository" "test" {
509+
full_name = "%[2]s/tf-acc-%[1]s"
510+
owner = "%[2]s"
511+
}
512+
`, randomID, testOrganization),
513+
// full_name with both name and owner
514+
fmt.Sprintf(`
515+
resource "github_repository" "test" {
516+
name = "tf-acc-%[1]s"
517+
}
518+
519+
data "github_repository" "test" {
520+
full_name = "%[2]s/tf-acc-%[1]s"
521+
name = "tf-acc-%[1]s"
522+
owner = "%[2]s"
523+
}
524+
`, randomID, testOrganization),
525+
}
526+
527+
// Test valid combinations
528+
validConfigs := []string{
529+
// Just full_name
530+
fmt.Sprintf(`
531+
resource "github_repository" "test" {
532+
name = "tf-acc-%[1]s"
533+
}
534+
535+
data "github_repository" "test" {
536+
full_name = "%[2]s/tf-acc-%[1]s"
537+
}
538+
`, randomID, testOrganization),
539+
// Just name (uses provider owner)
540+
fmt.Sprintf(`
541+
resource "github_repository" "test" {
542+
name = "tf-acc-%[1]s"
543+
}
544+
545+
data "github_repository" "test" {
546+
name = "tf-acc-%[1]s"
547+
}
548+
`, randomID),
549+
// name with owner
550+
fmt.Sprintf(`
551+
resource "github_repository" "test" {
552+
name = "tf-acc-%[1]s"
553+
}
554+
555+
data "github_repository" "test" {
556+
name = "tf-acc-%[1]s"
557+
owner = "%[2]s"
558+
}
559+
`, randomID, testOrganization),
560+
}
561+
562+
testCase := func(t *testing.T, mode string) {
563+
resource.Test(t, resource.TestCase{
564+
PreCheck: func() { skipUnlessMode(t, mode) },
565+
Providers: testAccProviders,
566+
Steps: []resource.TestStep{
567+
// Create the repository first
568+
{
569+
Config: config,
570+
},
571+
// Test that invalid configs fail
572+
{
573+
Config: invalidConfigs[0],
574+
ExpectError: regexp.MustCompile("(?i)conflicts with"),
575+
},
576+
{
577+
Config: invalidConfigs[1],
578+
ExpectError: regexp.MustCompile("(?i)conflicts with"),
579+
},
580+
{
581+
Config: invalidConfigs[2],
582+
ExpectError: regexp.MustCompile("(?i)conflicts with"),
583+
},
584+
// Test that valid configs succeed
585+
{
586+
Config: validConfigs[0],
587+
},
588+
{
589+
Config: validConfigs[1],
590+
},
591+
{
592+
Config: validConfigs[2],
593+
},
594+
},
595+
})
596+
}
597+
598+
t.Run("with an individual account", func(t *testing.T) {
599+
testCase(t, individual)
600+
})
601+
602+
t.Run("with an organization account", func(t *testing.T) {
603+
testCase(t, organization)
604+
})
605+
})
431606
}

github/resource_github_repository.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,11 @@ func resourceGithubRepository() *schema.Resource {
399399
Computed: true,
400400
Description: "A string of the form 'orgname/reponame'.",
401401
},
402+
"owner": {
403+
Type: schema.TypeString,
404+
Computed: true,
405+
Description: "The owner of the repository.",
406+
},
402407
"html_url": {
403408
Type: schema.TypeString,
404409
Computed: true,
@@ -809,6 +814,9 @@ func resourceGithubRepositoryRead(d *schema.ResourceData, meta any) error {
809814
_ = d.Set("topics", flattenStringList(repo.Topics))
810815
_ = d.Set("node_id", repo.GetNodeID())
811816
_ = d.Set("repo_id", repo.GetID())
817+
if repo.Owner != nil {
818+
_ = d.Set("owner", repo.Owner.GetLogin())
819+
}
812820

813821
// GitHub API doesn't respond following parameters when repository is archived
814822
if !d.Get("archived").(bool) {

github/resource_github_repository_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -956,6 +956,49 @@ func TestAccGithubRepositories(t *testing.T) {
956956
testCase(t, organization)
957957
})
958958
})
959+
960+
t.Run("creates repository and returns owner field", func(t *testing.T) {
961+
randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)
962+
963+
config := fmt.Sprintf(`
964+
resource "github_repository" "test" {
965+
name = "tf-acc-test-owner-%[1]s"
966+
description = "Terraform acceptance tests %[1]s"
967+
}
968+
`, randomID)
969+
970+
check := resource.ComposeTestCheckFunc(
971+
resource.TestCheckResourceAttrSet(
972+
"github_repository.test", "owner",
973+
),
974+
)
975+
976+
testCase := func(t *testing.T, mode string) {
977+
resource.Test(t, resource.TestCase{
978+
PreCheck: func() { skipUnlessMode(t, mode) },
979+
Providers: testAccProviders,
980+
Steps: []resource.TestStep{
981+
{
982+
Config: config,
983+
Check: check,
984+
},
985+
},
986+
})
987+
}
988+
989+
t.Run("with an anonymous account", func(t *testing.T) {
990+
t.Skip("anonymous account not supported for this operation")
991+
})
992+
993+
t.Run("with an individual account", func(t *testing.T) {
994+
testCase(t, individual)
995+
})
996+
997+
t.Run("with an organization account", func(t *testing.T) {
998+
testCase(t, organization)
999+
})
1000+
})
1001+
9591002
}
9601003

9611004
func TestAccGithubRepositoryPages(t *testing.T) {

website/docs/d/repository.html.markdown

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ The following arguments are supported:
2525

2626
* `full_name` - (Optional) Full name of the repository (in `org/name` format).
2727

28+
* `owner` - (Optional) Owner of the repository. If not provided, the provider's default owner is used.
29+
2830
## Attributes Reference
2931

3032
* `node_id` - the Node ID of the repository.

0 commit comments

Comments
 (0)