Repository: google/go-github (go)

Issue:
Support updated GitHub Pages Update API 
In former versions of the GitHub API the pages update request used a `source` field of type `string`, with the branch name and a path delimited by a space. According to the current [GitHub documentation](https://docs.github.com/en/rest/pages#update-information-about-a-github-pages-site) and experiments with `curl`, the update api apparently now also supports the `source` parameter to be a struct like `{Branch: string, Path: string}`.

Looking at the required changes I think that this might break existing consumers of go-github using the PagesUpdate request - correct me if I'm wrong. I'm not sure if you prefer to have some kind of migration path supporting both versions or if a breaking change would be tolerable (maybe communicated with a major version bump). If you have any preference, please leave a note or a code pointer with an example how you'd like me to handle this.

See https://github.com/integrations/terraform-provider-github/issues/1198 for the motivation, and #2371 where the same requirement came up already. The planned change would also make the _create_ and _update_ pages code more consistent.

I've already started on a patch and I'm going to submit the pull request in the next days, so we might have a discussion on the actual change.

---

To show the desired effect, here are some examples using `curl`:

```
curl -X PUT https://api.github.com/repos/gesellix/pages-test/pages \
  -H 'Accept: application/vnd.github.v3+json' \
  -H 'Content-Type: application/json' \
  -H 'User-Agent: go-github' \
  -d '{"source":"main /docs"}' \
  -w "\n%{http_code}\n"
{"message":"Invalid request.\n\nInvalid property /source: `main /docs` is not a possible value. Must be one of the following: gh-pages, master, master /docs.","documentation_url":"https://docs.github.com/rest/reference/repos#update-information-about-a-github-pages-site"}
422
```

```
curl -X PUT https://api.github.com/repos/gesellix/pages-test/pages \
  -H 'Accept: application/vnd.github.v3+json' \
  -H 'Content-Type: application/json' \
  -H 'User-Agent: go-github' \
  -d '{"source":{"branch":"main","path":"/docs"}}' \
  -w "\n%{http_code}\n"

204
```

```
curl -X PUT https://api.github.com/repos/gesellix/pages-test/pages \
  -H 'Accept: application/vnd.github.v3+json'\
  -H 'Content-Type: application/json'\
  -H 'User-Agent: go-github'\
  -d '{"source":{"branch":"master","path":"/docs"}}'\
  -w "\n%{http_code}\n"

204
```

```
curl -X PUT https://api.github.com/repos/gesellix/pages-test/pages \
  -H 'Accept: application/vnd.github.v3+json'\
  -H 'Content-Type: application/json'\
  -H 'User-Agent: go-github'\
  -d '{"source":{"branch":"gh-pages","path":"/docs"}}'\
  -w "\n%{http_code}\n"

204
```

```
curl -X PUT https://api.github.com/repos/gesellix/pages-test/pages \
  -H 'Accept: application/vnd.github.v3+json' \
  -H 'Content-Type: application/json'\
  -H 'User-Agent: go-github'\
  -d '{"source":{"branch":"gh-pages","path":"/wiki"}}'\
  -w "\n%{http_code}\n"
{"message":"Invalid request.\n\nInvalid property /source: `/wiki` is not a possible value. Must be one of the following: /, /docs.","documentation_url":"https://docs.github.com/rest/reference/repos#update-information-about-a-github-pages-site"}
422
```

```
curl -X PUT https://api.github.com/repos/gesellix/pages-test/pages \
  -H 'Accept: application/vnd.github.v3+json'\
  -H 'Content-Type: application/json'\
  -H 'User-Agent: go-github'\
  -d '{"source":{"branch":"gh-pages","path":"/"}}'\
  -w "\n%{http_code}\n"

204
```


Pull request:
Support PagesSource as struct for update pages API
Closes #2406 


Patch:
diff --git a/github/github-accessors.go b/github/github-accessors.go
index da146bcb..2efe1d43 100644
--- a/github/github-accessors.go
+++ b/github/github-accessors.go
@@ -10790,12 +10790,12 @@ func (p *PagesUpdate) GetPublic() bool {
 	return *p.Public
 }
 
-// GetSource returns the Source field if it's non-nil, zero value otherwise.
-func (p *PagesUpdate) GetSource() string {
-	if p == nil || p.Source == nil {
-		return ""
+// GetSource returns the Source field.
+func (p *PagesUpdate) GetSource() *PagesSource {
+	if p == nil {
+		return nil
 	}
-	return *p.Source
+	return p.Source
 }
 
 // GetHook returns the Hook field.
diff --git a/github/repos_pages.go b/github/repos_pages.go
index 9b864eb0..737cec0f 100644
--- a/github/repos_pages.go
+++ b/github/repos_pages.go
@@ -93,8 +93,10 @@ type PagesUpdate struct {
 	// Leaving CNAME empty will remove the custom domain.
 	CNAME *string `json:"cname"`
 	// Source must include the branch name, and may optionally specify the subdirectory "/docs".
-	// Possible values are: "gh-pages", "master", and "master /docs".
-	Source *string `json:"source,omitempty"`
+	// Possible values for Source.Branch are usually "gh-pages", "main", and "master",
+	// or any other existing branch name.
+	// Possible values for Source.Path are: "/", and "/docs".
+	Source *PagesSource `json:"source,omitempty"`
 	// Public configures access controls for the site.
 	// If "true", the site will be accessible to anyone on the internet. If "false",
 	// the site will be accessible to anyone with read access to the repository that


Test patch:
diff --git a/github/github-accessors_test.go b/github/github-accessors_test.go
index 5d30ec96..ac370a0f 100644
--- a/github/github-accessors_test.go
+++ b/github/github-accessors_test.go
@@ -12643,10 +12643,7 @@ func TestPagesUpdate_GetPublic(tt *testing.T) {
 }
 
 func TestPagesUpdate_GetSource(tt *testing.T) {
-	var zeroValue string
-	p := &PagesUpdate{Source: &zeroValue}
-	p.GetSource()
-	p = &PagesUpdate{}
+	p := &PagesUpdate{}
 	p.GetSource()
 	p = nil
 	p.GetSource()
diff --git a/github/repos_pages_test.go b/github/repos_pages_test.go
index 46bffcff..ed17e735 100644
--- a/github/repos_pages_test.go
+++ b/github/repos_pages_test.go
@@ -76,7 +76,7 @@ func TestRepositoriesService_UpdatePages(t *testing.T) {
 
 	input := &PagesUpdate{
 		CNAME:  String("www.my-domain.com"),
-		Source: String("gh-pages"),
+		Source: &PagesSource{Branch: String("gh-pages")},
 	}
 
 	mux.HandleFunc("/repos/o/r/pages", func(w http.ResponseWriter, r *http.Request) {
@@ -84,12 +84,12 @@ func TestRepositoriesService_UpdatePages(t *testing.T) {
 		json.NewDecoder(r.Body).Decode(v)
 
 		testMethod(t, r, "PUT")
-		want := &PagesUpdate{CNAME: String("www.my-domain.com"), Source: String("gh-pages")}
+		want := &PagesUpdate{CNAME: String("www.my-domain.com"), Source: &PagesSource{Branch: String("gh-pages")}}
 		if !cmp.Equal(v, want) {
 			t.Errorf("Request body = %+v, want %+v", v, want)
 		}
 
-		fmt.Fprint(w, `{"cname":"www.my-domain.com","source":"gh-pages"}`)
+		fmt.Fprint(w, `{"cname":"www.my-domain.com","source":{"branch":"gh-pages"}}`)
 	})
 
 	ctx := context.Background()
@@ -114,7 +114,7 @@ func TestRepositoriesService_UpdatePages_NullCNAME(t *testing.T) {
 	defer teardown()
 
 	input := &PagesUpdate{
-		Source: String("gh-pages"),
+		Source: &PagesSource{Branch: String("gh-pages")},
 	}
 
 	mux.HandleFunc("/repos/o/r/pages", func(w http.ResponseWriter, r *http.Request) {
@@ -123,12 +123,12 @@ func TestRepositoriesService_UpdatePages_NullCNAME(t *testing.T) {
 			t.Fatalf("unable to read body: %v", err)
 		}
 
-		want := []byte(`{"cname":null,"source":"gh-pages"}` + "\n")
+		want := []byte(`{"cname":null,"source":{"branch":"gh-pages"}}` + "\n")
 		if !bytes.Equal(got, want) {
 			t.Errorf("Request body = %+v, want %+v", got, want)
 		}
 
-		fmt.Fprint(w, `{"cname":null,"source":"gh-pages"}`)
+		fmt.Fprint(w, `{"cname":null,"source":{"branch":"gh-pages"}}`)
 	})
 
 	ctx := context.Background()
@@ -393,12 +393,12 @@ func TestPagesUpdate_Marshal(t *testing.T) {
 
 	u := &PagesUpdate{
 		CNAME:  String("cname"),
-		Source: String("src"),
+		Source: &PagesSource{Path: String("src")},
 	}
 
 	want := `{
 		"cname": "cname",
-		"source": "src"
+		"source": { "path": "src" }
 	}`
 
 	testJSONMarshal(t, u, want)