Skip to content

Commit 18178b1

Browse files
authored
[FEAT] Add github_repository_pages Resource and Data Source (#3168)
* Add resource for repository pages and deprecate it from repository R Signed-off-by: Timo Sand <[email protected]> * Add data source for repository pages and deprecate it from repository DS Signed-off-by: Timo Sand <[email protected]> * Update formatting of docs page Signed-off-by: Timo Sand <[email protected]> * Change `github_repository` to only Read pages info if pages is in the config Signed-off-by: Timo Sand <[email protected]> * Fix faulty test Signed-off-by: Timo Sand <[email protected]> * Update Import test Signed-off-by: Timo Sand <[email protected]> * Add `repository_id` diff logic and unify naming Signed-off-by: Timo Sand <[email protected]> * Use `ConfigStateChecks` in DS tests Signed-off-by: Timo Sand <[email protected]> * Refactor to use `ConfigStateChecks` in Resource Signed-off-by: Timo Sand <[email protected]> * Comment out `owner` field for now Signed-off-by: Timo Sand <[email protected]> * Comment out `owner` field for DS as well Signed-off-by: Timo Sand <[email protected]> * Simplify import ID Signed-off-by: Timo Sand <[email protected]> * Add support for `public` field in pages Signed-off-by: Timo Sand <[email protected]> * Update docs Signed-off-by: Timo Sand <[email protected]> * Improve field descriptions Signed-off-by: Timo Sand <[email protected]> * Only modify `CNAME` in state if it has a value upstream Signed-off-by: Timo Sand <[email protected]> * Add `https_enforced` field Signed-off-by: Timo Sand <[email protected]> * Update `go-github` version Signed-off-by: Timo Sand <[email protected]> * Replace `switch` with `if` Signed-off-by: Timo Sand <[email protected]> * Re-order `d.Set` calls Signed-off-by: Timo Sand <[email protected]> * Restructure `UpdatePages` section Signed-off-by: Timo Sand <[email protected]> * Refactor tests to use `testAccConf.testRepositoryVisibility` Signed-off-by: Timo Sand <[email protected]> * Fix linter Signed-off-by: Timo Sand <[email protected]> * Add tests to ensure that `source` validation works properly Signed-off-by: Timo Sand <[email protected]> * Add more debug logging and fix validation Signed-off-by: Timo Sand <[email protected]> * Fixed validation tests to notify when they are not working Signed-off-by: Timo Sand <[email protected]> * Add comments to make it clearer why we need to use this partial value setting in Create Signed-off-by: Timo Sand <[email protected]> * Remove unnecessary `hasChanges` checks and explain the ones that are unnecessary Signed-off-by: Timo Sand <[email protected]> * Address review comments Signed-off-by: Timo Sand <[email protected]> * Reduce test time by parallelising Signed-off-by: Timo Sand <[email protected]> --------- Signed-off-by: Timo Sand <[email protected]>
1 parent 4cf1e9d commit 18178b1

12 files changed

Lines changed: 1332 additions & 111 deletions

github/data_source_github_repository.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,8 +241,9 @@ func dataSourceGithubRepository() *schema.Resource {
241241
},
242242
},
243243
"pages": {
244-
Type: schema.TypeList,
245-
Computed: true,
244+
Type: schema.TypeList,
245+
Computed: true,
246+
Deprecated: "Use the github_repository_pages data source instead. This field will be removed in a future version.",
246247
Elem: &schema.Resource{
247248
Schema: map[string]*schema.Schema{
248249
"source": {
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
package github
2+
3+
import (
4+
"context"
5+
"net/http"
6+
"strconv"
7+
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
10+
)
11+
12+
func dataSourceGithubRepositoryPages() *schema.Resource {
13+
return &schema.Resource{
14+
Description: "Use this data source to retrieve GitHub Pages configuration for a repository.",
15+
ReadContext: dataSourceGithubRepositoryPagesRead,
16+
17+
Schema: map[string]*schema.Schema{
18+
"repository": {
19+
Type: schema.TypeString,
20+
Required: true,
21+
Description: "The repository name to get GitHub Pages information for.",
22+
},
23+
// TODO: Uncomment this when we are ready to support owner fields properly. https://github.com/integrations/terraform-provider-github/pull/3166#discussion_r2816053082
24+
// "owner": {
25+
// Type: schema.TypeString,
26+
// Required: true,
27+
// Description: "The owner of the repository.",
28+
// },
29+
"source": {
30+
Type: schema.TypeList,
31+
Computed: true,
32+
Description: "The source branch and directory for the rendered Pages site.",
33+
Elem: &schema.Resource{
34+
Schema: map[string]*schema.Schema{
35+
"branch": {
36+
Type: schema.TypeString,
37+
Computed: true,
38+
Description: "The repository branch used to publish the site's source files.",
39+
},
40+
"path": {
41+
Type: schema.TypeString,
42+
Computed: true,
43+
Description: "The repository directory from which the site publishes.",
44+
},
45+
},
46+
},
47+
},
48+
"build_type": {
49+
Type: schema.TypeString,
50+
Computed: true,
51+
Description: "The type of GitHub Pages site. Can be 'legacy' or 'workflow'.",
52+
},
53+
"cname": {
54+
Type: schema.TypeString,
55+
Computed: true,
56+
Description: "The custom domain for the repository.",
57+
},
58+
"custom_404": {
59+
Type: schema.TypeBool,
60+
Computed: true,
61+
Description: "Whether the rendered GitHub Pages site has a custom 404 page.",
62+
},
63+
"html_url": {
64+
Type: schema.TypeString,
65+
Computed: true,
66+
Description: "The absolute URL (with scheme) to the rendered GitHub Pages site.",
67+
},
68+
"build_status": {
69+
Type: schema.TypeString,
70+
Computed: true,
71+
Description: "The GitHub Pages site's build status e.g. 'building' or 'built'.",
72+
},
73+
"api_url": {
74+
Type: schema.TypeString,
75+
Computed: true,
76+
Description: "The API URL of the GitHub Pages resource.",
77+
},
78+
"public": {
79+
Type: schema.TypeBool,
80+
Computed: true,
81+
Description: "Whether the GitHub Pages site is publicly visible. If set to `true`, the site is accessible to anyone on the internet. If set to `false`, the site will only be accessible to users who have at least `read` access to the repository that published the site.",
82+
},
83+
"https_enforced": {
84+
Type: schema.TypeBool,
85+
Computed: true,
86+
Description: "Whether the rendered GitHub Pages site will only be served over HTTPS.",
87+
},
88+
},
89+
}
90+
}
91+
92+
func dataSourceGithubRepositoryPagesRead(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics {
93+
meta := m.(*Owner)
94+
client := meta.v3client
95+
96+
owner := meta.name // TODO: Add owner support // d.Get("owner").(string)
97+
repoName := d.Get("repository").(string)
98+
99+
pages, resp, err := client.Repositories.GetPagesInfo(ctx, owner, repoName)
100+
if err != nil {
101+
if resp != nil && resp.StatusCode == http.StatusNotFound {
102+
return diag.Errorf("GitHub Pages not found for repository %s/%s", owner, repoName)
103+
}
104+
return diag.Errorf("error reading repository pages: %s", err.Error())
105+
}
106+
107+
repo, _, err := client.Repositories.Get(ctx, owner, repoName)
108+
if err != nil {
109+
return diag.FromErr(err)
110+
}
111+
112+
d.SetId(strconv.Itoa(int(repo.GetID())))
113+
114+
if err := d.Set("build_type", pages.GetBuildType()); err != nil {
115+
return diag.FromErr(err)
116+
}
117+
if err := d.Set("cname", pages.GetCNAME()); err != nil {
118+
return diag.FromErr(err)
119+
}
120+
if err := d.Set("custom_404", pages.GetCustom404()); err != nil {
121+
return diag.FromErr(err)
122+
}
123+
if err := d.Set("html_url", pages.GetHTMLURL()); err != nil {
124+
return diag.FromErr(err)
125+
}
126+
if err := d.Set("build_status", pages.GetStatus()); err != nil {
127+
return diag.FromErr(err)
128+
}
129+
if err := d.Set("api_url", pages.GetURL()); err != nil {
130+
return diag.FromErr(err)
131+
}
132+
if err := d.Set("public", pages.GetPublic()); err != nil {
133+
return diag.FromErr(err)
134+
}
135+
if err := d.Set("https_enforced", pages.GetHTTPSEnforced()); err != nil {
136+
return diag.FromErr(err)
137+
}
138+
// Set source only for legacy build type
139+
if pages.GetBuildType() == "legacy" && pages.GetSource() != nil {
140+
source := []map[string]any{
141+
{
142+
"branch": pages.GetSource().GetBranch(),
143+
"path": pages.GetSource().GetPath(),
144+
},
145+
}
146+
if err := d.Set("source", source); err != nil {
147+
return diag.FromErr(err)
148+
}
149+
} else {
150+
if err := d.Set("source", []map[string]any{}); err != nil {
151+
return diag.FromErr(err)
152+
}
153+
}
154+
155+
return nil
156+
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
package github
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-plugin-testing/compare"
8+
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
9+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
10+
"github.com/hashicorp/terraform-plugin-testing/knownvalue"
11+
"github.com/hashicorp/terraform-plugin-testing/statecheck"
12+
"github.com/hashicorp/terraform-plugin-testing/tfjsonpath"
13+
)
14+
15+
func TestAccGithubRepositoryPagesDataSource(t *testing.T) {
16+
t.Run("reads_pages_configuration", func(t *testing.T) {
17+
randomID := acctest.RandString(5)
18+
repoName := fmt.Sprintf("%spages-ds-%s", testResourcePrefix, randomID)
19+
20+
config := fmt.Sprintf(`
21+
resource "github_repository" "test" {
22+
name = "%s"
23+
visibility = "%s"
24+
auto_init = true
25+
}
26+
27+
resource "github_repository_pages" "test" {
28+
repository = github_repository.test.name
29+
build_type = "legacy"
30+
source {
31+
branch = "main"
32+
path = "/"
33+
}
34+
}
35+
36+
data "github_repository_pages" "test" {
37+
repository = github_repository.test.name
38+
39+
depends_on = [github_repository_pages.test]
40+
}
41+
`, repoName, testAccConf.testRepositoryVisibility)
42+
43+
resource.Test(t, resource.TestCase{
44+
PreCheck: func() {
45+
skipUnauthenticated(t)
46+
},
47+
ProviderFactories: providerFactories,
48+
Steps: []resource.TestStep{
49+
{
50+
Config: config,
51+
ConfigStateChecks: []statecheck.StateCheck{
52+
statecheck.CompareValuePairs("data.github_repository_pages.test", tfjsonpath.New("build_type"), "github_repository_pages.test", tfjsonpath.New("build_type"), compare.ValuesSame()),
53+
statecheck.CompareValuePairs("data.github_repository_pages.test", tfjsonpath.New("source").AtSliceIndex(0).AtMapKey("branch"), "github_repository_pages.test", tfjsonpath.New("source").AtSliceIndex(0).AtMapKey("branch"), compare.ValuesSame()),
54+
statecheck.CompareValuePairs("data.github_repository_pages.test", tfjsonpath.New("source").AtSliceIndex(0).AtMapKey("path"), "github_repository_pages.test", tfjsonpath.New("source").AtSliceIndex(0).AtMapKey("path"), compare.ValuesSame()),
55+
statecheck.CompareValuePairs("data.github_repository_pages.test", tfjsonpath.New("cname"), "github_repository_pages.test", tfjsonpath.New("cname"), compare.ValuesSame()),
56+
statecheck.CompareValuePairs("data.github_repository_pages.test", tfjsonpath.New("custom_404"), "github_repository_pages.test", tfjsonpath.New("custom_404"), compare.ValuesSame()),
57+
statecheck.CompareValuePairs("data.github_repository_pages.test", tfjsonpath.New("html_url"), "github_repository_pages.test", tfjsonpath.New("html_url"), compare.ValuesSame()),
58+
statecheck.ExpectKnownValue("data.github_repository_pages.test", tfjsonpath.New("build_status"), knownvalue.NotNull()),
59+
statecheck.CompareValuePairs("data.github_repository_pages.test", tfjsonpath.New("api_url"), "github_repository_pages.test", tfjsonpath.New("api_url"), compare.ValuesSame()),
60+
statecheck.ExpectKnownValue("data.github_repository_pages.test", tfjsonpath.New("public"), knownvalue.Bool(testAccConf.authMode != enterprise)),
61+
statecheck.CompareValuePairs("data.github_repository_pages.test", tfjsonpath.New("https_enforced"), "github_repository_pages.test", tfjsonpath.New("https_enforced"), compare.ValuesSame()),
62+
},
63+
},
64+
},
65+
})
66+
})
67+
t.Run("reads_pages_enterprise_configuration", func(t *testing.T) {
68+
randomID := acctest.RandString(5)
69+
repoName := fmt.Sprintf("%spages-ds-%s", testResourcePrefix, randomID)
70+
71+
config := fmt.Sprintf(`
72+
resource "github_repository" "test" {
73+
name = "%s"
74+
visibility = "%s"
75+
auto_init = true
76+
}
77+
78+
resource "github_repository_pages" "test" {
79+
repository = github_repository.test.name
80+
build_type = "legacy"
81+
source {
82+
branch = "main"
83+
path = "/"
84+
}
85+
public = false
86+
}
87+
88+
data "github_repository_pages" "test" {
89+
repository = github_repository.test.name
90+
91+
depends_on = [github_repository_pages.test]
92+
}
93+
`, repoName, testAccConf.testRepositoryVisibility)
94+
95+
resource.Test(t, resource.TestCase{
96+
PreCheck: func() { skipUnlessEnterprise(t) },
97+
ProviderFactories: providerFactories,
98+
Steps: []resource.TestStep{
99+
{
100+
Config: config,
101+
ConfigStateChecks: []statecheck.StateCheck{
102+
statecheck.CompareValuePairs("data.github_repository_pages.test", tfjsonpath.New("build_type"), "github_repository_pages.test", tfjsonpath.New("build_type"), compare.ValuesSame()),
103+
statecheck.CompareValuePairs("data.github_repository_pages.test", tfjsonpath.New("source").AtSliceIndex(0).AtMapKey("branch"), "github_repository_pages.test", tfjsonpath.New("source").AtSliceIndex(0).AtMapKey("branch"), compare.ValuesSame()),
104+
statecheck.CompareValuePairs("data.github_repository_pages.test", tfjsonpath.New("source").AtSliceIndex(0).AtMapKey("path"), "github_repository_pages.test", tfjsonpath.New("source").AtSliceIndex(0).AtMapKey("path"), compare.ValuesSame()),
105+
statecheck.CompareValuePairs("data.github_repository_pages.test", tfjsonpath.New("cname"), "github_repository_pages.test", tfjsonpath.New("cname"), compare.ValuesSame()),
106+
statecheck.CompareValuePairs("data.github_repository_pages.test", tfjsonpath.New("custom_404"), "github_repository_pages.test", tfjsonpath.New("custom_404"), compare.ValuesSame()),
107+
statecheck.CompareValuePairs("data.github_repository_pages.test", tfjsonpath.New("html_url"), "github_repository_pages.test", tfjsonpath.New("html_url"), compare.ValuesSame()),
108+
statecheck.ExpectKnownValue("data.github_repository_pages.test", tfjsonpath.New("build_status"), knownvalue.NotNull()),
109+
statecheck.CompareValuePairs("data.github_repository_pages.test", tfjsonpath.New("api_url"), "github_repository_pages.test", tfjsonpath.New("api_url"), compare.ValuesSame()),
110+
statecheck.CompareValuePairs("data.github_repository_pages.test", tfjsonpath.New("public"), "github_repository_pages.test", tfjsonpath.New("public"), compare.ValuesSame()),
111+
statecheck.CompareValuePairs("data.github_repository_pages.test", tfjsonpath.New("https_enforced"), "github_repository_pages.test", tfjsonpath.New("https_enforced"), compare.ValuesSame()),
112+
},
113+
},
114+
},
115+
})
116+
})
117+
}

github/provider.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ func Provider() *schema.Provider {
198198
"github_repository_environment_deployment_policy": resourceGithubRepositoryEnvironmentDeploymentPolicy(),
199199
"github_repository_file": resourceGithubRepositoryFile(),
200200
"github_repository_milestone": resourceGithubRepositoryMilestone(),
201+
"github_repository_pages": resourceGithubRepositoryPages(),
201202
"github_repository_project": resourceGithubRepositoryProject(),
202203
"github_repository_pull_request": resourceGithubRepositoryPullRequest(),
203204
"github_repository_ruleset": resourceGithubRepositoryRuleset(),
@@ -284,6 +285,7 @@ func Provider() *schema.Provider {
284285
"github_repository_deployment_branch_policies": dataSourceGithubRepositoryDeploymentBranchPolicies(),
285286
"github_repository_file": dataSourceGithubRepositoryFile(),
286287
"github_repository_milestone": dataSourceGithubRepositoryMilestone(),
288+
"github_repository_pages": dataSourceGithubRepositoryPages(),
287289
"github_repository_pull_request": dataSourceGithubRepositoryPullRequest(),
288290
"github_repository_pull_requests": dataSourceGithubRepositoryPullRequests(),
289291
"github_repository_teams": dataSourceGithubRepositoryTeams(),

github/resource_github_repository.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ func resourceGithubRepository() *schema.Resource {
328328
MaxItems: 1,
329329
Optional: true,
330330
Description: "The repository's GitHub Pages configuration",
331+
Deprecated: "Use the github_repository_pages resource instead. This field will be removed in a future version.",
331332
Elem: &schema.Resource{
332333
Schema: map[string]*schema.Schema{
333334
"source": {
@@ -860,7 +861,8 @@ func resourceGithubRepositoryRead(ctx context.Context, d *schema.ResourceData, m
860861
_ = d.Set("squash_merge_commit_title", repo.GetSquashMergeCommitTitle())
861862
}
862863

863-
if repo.GetHasPages() {
864+
_, isPagesConfigured := d.GetOk("pages")
865+
if repo.GetHasPages() && isPagesConfigured {
864866
pages, _, err := client.Repositories.GetPagesInfo(ctx, owner, repoName)
865867
if err != nil {
866868
return diag.FromErr(err)

0 commit comments

Comments
 (0)