From 5069e18584f43a5d1f78e557e8ff8d8e130a6f36 Mon Sep 17 00:00:00 2001 From: Steve Hipwell Date: Tue, 14 Apr 2026 16:51:30 +0100 Subject: [PATCH 1/4] feat: Refactor repositories download contents Signed-off-by: Steve Hipwell --- github/repos_contents.go | 85 ++++------- github/repos_contents_test.go | 258 ++++++++++------------------------ 2 files changed, 101 insertions(+), 242 deletions(-) diff --git a/github/repos_contents.go b/github/repos_contents.go index 0c2ac3bf25f..c54176f49c5 100644 --- a/github/repos_contents.go +++ b/github/repos_contents.go @@ -17,7 +17,6 @@ import ( "io" "net/http" "net/url" - "path" "strings" ) @@ -137,40 +136,8 @@ func (s *RepositoriesService) GetReadme(ctx context.Context, owner, repo string, // //meta:operation GET /repos/{owner}/{repo}/contents/{path} func (s *RepositoriesService) DownloadContents(ctx context.Context, owner, repo, filepath string, opts *RepositoryContentGetOptions) (io.ReadCloser, *Response, error) { - dir := path.Dir(filepath) - filename := path.Base(filepath) - fileContent, _, resp, err := s.GetContents(ctx, owner, repo, filepath, opts) - if err == nil && fileContent != nil { - content, err := fileContent.GetContent() - if err == nil && content != "" { - return io.NopCloser(strings.NewReader(content)), resp, nil - } - } - - _, dirContents, resp, err := s.GetContents(ctx, owner, repo, dir, opts) - if err != nil { - return nil, resp, err - } - - for _, contents := range dirContents { - if contents.GetName() == filename { - if contents.GetDownloadURL() == "" { - return nil, resp, fmt.Errorf("no download link found for %v", filepath) - } - dlReq, err := http.NewRequestWithContext(ctx, "GET", *contents.DownloadURL, nil) - if err != nil { - return nil, resp, err - } - dlResp, err := s.client.client.Do(dlReq) - if err != nil { - return nil, &Response{Response: dlResp}, err - } - - return dlResp.Body, &Response{Response: dlResp}, nil - } - } - - return nil, resp, fmt.Errorf("no file named %v found in %v", filename, dir) + rc, _, resp, err := s.DownloadContentsWithMeta(ctx, owner, repo, filepath, opts) + return rc, resp, err } // DownloadContentsWithMeta is identical to DownloadContents but additionally @@ -186,40 +153,36 @@ func (s *RepositoriesService) DownloadContents(ctx context.Context, owner, repo, // //meta:operation GET /repos/{owner}/{repo}/contents/{path} func (s *RepositoriesService) DownloadContentsWithMeta(ctx context.Context, owner, repo, filepath string, opts *RepositoryContentGetOptions) (io.ReadCloser, *RepositoryContent, *Response, error) { - dir := path.Dir(filepath) - filename := path.Base(filepath) fileContent, _, resp, err := s.GetContents(ctx, owner, repo, filepath, opts) - if err == nil && fileContent != nil { - content, err := fileContent.GetContent() - if err == nil && content != "" { - return io.NopCloser(strings.NewReader(content)), fileContent, resp, nil - } + if err != nil { + return nil, nil, resp, err + } + + if fileContent == nil { + return nil, nil, resp, fmt.Errorf("no file content found at path %v in %v/%v", filepath, owner, repo) + } + + content, err := fileContent.GetContent() + if err == nil && content != "" { + return io.NopCloser(strings.NewReader(content)), fileContent, resp, nil } - _, dirContents, resp, err := s.GetContents(ctx, owner, repo, dir, opts) + downloadURL := fileContent.GetDownloadURL() + if downloadURL == "" { + return nil, fileContent, resp, fmt.Errorf("could not get download url for path %v in %v/%v", filepath, owner, repo) + } + + dlReq, err := http.NewRequestWithContext(ctx, "GET", downloadURL, nil) if err != nil { - return nil, nil, resp, err + return nil, fileContent, resp, err } - for _, contents := range dirContents { - if contents.GetName() == filename { - if contents.GetDownloadURL() == "" { - return nil, contents, resp, fmt.Errorf("no download link found for %v", filepath) - } - dlReq, err := http.NewRequestWithContext(ctx, "GET", *contents.DownloadURL, nil) - if err != nil { - return nil, contents, resp, err - } - dlResp, err := s.client.client.Do(dlReq) - if err != nil { - return nil, contents, &Response{Response: dlResp}, err - } - - return dlResp.Body, contents, &Response{Response: dlResp}, nil - } + dlResp, err := s.client.client.Do(dlReq) + if err != nil { + return nil, fileContent, &Response{Response: dlResp}, err } - return nil, nil, resp, fmt.Errorf("no file named %v found in %v", filename, dir) + return dlResp.Body, fileContent, &Response{Response: dlResp}, nil } // GetContents can return either the metadata and content of a single file diff --git a/github/repos_contents_test.go b/github/repos_contents_test.go index 113aad6ebc4..7527677973f 100644 --- a/github/repos_contents_test.go +++ b/github/repos_contents_test.go @@ -126,77 +126,17 @@ func TestRepositoriesService_GetReadme(t *testing.T) { }) } -func TestRepositoriesService_DownloadContents_SuccessForFile(t *testing.T) { +func TestRepositoriesService_DownloadContents_Success(t *testing.T) { t.Parallel() - client, mux, serverURL := setup(t) - - mux.HandleFunc("/repos/o/r/contents/d/f", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - fmt.Fprint(w, `{ - "type": "file", - "name": "f", - "content": "foo", - "download_url": "`+serverURL+baseURLPath+`/download/f" - }`) - }) - - ctx := t.Context() - r, resp, err := client.Repositories.DownloadContents(ctx, "o", "r", "d/f", nil) - if err != nil { - t.Errorf("Repositories.DownloadContents returned error: %v", err) - } - - if got, want := resp.Response.StatusCode, http.StatusOK; got != want { - t.Errorf("Repositories.DownloadContents returned status code %v, want %v", got, want) - } - - bytes, err := io.ReadAll(r) - if err != nil { - t.Errorf("Error reading response body: %v", err) - } - r.Close() - - if got, want := string(bytes), "foo"; got != want { - t.Errorf("Repositories.DownloadContents returned %v, want %v", got, want) - } - - const methodName = "DownloadContents" - testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Repositories.DownloadContents(ctx, "\n", "\n", "\n", nil) - return err - }) - - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Repositories.DownloadContents(ctx, "o", "r", "d/f", nil) - if got != nil { - t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) - } - return resp, err - }) -} - -func TestRepositoriesService_DownloadContents_SuccessForDirectory(t *testing.T) { - t.Parallel() - client, mux, serverURL := setup(t) + client, mux, _ := setup(t) mux.HandleFunc("/repos/o/r/contents/d/f", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{ - "type": "file", - "name": "f" - }`) - }) - mux.HandleFunc("/repos/o/r/contents/d", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - fmt.Fprint(w, `[{ - "type": "file", - "name": "f", - "download_url": "`+serverURL+baseURLPath+`/download/f" - }]`) - }) - mux.HandleFunc("/download/f", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - fmt.Fprint(w, "foo") + "type": "file", + "name": "f", + "content": "foo" +}`) }) ctx := t.Context() @@ -234,52 +174,6 @@ func TestRepositoriesService_DownloadContents_SuccessForDirectory(t *testing.T) }) } -func TestRepositoriesService_DownloadContents_FailedResponse(t *testing.T) { - t.Parallel() - client, mux, serverURL := setup(t) - - mux.HandleFunc("/repos/o/r/contents/d/f", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - fmt.Fprint(w, `{ - "type": "file", - "name": "f" - }`) - }) - mux.HandleFunc("/repos/o/r/contents/d", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - fmt.Fprint(w, `[{ - "type": "file", - "name": "f", - "download_url": "`+serverURL+baseURLPath+`/download/f" - }]`) - }) - mux.HandleFunc("/download/f", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - w.WriteHeader(http.StatusInternalServerError) - fmt.Fprint(w, "foo error") - }) - - ctx := t.Context() - r, resp, err := client.Repositories.DownloadContents(ctx, "o", "r", "d/f", nil) - if err != nil { - t.Errorf("Repositories.DownloadContents returned error: %v", err) - } - - if got, want := resp.Response.StatusCode, http.StatusInternalServerError; got != want { - t.Errorf("Repositories.DownloadContents returned status code %v, want %v", got, want) - } - - bytes, err := io.ReadAll(r) - if err != nil { - t.Errorf("Error reading response body: %v", err) - } - r.Close() - - if got, want := string(bytes), "foo error"; got != want { - t.Errorf("Repositories.DownloadContents returned %v, want %v", got, want) - } -} - func TestRepositoriesService_DownloadContents_NoDownloadURL(t *testing.T) { t.Parallel() client, mux, _ := setup(t) @@ -287,18 +181,9 @@ func TestRepositoriesService_DownloadContents_NoDownloadURL(t *testing.T) { mux.HandleFunc("/repos/o/r/contents/d/f", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{ - "type": "file", - "name": "f", - "content": "" - }`) - }) - mux.HandleFunc("/repos/o/r/contents/d", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - fmt.Fprint(w, `[{ - "type": "file", - "name": "f", - "content": "" - }]`) + "type": "file", + "name": "f" +}`) }) ctx := t.Context() @@ -312,26 +197,17 @@ func TestRepositoriesService_DownloadContents_NoDownloadURL(t *testing.T) { } if reader != nil { - t.Error("Repositories.DownloadContents did not return expected reader") + t.Error("Repositories.DownloadContents returned unexpected reader") } } -func TestRepositoriesService_DownloadContents_NoFile(t *testing.T) { +func TestRepositoriesService_DownloadContents_GetContentsError(t *testing.T) { t.Parallel() client, mux, _ := setup(t) mux.HandleFunc("/repos/o/r/contents/d/f", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") - fmt.Fprint(w, `{ - "type": "file", - "name": "f", - "content": "" - }`) - }) - - mux.HandleFunc("/repos/o/r/contents/d", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - fmt.Fprint(w, `[]`) + w.WriteHeader(http.StatusNotFound) }) ctx := t.Context() @@ -345,22 +221,21 @@ func TestRepositoriesService_DownloadContents_NoFile(t *testing.T) { } if reader != nil { - t.Error("Repositories.DownloadContents did not return expected reader") + t.Error("Repositories.DownloadContents returned unexpected reader") } } -func TestRepositoriesService_DownloadContentsWithMeta_SuccessForFile(t *testing.T) { +func TestRepositoriesService_DownloadContentsWithMeta_SuccessWithContent(t *testing.T) { t.Parallel() - client, mux, serverURL := setup(t) + client, mux, _ := setup(t) mux.HandleFunc("/repos/o/r/contents/d/f", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{ - "type": "file", - "name": "f", - "download_url": "`+serverURL+baseURLPath+`/download/f", - "content": "foo" - }`) + "type": "file", + "name": "f", + "content": "foo" +}`) }) ctx := t.Context() @@ -409,17 +284,17 @@ func TestRepositoriesService_DownloadContentsWithMeta_SuccessForFile(t *testing. }) } -func TestRepositoriesService_DownloadContentsWithMeta_SuccessForDirectory(t *testing.T) { +func TestRepositoriesService_DownloadContentsWithMeta_SuccessViaDownloadURL(t *testing.T) { t.Parallel() client, mux, serverURL := setup(t) - mux.HandleFunc("/repos/o/r/contents/d", func(w http.ResponseWriter, r *http.Request) { + mux.HandleFunc("/repos/o/r/contents/d/f", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") - fmt.Fprint(w, `[{ - "type": "file", - "name": "f", - "download_url": "`+serverURL+baseURLPath+`/download/f" - }]`) + fmt.Fprintf(w, `{ + "type": "file", + "name": "f", + "download_url": "%v/download/f" +}`, serverURL+baseURLPath) }) mux.HandleFunc("/download/f", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") @@ -459,29 +334,19 @@ func TestRepositoriesService_DownloadContentsWithMeta_FailedResponse(t *testing. t.Parallel() client, mux, serverURL := setup(t) - downloadURL := fmt.Sprintf("%v%v/download/f", serverURL, baseURLPath) - mux.HandleFunc("/repos/o/r/contents/d/f", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") - fmt.Fprint(w, `{ - "type": "file", - "name": "f", - "download_url": "`+downloadURL+`" - }`) + fmt.Fprintf(w, `{ + "type": "file", + "name": "f", + "download_url": "%v/download/f" +}`, serverURL+baseURLPath) }) mux.HandleFunc("/download/f", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") w.WriteHeader(http.StatusInternalServerError) fmt.Fprint(w, "foo error") }) - mux.HandleFunc("/repos/o/r/contents/d", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - fmt.Fprint(w, `[{ - "type": "file", - "name": "f", - "download_url": "`+downloadURL+`" - }]`) - }) ctx := t.Context() r, c, resp, err := client.Repositories.DownloadContentsWithMeta(ctx, "o", "r", "d/f", nil) @@ -519,17 +384,9 @@ func TestRepositoriesService_DownloadContentsWithMeta_NoDownloadURL(t *testing.T mux.HandleFunc("/repos/o/r/contents/d/f", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") fmt.Fprint(w, `{ - "type": "file", - "name": "f", - }`) - }) - mux.HandleFunc("/repos/o/r/contents/d", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - fmt.Fprint(w, `[{ - "type": "file", - "name": "f", - "content": "" - }]`) + "type": "file", + "name": "f" +}`) }) ctx := t.Context() @@ -539,7 +396,7 @@ func TestRepositoriesService_DownloadContentsWithMeta_NoDownloadURL(t *testing.T } if reader != nil { - t.Error("Repositories.DownloadContentsWithMeta did not return expected reader") + t.Error("Repositories.DownloadContentsWithMeta returned unexpected reader") } if resp == nil { @@ -551,24 +408,63 @@ func TestRepositoriesService_DownloadContentsWithMeta_NoDownloadURL(t *testing.T } } -func TestRepositoriesService_DownloadContentsWithMeta_NoFile(t *testing.T) { +func TestRepositoriesService_DownloadContentsWithMeta_GetContentsError(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/repos/o/r/contents/d/f", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + w.WriteHeader(http.StatusNotFound) + }) + + ctx := t.Context() + reader, contents, resp, err := client.Repositories.DownloadContentsWithMeta(ctx, "o", "r", "d/f", nil) + if err == nil { + t.Error("Repositories.DownloadContentsWithMeta did not return expected error") + } + + if reader != nil { + t.Error("Repositories.DownloadContentsWithMeta returned unexpected reader") + } + + if resp == nil { + t.Error("Repositories.DownloadContentsWithMeta did not return expected response") + } + + if contents != nil { + t.Error("Repositories.DownloadContentsWithMeta returned unexpected content") + } +} + +func TestRepositoriesService_DownloadContentsWithMeta_NilFileContent(t *testing.T) { t.Parallel() client, mux, _ := setup(t) mux.HandleFunc("/repos/o/r/contents/d", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "GET") - fmt.Fprint(w, `[]`) + fmt.Fprint(w, `[{ + "type": "file", + "name": "f" +}]`) }) ctx := t.Context() - _, _, resp, err := client.Repositories.DownloadContentsWithMeta(ctx, "o", "r", "d/f", nil) + reader, contents, resp, err := client.Repositories.DownloadContentsWithMeta(ctx, "o", "r", "d", nil) if err == nil { t.Error("Repositories.DownloadContentsWithMeta did not return expected error") } + if reader != nil { + t.Error("Repositories.DownloadContentsWithMeta returned unexpected reader") + } + if resp == nil { t.Error("Repositories.DownloadContentsWithMeta did not return expected response") } + + if contents != nil { + t.Error("Repositories.DownloadContentsWithMeta returned unexpected content") + } } func TestRepositoriesService_GetContents_File(t *testing.T) { From eaa3b4a82e9d964546a2ae0777ff2dc92ede3a48 Mon Sep 17 00:00:00 2001 From: Steve Hipwell Date: Tue, 14 Apr 2026 17:30:32 +0100 Subject: [PATCH 2/4] fixup! feat: Refactor repositories download contents --- openapi_operations.yaml | 90 +++++++++++++++++++++++++++++++++---- tools/metadata/main_test.go | 11 +++-- 2 files changed, 86 insertions(+), 15 deletions(-) diff --git a/openapi_operations.yaml b/openapi_operations.yaml index a5ca34f280d..70716fbba74 100644 --- a/openapi_operations.yaml +++ b/openapi_operations.yaml @@ -27,7 +27,7 @@ operation_overrides: documentation_url: https://docs.github.com/rest/pages/pages#request-a-github-pages-build - name: GET /repos/{owner}/{repo}/pages/builds/{build_id} documentation_url: https://docs.github.com/rest/pages/pages#get-github-pages-build -openapi_commit: 4e819bd9aa9411232e1c34e7d1ffaaffc224e94b +openapi_commit: e6a345665a64530821d4ebcd07e7805a0cdeff09 openapi_operations: - name: GET / documentation_url: https://docs.github.com/rest/meta/meta#github-api-root @@ -586,6 +586,21 @@ openapi_operations: documentation_url: https://docs.github.com/enterprise-cloud@latest//rest/actions/oidc#set-the-github-actions-oidc-custom-issuer-policy-for-an-enterprise openapi_files: - descriptions/ghec/ghec.json + - name: GET /enterprises/{enterprise}/actions/oidc/customization/properties/repo + documentation_url: https://docs.github.com/rest/actions/oidc#list-oidc-custom-property-inclusions-for-an-enterprise + openapi_files: + - descriptions/api.github.com/api.github.com.json + - descriptions/ghec/ghec.json + - name: POST /enterprises/{enterprise}/actions/oidc/customization/properties/repo + documentation_url: https://docs.github.com/rest/actions/oidc#create-an-oidc-custom-property-inclusion-for-an-enterprise + openapi_files: + - descriptions/api.github.com/api.github.com.json + - descriptions/ghec/ghec.json + - name: DELETE /enterprises/{enterprise}/actions/oidc/customization/properties/repo/{custom_property_name} + documentation_url: https://docs.github.com/rest/actions/oidc#delete-an-oidc-custom-property-inclusion-for-an-enterprise + openapi_files: + - descriptions/api.github.com/api.github.com.json + - descriptions/ghec/ghec.json - name: GET /enterprises/{enterprise}/actions/permissions documentation_url: https://docs.github.com/enterprise-cloud@latest//rest/actions/permissions#get-github-actions-permissions-for-an-enterprise openapi_files: @@ -1025,20 +1040,24 @@ openapi_operations: openapi_files: - descriptions/ghec/ghec.json - name: GET /enterprises/{enterprise}/copilot/metrics/reports/enterprise-1-day - documentation_url: https://docs.github.com/enterprise-cloud@latest//rest/copilot/copilot-usage-metrics#get-copilot-enterprise-usage-metrics-for-a-specific-day + documentation_url: https://docs.github.com/rest/copilot/copilot-usage-metrics#get-copilot-enterprise-usage-metrics-for-a-specific-day openapi_files: + - descriptions/api.github.com/api.github.com.json - descriptions/ghec/ghec.json - name: GET /enterprises/{enterprise}/copilot/metrics/reports/enterprise-28-day/latest - documentation_url: https://docs.github.com/enterprise-cloud@latest//rest/copilot/copilot-usage-metrics#get-copilot-enterprise-usage-metrics + documentation_url: https://docs.github.com/rest/copilot/copilot-usage-metrics#get-copilot-enterprise-usage-metrics openapi_files: + - descriptions/api.github.com/api.github.com.json - descriptions/ghec/ghec.json - name: GET /enterprises/{enterprise}/copilot/metrics/reports/users-1-day - documentation_url: https://docs.github.com/enterprise-cloud@latest//rest/copilot/copilot-usage-metrics#get-copilot-users-usage-metrics-for-a-specific-day + documentation_url: https://docs.github.com/rest/copilot/copilot-usage-metrics#get-copilot-users-usage-metrics-for-a-specific-day openapi_files: + - descriptions/api.github.com/api.github.com.json - descriptions/ghec/ghec.json - name: GET /enterprises/{enterprise}/copilot/metrics/reports/users-28-day/latest - documentation_url: https://docs.github.com/enterprise-cloud@latest//rest/copilot/copilot-usage-metrics#get-copilot-users-usage-metrics + documentation_url: https://docs.github.com/rest/copilot/copilot-usage-metrics#get-copilot-users-usage-metrics openapi_files: + - descriptions/api.github.com/api.github.com.json - descriptions/ghec/ghec.json - name: GET /enterprises/{enterprise}/dependabot/alerts documentation_url: https://docs.github.com/rest/dependabot/alerts#list-dependabot-alerts-for-an-enterprise @@ -1046,6 +1065,10 @@ openapi_operations: - descriptions/api.github.com/api.github.com.json - descriptions/ghec/ghec.json - descriptions/ghes-3.20/ghes-3.20.json + - name: GET /enterprises/{enterprise}/dismissal-requests/secret-scanning + documentation_url: https://docs.github.com/enterprise-cloud@latest//rest/secret-scanning/alert-dismissal-requests#list-alert-dismissal-requests-for-secret-scanning-for-an-enterprise + openapi_files: + - descriptions/ghec/ghec.json - name: GET /enterprises/{enterprise}/enterprise-roles documentation_url: https://docs.github.com/enterprise-cloud@latest//rest/enterprise-admin/enterprise-roles#get-all-enterprise-roles-for-an-enterprise openapi_files: @@ -1955,6 +1978,21 @@ openapi_operations: openapi_files: - descriptions/api.github.com/api.github.com.json - descriptions/ghec/ghec.json + - name: GET /orgs/{org}/actions/oidc/customization/properties/repo + documentation_url: https://docs.github.com/rest/actions/oidc#list-oidc-custom-property-inclusions-for-an-organization + openapi_files: + - descriptions/api.github.com/api.github.com.json + - descriptions/ghec/ghec.json + - name: POST /orgs/{org}/actions/oidc/customization/properties/repo + documentation_url: https://docs.github.com/rest/actions/oidc#create-an-oidc-custom-property-inclusion-for-an-organization + openapi_files: + - descriptions/api.github.com/api.github.com.json + - descriptions/ghec/ghec.json + - name: DELETE /orgs/{org}/actions/oidc/customization/properties/repo/{custom_property_name} + documentation_url: https://docs.github.com/rest/actions/oidc#delete-an-oidc-custom-property-inclusion-for-an-organization + openapi_files: + - descriptions/api.github.com/api.github.com.json + - descriptions/ghec/ghec.json - name: GET /orgs/{org}/actions/oidc/customization/sub documentation_url: https://docs.github.com/rest/actions/oidc#get-the-customization-template-for-an-oidc-subject-claim-for-an-organization openapi_files: @@ -2653,6 +2691,36 @@ openapi_operations: openapi_files: - descriptions/api.github.com/api.github.com.json - descriptions/ghec/ghec.json + - name: GET /orgs/{org}/copilot/coding-agent/permissions + documentation_url: https://docs.github.com/rest/copilot/copilot-coding-agent-management#get-copilot-coding-agent-permissions-for-an-organization + openapi_files: + - descriptions/api.github.com/api.github.com.json + - descriptions/ghec/ghec.json + - name: PUT /orgs/{org}/copilot/coding-agent/permissions + documentation_url: https://docs.github.com/rest/copilot/copilot-coding-agent-management#set-copilot-coding-agent-permissions-for-an-organization + openapi_files: + - descriptions/api.github.com/api.github.com.json + - descriptions/ghec/ghec.json + - name: GET /orgs/{org}/copilot/coding-agent/permissions/repositories + documentation_url: https://docs.github.com/rest/copilot/copilot-coding-agent-management#list-repositories-enabled-for-copilot-coding-agent-in-an-organization + openapi_files: + - descriptions/api.github.com/api.github.com.json + - descriptions/ghec/ghec.json + - name: PUT /orgs/{org}/copilot/coding-agent/permissions/repositories + documentation_url: https://docs.github.com/rest/copilot/copilot-coding-agent-management#set-selected-repositories-for-copilot-coding-agent-in-an-organization + openapi_files: + - descriptions/api.github.com/api.github.com.json + - descriptions/ghec/ghec.json + - name: DELETE /orgs/{org}/copilot/coding-agent/permissions/repositories/{repository_id} + documentation_url: https://docs.github.com/rest/copilot/copilot-coding-agent-management#disable-a-repository-for-copilot-coding-agent-in-an-organization + openapi_files: + - descriptions/api.github.com/api.github.com.json + - descriptions/ghec/ghec.json + - name: PUT /orgs/{org}/copilot/coding-agent/permissions/repositories/{repository_id} + documentation_url: https://docs.github.com/rest/copilot/copilot-coding-agent-management#enable-a-repository-for-copilot-coding-agent-in-an-organization + openapi_files: + - descriptions/api.github.com/api.github.com.json + - descriptions/ghec/ghec.json - name: GET /orgs/{org}/copilot/content_exclusion documentation_url: https://docs.github.com/rest/copilot/copilot-content-exclusion-management#get-copilot-content-exclusion-rules-for-an-organization openapi_files: @@ -2669,20 +2737,24 @@ openapi_operations: - descriptions/api.github.com/api.github.com.json - descriptions/ghec/ghec.json - name: GET /orgs/{org}/copilot/metrics/reports/organization-1-day - documentation_url: https://docs.github.com/enterprise-cloud@latest//rest/copilot/copilot-usage-metrics#get-copilot-organization-usage-metrics-for-a-specific-day + documentation_url: https://docs.github.com/rest/copilot/copilot-usage-metrics#get-copilot-organization-usage-metrics-for-a-specific-day openapi_files: + - descriptions/api.github.com/api.github.com.json - descriptions/ghec/ghec.json - name: GET /orgs/{org}/copilot/metrics/reports/organization-28-day/latest - documentation_url: https://docs.github.com/enterprise-cloud@latest//rest/copilot/copilot-usage-metrics#get-copilot-organization-usage-metrics + documentation_url: https://docs.github.com/rest/copilot/copilot-usage-metrics#get-copilot-organization-usage-metrics openapi_files: + - descriptions/api.github.com/api.github.com.json - descriptions/ghec/ghec.json - name: GET /orgs/{org}/copilot/metrics/reports/users-1-day - documentation_url: https://docs.github.com/enterprise-cloud@latest//rest/copilot/copilot-usage-metrics#get-copilot-organization-users-usage-metrics-for-a-specific-day + documentation_url: https://docs.github.com/rest/copilot/copilot-usage-metrics#get-copilot-organization-users-usage-metrics-for-a-specific-day openapi_files: + - descriptions/api.github.com/api.github.com.json - descriptions/ghec/ghec.json - name: GET /orgs/{org}/copilot/metrics/reports/users-28-day/latest - documentation_url: https://docs.github.com/enterprise-cloud@latest//rest/copilot/copilot-usage-metrics#get-copilot-organization-users-usage-metrics + documentation_url: https://docs.github.com/rest/copilot/copilot-usage-metrics#get-copilot-organization-users-usage-metrics openapi_files: + - descriptions/api.github.com/api.github.com.json - descriptions/ghec/ghec.json - name: GET /orgs/{org}/credential-authorizations documentation_url: https://docs.github.com/enterprise-cloud@latest//rest/orgs/orgs#list-saml-sso-authorizations-for-an-organization diff --git a/tools/metadata/main_test.go b/tools/metadata/main_test.go index 703c2d1d7cb..7951bce6b63 100644 --- a/tools/metadata/main_test.go +++ b/tools/metadata/main_test.go @@ -362,13 +362,12 @@ func newTestServer(t *testing.T, ref string, files map[string]any) *httptest.Ser descriptionsContent = append(descriptionsContent, &github.RepositoryContent{ Name: github.Ptr(path.Base(path.Dir(name))), }) + dlURL := server.URL + "/dl/" + name mux.HandleFunc( - path.Join(repoPath, "contents/descriptions", path.Dir(name)), - jsonHandler(refQuery, []*github.RepositoryContent{ - { - Name: github.Ptr(path.Base(name)), - DownloadURL: github.Ptr(server.URL + "/dl/" + name), - }, + path.Join(repoPath, "contents/descriptions", name), + jsonHandler(refQuery, &github.RepositoryContent{ + Name: github.Ptr(path.Base(name)), + DownloadURL: github.Ptr(dlURL), }), ) mux.HandleFunc( From 52eb7b3edb2d50c9d96f28255ebd69244c6731c0 Mon Sep 17 00:00:00 2001 From: Steve Hipwell Date: Wed, 15 Apr 2026 08:39:47 +0100 Subject: [PATCH 3/4] fixup! feat: Refactor repositories download contents --- tools/metadata/main_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/metadata/main_test.go b/tools/metadata/main_test.go index 7951bce6b63..4cb2436cb60 100644 --- a/tools/metadata/main_test.go +++ b/tools/metadata/main_test.go @@ -367,7 +367,7 @@ func newTestServer(t *testing.T, ref string, files map[string]any) *httptest.Ser path.Join(repoPath, "contents/descriptions", name), jsonHandler(refQuery, &github.RepositoryContent{ Name: github.Ptr(path.Base(name)), - DownloadURL: github.Ptr(dlURL), + DownloadURL: &dlURL, }), ) mux.HandleFunc( From 7312075ca22c4852704dc846a7a79d4948dab7ad Mon Sep 17 00:00:00 2001 From: Steve Hipwell Date: Wed, 15 Apr 2026 12:46:03 +0100 Subject: [PATCH 4/4] fixup! feat: Refactor repositories download contents --- tools/metadata/main_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/metadata/main_test.go b/tools/metadata/main_test.go index 4cb2436cb60..e9b656190a6 100644 --- a/tools/metadata/main_test.go +++ b/tools/metadata/main_test.go @@ -362,12 +362,11 @@ func newTestServer(t *testing.T, ref string, files map[string]any) *httptest.Ser descriptionsContent = append(descriptionsContent, &github.RepositoryContent{ Name: github.Ptr(path.Base(path.Dir(name))), }) - dlURL := server.URL + "/dl/" + name mux.HandleFunc( path.Join(repoPath, "contents/descriptions", name), jsonHandler(refQuery, &github.RepositoryContent{ Name: github.Ptr(path.Base(name)), - DownloadURL: &dlURL, + DownloadURL: github.Ptr(server.URL + "/dl/" + name), }), ) mux.HandleFunc(