From 4324bd5644f9f5e5bc2b640df4fffa5500a41e28 Mon Sep 17 00:00:00 2001 From: Dhananjay Mishra Date: Thu, 9 Oct 2025 17:37:57 +0000 Subject: [PATCH 1/6] feat: Add organization immutable releases settings API --- github/github-accessors.go | 8 + github/github-accessors_test.go | 11 + github/orgs_immutable_releases.go | 187 +++++++++++++++++ github/orgs_immutable_releases_test.go | 273 +++++++++++++++++++++++++ 4 files changed, 479 insertions(+) create mode 100644 github/orgs_immutable_releases.go create mode 100644 github/orgs_immutable_releases_test.go diff --git a/github/github-accessors.go b/github/github-accessors.go index 4371d0ca274..3cf86116374 100644 --- a/github/github-accessors.go +++ b/github/github-accessors.go @@ -10886,6 +10886,14 @@ func (i *IDPGroup) GetGroupName() string { return *i.GroupName } +// GetSelectedRepositoriesURL returns the SelectedRepositoriesURL field if it's non-nil, zero value otherwise. +func (i *ImmutableReleaseSettings) GetSelectedRepositoriesURL() string { + if i == nil || i.SelectedRepositoriesURL == nil { + return "" + } + return *i.SelectedRepositoriesURL +} + // GetAuthorsCount returns the AuthorsCount field if it's non-nil, zero value otherwise. func (i *Import) GetAuthorsCount() int { if i == nil || i.AuthorsCount == nil { diff --git a/github/github-accessors_test.go b/github/github-accessors_test.go index 2aa09771e4a..3184b549c5b 100644 --- a/github/github-accessors_test.go +++ b/github/github-accessors_test.go @@ -14121,6 +14121,17 @@ func TestIDPGroup_GetGroupName(tt *testing.T) { i.GetGroupName() } +func TestImmutableReleaseSettings_GetSelectedRepositoriesURL(tt *testing.T) { + tt.Parallel() + var zeroValue string + i := &ImmutableReleaseSettings{SelectedRepositoriesURL: &zeroValue} + i.GetSelectedRepositoriesURL() + i = &ImmutableReleaseSettings{} + i.GetSelectedRepositoriesURL() + i = nil + i.GetSelectedRepositoriesURL() +} + func TestImport_GetAuthorsCount(tt *testing.T) { tt.Parallel() var zeroValue int diff --git a/github/orgs_immutable_releases.go b/github/orgs_immutable_releases.go new file mode 100644 index 00000000000..10c3a0ed278 --- /dev/null +++ b/github/orgs_immutable_releases.go @@ -0,0 +1,187 @@ +// Copyright 2025 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package github + +import ( + "context" + "fmt" +) + +// ImmutableReleaseSettings represents the response from the immutable releases settings endpoint. +type ImmutableReleaseSettings struct { + // EnforcedRepositories specifies how immutable releases are enforced in the organization. + // Possible values include "all", "none", or "selected". + EnforcedRepositories string `json:"enforced_repositories,omitempty"` + // SelectedRepositoriesURL provides the API URL for managing the repositories + // selected for immutable releases enforcement when EnforcedRepositories is set to "selected". + SelectedRepositoriesURL *string `json:"selected_repositories_url,omitempty"` +} + +// ImmutableReleaseRepository for seting the immutable releases policy for repositories in an organization. +type ImmutableReleaseRepository struct { + // EnforcedRepositories specifies how immutable releases are enforced in the organization. + // Possible values include "all", "none", or "selected". + EnforcedRepositories string `json:"enforced_repositories"` + // An array of repository ids for which immutable releases enforcement should be applied. + // You can only provide a list of repository ids when the enforced_repositories is set to "selected" + SelectedRepositoriesIDs []int64 `json:"selected_repository_ids,omitempty"` +} + +// SelectedRepositories represents the request body for setting repositories. +type SelectedRepositories struct { + // An array of repository ids for which immutable releases enforcement should be applied. + // You can only provide a list of repository ids when the enforced_repositories is set to "selected" + SelectedRepositoryIDs []int64 `json:"selected_repository_ids"` +} + +// GetImmutableReleasesSettings gets immutable releases settings for an organization. +// +// This endpoint returns the immutable releases configuration that applies to repositories +// within the given organization. +// +// GitHub API docs: https://docs.github.com/rest/orgs/orgs#get-immutable-releases-settings-for-an-organization +// +//meta:operation GET /orgs/{org}/settings/immutable-releases +func (s *OrganizationsService) GetImmutableReleasesSettings(ctx context.Context, org string) (*ImmutableReleaseSettings, *Response, error) { + u := fmt.Sprintf("orgs/%v/settings/immutable-releases", org) + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + var settings *ImmutableReleaseSettings + resp, err := s.client.Do(ctx, req, &settings) + if err != nil { + return nil, resp, err + } + + return settings, resp, nil +} + +// SetImmutableReleasesPolicy sets immutable releases settings for an organization/ +// +// This endpoint sets the immutable releases policy for repositories in an organization. +// +// GitHub API docs: https://docs.github.com/rest/orgs/orgs#set-immutable-releases-settings-for-an-organization +// +//meta:operation PUT /orgs/{org}/settings/immutable-releases +func (s *OrganizationsService) SetImmutableReleasesPolicy(ctx context.Context, org string, opts *ImmutableReleaseRepository) (*Response, error) { + u := fmt.Sprintf("orgs/%v/settings/immutable-releases", org) + + req, err := s.client.NewRequest("PUT", u, opts) + if err != nil { + return nil, err + } + + resp, err := s.client.Do(ctx, req, nil) + if err != nil { + return resp, err + } + + return resp, nil +} + +// ListImmutableReleaseRepositories lists selected repositories for immutable releases enforcement. +// +// This endpoint gives a list of all the repositories that have been selected for immutable releases enforcement in an organization. +// +// GitHub API docs: https://docs.github.com/rest/orgs/orgs#list-selected-repositories-for-immutable-releases-enforcement +// +//meta:operation GET /orgs/{org}/settings/immutable-releases/repositories +func (s *OrganizationsService) ListImmutableReleaseRepositories(ctx context.Context, org string, opts *ListOptions) (*ListRepositories, *Response, error) { + u := fmt.Sprintf("orgs/%v/settings/immutable-releases/repositories", org) + + u, err := addOptions(u, opts) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + var repositories *ListRepositories + resp, err := s.client.Do(ctx, req, &repositories) + if err != nil { + return nil, resp, err + } + + return repositories, resp, nil +} + +// SetImmutableReleaseRepositories sets selected repositories for immutable releases enforcement. +// +// This endpoint replaces all repositories that have been selected for immutable releases enforcement in an organization. +// To use this endpoint, the organization immutable releases policy for enforced_repositories must be configured to selected. +// +// GitHub API docs: https://docs.github.com/rest/orgs/orgs#set-selected-repositories-for-immutable-releases-enforcement +// +//meta:operation PUT /orgs/{org}/settings/immutable-releases/repositories +func (s *OrganizationsService) SetImmutableReleaseRepositories(ctx context.Context, org string, opts *SelectedRepositories) (*Response, error) { + u := fmt.Sprintf("orgs/%v/settings/immutable-releases/repositories", org) + + req, err := s.client.NewRequest("PUT", u, opts) + if err != nil { + return nil, err + } + + resp, err := s.client.Do(ctx, req, nil) + if err != nil { + return resp, err + } + + return resp, nil +} + +// EnableRepositoryForImmutableRelease enable a selected repository for immutable releases in an organization. +// +// To add a repository to the list of selected repositories that are enforced for immutable releases in an organization. +// To use this endpoint, the organization immutable releases policy for enforced_repositories must be configured to selected. +// +// GitHub API docs: https://docs.github.com/rest/orgs/orgs#enable-a-selected-repository-for-immutable-releases-in-an-organization +// +//meta:operation PUT /orgs/{org}/settings/immutable-releases/repositories/{repository_id} +func (s *OrganizationsService) EnableRepositoryForImmutableRelease(ctx context.Context, org string, repoID int64) (*Response, error) { + u := fmt.Sprintf("orgs/%v/settings/immutable-releases/repositories/%v", org, repoID) + + req, err := s.client.NewRequest("PUT", u, nil) + if err != nil { + return nil, err + } + + resp, err := s.client.Do(ctx, req, nil) + if err != nil { + return resp, err + } + + return resp, nil +} + +// DisableRepositoryForImmutableRelease disable a selected repository for immutable releases in an organization. +// +// To remove a repository from the list of selected repositories that are enforced for immutable releases in an organization. +// To use this endpoint, the organization immutable releases policy for enforced_repositories must be configured to selected. +// +// GitHub API docs: https://docs.github.com/rest/orgs/orgs#disable-a-selected-repository-for-immutable-releases-in-an-organization +// +//meta:operation DELETE /orgs/{org}/settings/immutable-releases/repositories/{repository_id} +func (s *OrganizationsService) DisableRepositoryForImmutableRelease(ctx context.Context, org string, repoID int64) (*Response, error) { + u := fmt.Sprintf("orgs/%v/settings/immutable-releases/repositories/%v", org, repoID) + + req, err := s.client.NewRequest("DELETE", u, nil) + if err != nil { + return nil, err + } + + resp, err := s.client.Do(ctx, req, nil) + if err != nil { + return resp, err + } + + return resp, nil +} diff --git a/github/orgs_immutable_releases_test.go b/github/orgs_immutable_releases_test.go new file mode 100644 index 00000000000..a57ffb7e5ab --- /dev/null +++ b/github/orgs_immutable_releases_test.go @@ -0,0 +1,273 @@ +// Copyright 2025 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package github + +import ( + "encoding/json" + "fmt" + "net/http" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestOrganizationsService_GetImmutableReleasesSettings(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/orgs/o/settings/immutable-releases", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{ + "enforced_repositories": "selected", + "selected_repositories_url": "https://api.github.com/orgs/o/r" + }`) + }) + + ctx := t.Context() + settings, _, err := client.Organizations.GetImmutableReleasesSettings(ctx, "o") + if err != nil { + t.Errorf("Organizations.GetImmutableReleasesSettings returned error: %v", err) + } + + wantURL := "https://api.github.com/orgs/o/r" + want := &ImmutableReleaseSettings{ + EnforcedRepositories: "selected", + SelectedRepositoriesURL: &wantURL, + } + + if !cmp.Equal(settings, want) { + t.Errorf("Organizations.GetImmutableReleasesSettings returned %+v, want %+v", settings, want) + } + + const methodName = "GetImmutableReleasesSettings" + + testBadOptions(t, methodName, func() error { + _, _, err := client.Organizations.GetImmutableReleasesSettings(ctx, "\n") + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Organizations.GetImmutableReleasesSettings(ctx, "o") + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestOrganizationsService_SetImmutableReleasesPolicy(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + input := &ImmutableReleaseRepository{ + EnforcedRepositories: "selected", + } + + mux.HandleFunc("/orgs/o/settings/immutable-releases", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PUT") + + // Decode request body into map + var gotBody map[string]any + if err := json.NewDecoder(r.Body).Decode(&gotBody); err != nil { + t.Fatalf("Failed to decode request body: %v", err) + } + + // Expected body + wantBody := map[string]any{ + "enforced_repositories": "selected", + } + + if !cmp.Equal(gotBody, wantBody) { + t.Errorf("Request body = %+v, want %+v", gotBody, wantBody) + } + + w.WriteHeader(http.StatusOK) + fmt.Fprint(w, `{"enforced_repositories":"selected"}`) + }) + + ctx := t.Context() + resp, err := client.Organizations.SetImmutableReleasesPolicy(ctx, "o", input) + if err != nil { + t.Errorf("Organizations.SetImmutableReleasesPolicy returned error: %v", err) + } + + if resp.StatusCode != http.StatusOK { + t.Errorf("Expected status 200 OK, got %v", resp.StatusCode) + } + + const methodName = "SetImmutableReleasesPolicy" + + testBadOptions(t, methodName, func() error { + _, err := client.Organizations.SetImmutableReleasesPolicy(ctx, "\n", input) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + resp, err := client.Organizations.SetImmutableReleasesPolicy(ctx, "o", input) + return resp, err + }) +} + +func TestOrganizationsService_ListImmutableReleaseRepositories(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + responseBody := `{ + "total_count": 2, + "repositories": [ + {"id": 1, "name": "repo1"}, + {"id": 2, "name": "repo2"} + ] + }` + + mux.HandleFunc("/orgs/o/settings/immutable-releases/repositories", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, responseBody) + }) + + ctx := t.Context() + opts := &ListOptions{Page: 1, PerPage: 10} + repos, _, err := client.Organizations.ListImmutableReleaseRepositories(ctx, "o", opts) + if err != nil { + t.Errorf("Organizations.ListImmutableReleaseRepositories returned error: %v", err) + } + + want := &ListRepositories{ + TotalCount: Ptr(2), + Repositories: []*Repository{ + {ID: Ptr(int64(1)), Name: Ptr("repo1")}, + {ID: Ptr(int64(2)), Name: Ptr("repo2")}, + }, + } + + if !cmp.Equal(repos, want) { + t.Errorf("Organizations.ListImmutableReleaseRepositories returned %+v, want %+v", repos, want) + } + + const methodName = "ListImmutableReleaseRepositories" + + testBadOptions(t, methodName, func() error { + _, _, err := client.Organizations.ListImmutableReleaseRepositories(ctx, "\n", opts) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Organizations.ListImmutableReleaseRepositories(ctx, "o", opts) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestOrganizationsService_SetImmutableReleaseRepositories(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + input := &SelectedRepositories{ + SelectedRepositoryIDs: []int64{1, 2, 3}, + } + + mux.HandleFunc("/orgs/o/settings/immutable-releases/repositories", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PUT") + + var gotBody SelectedRepositories + if err := json.NewDecoder(r.Body).Decode(&gotBody); err != nil { + t.Fatalf("Failed to decode request body: %v", err) + } + + if !cmp.Equal(gotBody, *input) { + t.Errorf("Request body = %+v, want %+v", gotBody, *input) + } + + w.WriteHeader(http.StatusOK) + }) + + ctx := t.Context() + resp, err := client.Organizations.SetImmutableReleaseRepositories(ctx, "o", input) + if err != nil { + t.Errorf("Organizations.SetImmutableReleaseRepositories returned error: %v", err) + } + + if resp.StatusCode != http.StatusOK { + t.Errorf("Expected status 200 OK, got %v", resp.StatusCode) + } + + const methodName = "SetImmutableReleaseRepositories" + + testBadOptions(t, methodName, func() error { + _, err := client.Organizations.SetImmutableReleaseRepositories(ctx, "\n", input) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + return client.Organizations.SetImmutableReleaseRepositories(ctx, "o", input) + }) +} + +func TestOrganizationsService_EnableRepositoryForImmutableRelease(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + repoID := int64(42) + + mux.HandleFunc(fmt.Sprintf("/orgs/o/settings/immutable-releases/repositories/%v", repoID), func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PUT") + w.WriteHeader(http.StatusNoContent) + }) + + ctx := t.Context() + resp, err := client.Organizations.EnableRepositoryForImmutableRelease(ctx, "o", repoID) + if err != nil { + t.Errorf("EnableRepositoryForImmutableRelease returned error: %v", err) + } + if resp.StatusCode != http.StatusNoContent { + t.Errorf("Expected status 204 No Content, got %v", resp.StatusCode) + } + + const methodName = "EnableRepositoryForImmutableRelease" + + testBadOptions(t, methodName, func() error { + _, err := client.Organizations.EnableRepositoryForImmutableRelease(ctx, "o", -1) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + return client.Organizations.EnableRepositoryForImmutableRelease(ctx, "o", repoID) + }) +} + +func TestOrganizationsService_DisableRepositoryForImmutableRelease(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + repoID := int64(42) + + mux.HandleFunc(fmt.Sprintf("/orgs/o/settings/immutable-releases/repositories/%v", repoID), func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + w.WriteHeader(http.StatusNoContent) + }) + + ctx := t.Context() + resp, err := client.Organizations.DisableRepositoryForImmutableRelease(ctx, "o", repoID) + if err != nil { + t.Errorf("DisableRepositoryForImmutableRelease returned error: %v", err) + } + if resp.StatusCode != http.StatusNoContent { + t.Errorf("Expected status 204 No Content, got %v", resp.StatusCode) + } + + const methodName = "DisableRepositoryForImmutableRelease" + + testBadOptions(t, methodName, func() error { + _, err := client.Organizations.DisableRepositoryForImmutableRelease(ctx, "o", -1) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + return client.Organizations.DisableRepositoryForImmutableRelease(ctx, "o", repoID) + }) +} From 723c4016a4894a24512b7e35b7036ed95d7a1d1f Mon Sep 17 00:00:00 2001 From: Dhananjay Mishra Date: Thu, 9 Oct 2025 17:54:01 +0000 Subject: [PATCH 2/6] fix lint issue --- github/orgs_immutable_releases_test.go | 546 ++++++++++++------------- 1 file changed, 273 insertions(+), 273 deletions(-) diff --git a/github/orgs_immutable_releases_test.go b/github/orgs_immutable_releases_test.go index a57ffb7e5ab..5940c653690 100644 --- a/github/orgs_immutable_releases_test.go +++ b/github/orgs_immutable_releases_test.go @@ -1,273 +1,273 @@ -// Copyright 2025 The go-github AUTHORS. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "encoding/json" - "fmt" - "net/http" - "testing" - - "github.com/google/go-cmp/cmp" -) - -func TestOrganizationsService_GetImmutableReleasesSettings(t *testing.T) { - t.Parallel() - client, mux, _ := setup(t) - - mux.HandleFunc("/orgs/o/settings/immutable-releases", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - fmt.Fprint(w, `{ - "enforced_repositories": "selected", - "selected_repositories_url": "https://api.github.com/orgs/o/r" - }`) - }) - - ctx := t.Context() - settings, _, err := client.Organizations.GetImmutableReleasesSettings(ctx, "o") - if err != nil { - t.Errorf("Organizations.GetImmutableReleasesSettings returned error: %v", err) - } - - wantURL := "https://api.github.com/orgs/o/r" - want := &ImmutableReleaseSettings{ - EnforcedRepositories: "selected", - SelectedRepositoriesURL: &wantURL, - } - - if !cmp.Equal(settings, want) { - t.Errorf("Organizations.GetImmutableReleasesSettings returned %+v, want %+v", settings, want) - } - - const methodName = "GetImmutableReleasesSettings" - - testBadOptions(t, methodName, func() error { - _, _, err := client.Organizations.GetImmutableReleasesSettings(ctx, "\n") - return err - }) - - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Organizations.GetImmutableReleasesSettings(ctx, "o") - if got != nil { - t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) - } - return resp, err - }) -} - -func TestOrganizationsService_SetImmutableReleasesPolicy(t *testing.T) { - t.Parallel() - client, mux, _ := setup(t) - - input := &ImmutableReleaseRepository{ - EnforcedRepositories: "selected", - } - - mux.HandleFunc("/orgs/o/settings/immutable-releases", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "PUT") - - // Decode request body into map - var gotBody map[string]any - if err := json.NewDecoder(r.Body).Decode(&gotBody); err != nil { - t.Fatalf("Failed to decode request body: %v", err) - } - - // Expected body - wantBody := map[string]any{ - "enforced_repositories": "selected", - } - - if !cmp.Equal(gotBody, wantBody) { - t.Errorf("Request body = %+v, want %+v", gotBody, wantBody) - } - - w.WriteHeader(http.StatusOK) - fmt.Fprint(w, `{"enforced_repositories":"selected"}`) - }) - - ctx := t.Context() - resp, err := client.Organizations.SetImmutableReleasesPolicy(ctx, "o", input) - if err != nil { - t.Errorf("Organizations.SetImmutableReleasesPolicy returned error: %v", err) - } - - if resp.StatusCode != http.StatusOK { - t.Errorf("Expected status 200 OK, got %v", resp.StatusCode) - } - - const methodName = "SetImmutableReleasesPolicy" - - testBadOptions(t, methodName, func() error { - _, err := client.Organizations.SetImmutableReleasesPolicy(ctx, "\n", input) - return err - }) - - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - resp, err := client.Organizations.SetImmutableReleasesPolicy(ctx, "o", input) - return resp, err - }) -} - -func TestOrganizationsService_ListImmutableReleaseRepositories(t *testing.T) { - t.Parallel() - client, mux, _ := setup(t) - - responseBody := `{ - "total_count": 2, - "repositories": [ - {"id": 1, "name": "repo1"}, - {"id": 2, "name": "repo2"} - ] - }` - - mux.HandleFunc("/orgs/o/settings/immutable-releases/repositories", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "GET") - fmt.Fprint(w, responseBody) - }) - - ctx := t.Context() - opts := &ListOptions{Page: 1, PerPage: 10} - repos, _, err := client.Organizations.ListImmutableReleaseRepositories(ctx, "o", opts) - if err != nil { - t.Errorf("Organizations.ListImmutableReleaseRepositories returned error: %v", err) - } - - want := &ListRepositories{ - TotalCount: Ptr(2), - Repositories: []*Repository{ - {ID: Ptr(int64(1)), Name: Ptr("repo1")}, - {ID: Ptr(int64(2)), Name: Ptr("repo2")}, - }, - } - - if !cmp.Equal(repos, want) { - t.Errorf("Organizations.ListImmutableReleaseRepositories returned %+v, want %+v", repos, want) - } - - const methodName = "ListImmutableReleaseRepositories" - - testBadOptions(t, methodName, func() error { - _, _, err := client.Organizations.ListImmutableReleaseRepositories(ctx, "\n", opts) - return err - }) - - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Organizations.ListImmutableReleaseRepositories(ctx, "o", opts) - if got != nil { - t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) - } - return resp, err - }) -} - -func TestOrganizationsService_SetImmutableReleaseRepositories(t *testing.T) { - t.Parallel() - client, mux, _ := setup(t) - - input := &SelectedRepositories{ - SelectedRepositoryIDs: []int64{1, 2, 3}, - } - - mux.HandleFunc("/orgs/o/settings/immutable-releases/repositories", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "PUT") - - var gotBody SelectedRepositories - if err := json.NewDecoder(r.Body).Decode(&gotBody); err != nil { - t.Fatalf("Failed to decode request body: %v", err) - } - - if !cmp.Equal(gotBody, *input) { - t.Errorf("Request body = %+v, want %+v", gotBody, *input) - } - - w.WriteHeader(http.StatusOK) - }) - - ctx := t.Context() - resp, err := client.Organizations.SetImmutableReleaseRepositories(ctx, "o", input) - if err != nil { - t.Errorf("Organizations.SetImmutableReleaseRepositories returned error: %v", err) - } - - if resp.StatusCode != http.StatusOK { - t.Errorf("Expected status 200 OK, got %v", resp.StatusCode) - } - - const methodName = "SetImmutableReleaseRepositories" - - testBadOptions(t, methodName, func() error { - _, err := client.Organizations.SetImmutableReleaseRepositories(ctx, "\n", input) - return err - }) - - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - return client.Organizations.SetImmutableReleaseRepositories(ctx, "o", input) - }) -} - -func TestOrganizationsService_EnableRepositoryForImmutableRelease(t *testing.T) { - t.Parallel() - client, mux, _ := setup(t) - - repoID := int64(42) - - mux.HandleFunc(fmt.Sprintf("/orgs/o/settings/immutable-releases/repositories/%v", repoID), func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "PUT") - w.WriteHeader(http.StatusNoContent) - }) - - ctx := t.Context() - resp, err := client.Organizations.EnableRepositoryForImmutableRelease(ctx, "o", repoID) - if err != nil { - t.Errorf("EnableRepositoryForImmutableRelease returned error: %v", err) - } - if resp.StatusCode != http.StatusNoContent { - t.Errorf("Expected status 204 No Content, got %v", resp.StatusCode) - } - - const methodName = "EnableRepositoryForImmutableRelease" - - testBadOptions(t, methodName, func() error { - _, err := client.Organizations.EnableRepositoryForImmutableRelease(ctx, "o", -1) - return err - }) - - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - return client.Organizations.EnableRepositoryForImmutableRelease(ctx, "o", repoID) - }) -} - -func TestOrganizationsService_DisableRepositoryForImmutableRelease(t *testing.T) { - t.Parallel() - client, mux, _ := setup(t) - - repoID := int64(42) - - mux.HandleFunc(fmt.Sprintf("/orgs/o/settings/immutable-releases/repositories/%v", repoID), func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "DELETE") - w.WriteHeader(http.StatusNoContent) - }) - - ctx := t.Context() - resp, err := client.Organizations.DisableRepositoryForImmutableRelease(ctx, "o", repoID) - if err != nil { - t.Errorf("DisableRepositoryForImmutableRelease returned error: %v", err) - } - if resp.StatusCode != http.StatusNoContent { - t.Errorf("Expected status 204 No Content, got %v", resp.StatusCode) - } - - const methodName = "DisableRepositoryForImmutableRelease" - - testBadOptions(t, methodName, func() error { - _, err := client.Organizations.DisableRepositoryForImmutableRelease(ctx, "o", -1) - return err - }) - - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - return client.Organizations.DisableRepositoryForImmutableRelease(ctx, "o", repoID) - }) -} +// Copyright 2025 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package github + +import ( + "encoding/json" + "fmt" + "net/http" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestOrganizationsService_GetImmutableReleasesSettings(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/orgs/o/settings/immutable-releases", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{ + "enforced_repositories": "selected", + "selected_repositories_url": "https://api.github.com/orgs/o/r" + }`) + }) + + ctx := t.Context() + settings, _, err := client.Organizations.GetImmutableReleasesSettings(ctx, "o") + if err != nil { + t.Errorf("Organizations.GetImmutableReleasesSettings returned error: %v", err) + } + + wantURL := "https://api.github.com/orgs/o/r" + want := &ImmutableReleaseSettings{ + EnforcedRepositories: "selected", + SelectedRepositoriesURL: &wantURL, + } + + if !cmp.Equal(settings, want) { + t.Errorf("Organizations.GetImmutableReleasesSettings returned %+v, want %+v", settings, want) + } + + const methodName = "GetImmutableReleasesSettings" + + testBadOptions(t, methodName, func() error { + _, _, err := client.Organizations.GetImmutableReleasesSettings(ctx, "\n") + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Organizations.GetImmutableReleasesSettings(ctx, "o") + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestOrganizationsService_SetImmutableReleasesPolicy(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + input := &ImmutableReleaseRepository{ + EnforcedRepositories: "selected", + } + + mux.HandleFunc("/orgs/o/settings/immutable-releases", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PUT") + + // Decode request body into map + var gotBody map[string]any + if err := json.NewDecoder(r.Body).Decode(&gotBody); err != nil { + t.Fatalf("Failed to decode request body: %v", err) + } + + // Expected body + wantBody := map[string]any{ + "enforced_repositories": "selected", + } + + if !cmp.Equal(gotBody, wantBody) { + t.Errorf("Request body = %+v, want %+v", gotBody, wantBody) + } + + w.WriteHeader(http.StatusOK) + fmt.Fprint(w, `{"enforced_repositories":"selected"}`) + }) + + ctx := t.Context() + resp, err := client.Organizations.SetImmutableReleasesPolicy(ctx, "o", input) + if err != nil { + t.Errorf("Organizations.SetImmutableReleasesPolicy returned error: %v", err) + } + + if resp.StatusCode != http.StatusOK { + t.Errorf("Expected status 200 OK, got %v", resp.StatusCode) + } + + const methodName = "SetImmutableReleasesPolicy" + + testBadOptions(t, methodName, func() error { + _, err := client.Organizations.SetImmutableReleasesPolicy(ctx, "\n", input) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + resp, err := client.Organizations.SetImmutableReleasesPolicy(ctx, "o", input) + return resp, err + }) +} + +func TestOrganizationsService_ListImmutableReleaseRepositories(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + responseBody := `{ + "total_count": 2, + "repositories": [ + {"id": 1, "name": "repo1"}, + {"id": 2, "name": "repo2"} + ] + }` + + mux.HandleFunc("/orgs/o/settings/immutable-releases/repositories", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, responseBody) + }) + + ctx := t.Context() + opts := &ListOptions{Page: 1, PerPage: 10} + repos, _, err := client.Organizations.ListImmutableReleaseRepositories(ctx, "o", opts) + if err != nil { + t.Errorf("Organizations.ListImmutableReleaseRepositories returned error: %v", err) + } + + want := &ListRepositories{ + TotalCount: Ptr(2), + Repositories: []*Repository{ + {ID: Ptr(int64(1)), Name: Ptr("repo1")}, + {ID: Ptr(int64(2)), Name: Ptr("repo2")}, + }, + } + + if !cmp.Equal(repos, want) { + t.Errorf("Organizations.ListImmutableReleaseRepositories returned %+v, want %+v", repos, want) + } + + const methodName = "ListImmutableReleaseRepositories" + + testBadOptions(t, methodName, func() error { + _, _, err := client.Organizations.ListImmutableReleaseRepositories(ctx, "\n", opts) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Organizations.ListImmutableReleaseRepositories(ctx, "o", opts) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestOrganizationsService_SetImmutableReleaseRepositories(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + input := &SelectedRepositories{ + SelectedRepositoryIDs: []int64{1, 2, 3}, + } + + mux.HandleFunc("/orgs/o/settings/immutable-releases/repositories", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PUT") + + var gotBody SelectedRepositories + if err := json.NewDecoder(r.Body).Decode(&gotBody); err != nil { + t.Fatalf("Failed to decode request body: %v", err) + } + + if !cmp.Equal(gotBody, *input) { + t.Errorf("Request body = %+v, want %+v", gotBody, *input) + } + + w.WriteHeader(http.StatusOK) + }) + + ctx := t.Context() + resp, err := client.Organizations.SetImmutableReleaseRepositories(ctx, "o", input) + if err != nil { + t.Errorf("Organizations.SetImmutableReleaseRepositories returned error: %v", err) + } + + if resp.StatusCode != http.StatusOK { + t.Errorf("Expected status 200 OK, got %v", resp.StatusCode) + } + + const methodName = "SetImmutableReleaseRepositories" + + testBadOptions(t, methodName, func() error { + _, err := client.Organizations.SetImmutableReleaseRepositories(ctx, "\n", input) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + return client.Organizations.SetImmutableReleaseRepositories(ctx, "o", input) + }) +} + +func TestOrganizationsService_EnableRepositoryForImmutableRelease(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + repoID := int64(42) + + mux.HandleFunc(fmt.Sprintf("/orgs/o/settings/immutable-releases/repositories/%v", repoID), func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PUT") + w.WriteHeader(http.StatusNoContent) + }) + + ctx := t.Context() + resp, err := client.Organizations.EnableRepositoryForImmutableRelease(ctx, "o", repoID) + if err != nil { + t.Errorf("EnableRepositoryForImmutableRelease returned error: %v", err) + } + if resp.StatusCode != http.StatusNoContent { + t.Errorf("Expected status 204 No Content, got %v", resp.StatusCode) + } + + const methodName = "EnableRepositoryForImmutableRelease" + + testBadOptions(t, methodName, func() error { + _, err := client.Organizations.EnableRepositoryForImmutableRelease(ctx, "o", -1) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + return client.Organizations.EnableRepositoryForImmutableRelease(ctx, "o", repoID) + }) +} + +func TestOrganizationsService_DisableRepositoryForImmutableRelease(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + repoID := int64(42) + + mux.HandleFunc(fmt.Sprintf("/orgs/o/settings/immutable-releases/repositories/%v", repoID), func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + w.WriteHeader(http.StatusNoContent) + }) + + ctx := t.Context() + resp, err := client.Organizations.DisableRepositoryForImmutableRelease(ctx, "o", repoID) + if err != nil { + t.Errorf("DisableRepositoryForImmutableRelease returned error: %v", err) + } + if resp.StatusCode != http.StatusNoContent { + t.Errorf("Expected status 204 No Content, got %v", resp.StatusCode) + } + + const methodName = "DisableRepositoryForImmutableRelease" + + testBadOptions(t, methodName, func() error { + _, err := client.Organizations.DisableRepositoryForImmutableRelease(ctx, "o", -1) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + return client.Organizations.DisableRepositoryForImmutableRelease(ctx, "o", repoID) + }) +} From 98aab3d9c724bbb0a81bf746f9e1c9e8b625a042 Mon Sep 17 00:00:00 2001 From: Not-Dhananjay-Mishra Date: Fri, 10 Oct 2025 08:10:09 +0530 Subject: [PATCH 3/6] Refactor methods and update description --- github/orgs_immutable_releases.go | 47 +++++++++----------------- github/orgs_immutable_releases_test.go | 19 +++++------ 2 files changed, 24 insertions(+), 42 deletions(-) diff --git a/github/orgs_immutable_releases.go b/github/orgs_immutable_releases.go index 10c3a0ed278..aaaeedb5aef 100644 --- a/github/orgs_immutable_releases.go +++ b/github/orgs_immutable_releases.go @@ -12,9 +12,8 @@ import ( // ImmutableReleaseSettings represents the response from the immutable releases settings endpoint. type ImmutableReleaseSettings struct { - // EnforcedRepositories specifies how immutable releases are enforced in the organization. - // Possible values include "all", "none", or "selected". - EnforcedRepositories string `json:"enforced_repositories,omitempty"` + // EnforcedRepositories specifies how immutable releases are enforced in the organization. Possible values include "all", "none", or "selected". + EnforcedRepositories *string `json:"enforced_repositories,omitempty"` // SelectedRepositoriesURL provides the API URL for managing the repositories // selected for immutable releases enforcement when EnforcedRepositories is set to "selected". SelectedRepositoriesURL *string `json:"selected_repositories_url,omitempty"` @@ -22,25 +21,16 @@ type ImmutableReleaseSettings struct { // ImmutableReleaseRepository for seting the immutable releases policy for repositories in an organization. type ImmutableReleaseRepository struct { - // EnforcedRepositories specifies how immutable releases are enforced in the organization. - // Possible values include "all", "none", or "selected". - EnforcedRepositories string `json:"enforced_repositories"` + // EnforcedRepositories specifies how immutable releases are enforced in the organization. Possible values include "all", "none", or "selected". + EnforcedRepositories *string `json:"enforced_repositories,omitempty"` // An array of repository ids for which immutable releases enforcement should be applied. // You can only provide a list of repository ids when the enforced_repositories is set to "selected" - SelectedRepositoriesIDs []int64 `json:"selected_repository_ids,omitempty"` -} - -// SelectedRepositories represents the request body for setting repositories. -type SelectedRepositories struct { - // An array of repository ids for which immutable releases enforcement should be applied. - // You can only provide a list of repository ids when the enforced_repositories is set to "selected" - SelectedRepositoryIDs []int64 `json:"selected_repository_ids"` + SelectedRepositoryIDs []int64 `json:"selected_repository_ids,omitempty"` } // GetImmutableReleasesSettings gets immutable releases settings for an organization. // -// This endpoint returns the immutable releases configuration that applies to repositories -// within the given organization. +// This endpoint returns the immutable releases configuration that applies to repositories within the given organization. // // GitHub API docs: https://docs.github.com/rest/orgs/orgs#get-immutable-releases-settings-for-an-organization // @@ -62,14 +52,12 @@ func (s *OrganizationsService) GetImmutableReleasesSettings(ctx context.Context, return settings, resp, nil } -// SetImmutableReleasesPolicy sets immutable releases settings for an organization/ -// -// This endpoint sets the immutable releases policy for repositories in an organization. +// SetImmutableReleasesPolicy sets immutable releases settings for an organization. // // GitHub API docs: https://docs.github.com/rest/orgs/orgs#set-immutable-releases-settings-for-an-organization // -//meta:operation PUT /orgs/{org}/settings/immutable-releases -func (s *OrganizationsService) SetImmutableReleasesPolicy(ctx context.Context, org string, opts *ImmutableReleaseRepository) (*Response, error) { +// meta:operation PUT /orgs/{org}/settings/immutable-releases +func (s *OrganizationsService) SetImmutableReleasesPolicy(ctx context.Context, org string, opts ImmutableReleaseRepository) (*Response, error) { u := fmt.Sprintf("orgs/%v/settings/immutable-releases", org) req, err := s.client.NewRequest("PUT", u, opts) @@ -116,16 +104,15 @@ func (s *OrganizationsService) ListImmutableReleaseRepositories(ctx context.Cont // SetImmutableReleaseRepositories sets selected repositories for immutable releases enforcement. // -// This endpoint replaces all repositories that have been selected for immutable releases enforcement in an organization. -// To use this endpoint, the organization immutable releases policy for enforced_repositories must be configured to selected. +// Replaces all repositories selected for immutable releases enforcement in an organization. Requires the organization's immutable releases policy for enforced_repositories to be set to "selected". // // GitHub API docs: https://docs.github.com/rest/orgs/orgs#set-selected-repositories-for-immutable-releases-enforcement // //meta:operation PUT /orgs/{org}/settings/immutable-releases/repositories -func (s *OrganizationsService) SetImmutableReleaseRepositories(ctx context.Context, org string, opts *SelectedRepositories) (*Response, error) { +func (s *OrganizationsService) SetImmutableReleaseRepositories(ctx context.Context, org string, repositoryIDs []int64) (*Response, error) { u := fmt.Sprintf("orgs/%v/settings/immutable-releases/repositories", org) - req, err := s.client.NewRequest("PUT", u, opts) + req, err := s.client.NewRequest("PUT", u, repositoryIDs) if err != nil { return nil, err } @@ -138,10 +125,9 @@ func (s *OrganizationsService) SetImmutableReleaseRepositories(ctx context.Conte return resp, nil } -// EnableRepositoryForImmutableRelease enable a selected repository for immutable releases in an organization. +// EnableRepositoryForImmutableRelease enables a selected repository for immutable releases in an organization. // -// To add a repository to the list of selected repositories that are enforced for immutable releases in an organization. -// To use this endpoint, the organization immutable releases policy for enforced_repositories must be configured to selected. +// Adds a repository to the organization's selected list for immutable releases enforcement (requires enforced_repositories set to "selected"). // // GitHub API docs: https://docs.github.com/rest/orgs/orgs#enable-a-selected-repository-for-immutable-releases-in-an-organization // @@ -162,10 +148,9 @@ func (s *OrganizationsService) EnableRepositoryForImmutableRelease(ctx context.C return resp, nil } -// DisableRepositoryForImmutableRelease disable a selected repository for immutable releases in an organization. +// DisableRepositoryForImmutableRelease disables a selected repository for immutable releases in an organization. // -// To remove a repository from the list of selected repositories that are enforced for immutable releases in an organization. -// To use this endpoint, the organization immutable releases policy for enforced_repositories must be configured to selected. +// Removes a repository from the organization's selected list for immutable releases enforcement (requires enforced_repositories set to "selected"). // // GitHub API docs: https://docs.github.com/rest/orgs/orgs#disable-a-selected-repository-for-immutable-releases-in-an-organization // diff --git a/github/orgs_immutable_releases_test.go b/github/orgs_immutable_releases_test.go index 5940c653690..9e47e4fac80 100644 --- a/github/orgs_immutable_releases_test.go +++ b/github/orgs_immutable_releases_test.go @@ -34,7 +34,7 @@ func TestOrganizationsService_GetImmutableReleasesSettings(t *testing.T) { wantURL := "https://api.github.com/orgs/o/r" want := &ImmutableReleaseSettings{ - EnforcedRepositories: "selected", + EnforcedRepositories: Ptr("selected"), SelectedRepositoriesURL: &wantURL, } @@ -62,8 +62,8 @@ func TestOrganizationsService_SetImmutableReleasesPolicy(t *testing.T) { t.Parallel() client, mux, _ := setup(t) - input := &ImmutableReleaseRepository{ - EnforcedRepositories: "selected", + input := ImmutableReleaseRepository{ + EnforcedRepositories: Ptr("selected"), } mux.HandleFunc("/orgs/o/settings/immutable-releases", func(w http.ResponseWriter, r *http.Request) { @@ -167,20 +167,17 @@ func TestOrganizationsService_SetImmutableReleaseRepositories(t *testing.T) { t.Parallel() client, mux, _ := setup(t) - input := &SelectedRepositories{ - SelectedRepositoryIDs: []int64{1, 2, 3}, - } - + input := []int64{1, 2, 3} mux.HandleFunc("/orgs/o/settings/immutable-releases/repositories", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") - var gotBody SelectedRepositories + var gotBody []int64 if err := json.NewDecoder(r.Body).Decode(&gotBody); err != nil { t.Fatalf("Failed to decode request body: %v", err) } - if !cmp.Equal(gotBody, *input) { - t.Errorf("Request body = %+v, want %+v", gotBody, *input) + if !cmp.Equal(gotBody, input) { + t.Errorf("Request body = %+v, want %+v", gotBody, input) } w.WriteHeader(http.StatusOK) @@ -189,7 +186,7 @@ func TestOrganizationsService_SetImmutableReleaseRepositories(t *testing.T) { ctx := t.Context() resp, err := client.Organizations.SetImmutableReleaseRepositories(ctx, "o", input) if err != nil { - t.Errorf("Organizations.SetImmutableReleaseRepositories returned error: %v", err) + t.Fatalf("SetImmutableReleaseRepositories returned error: %v", err) } if resp.StatusCode != http.StatusOK { From 13c0e17bf428fc1ed0b6d91a3c8c341978380487 Mon Sep 17 00:00:00 2001 From: Dhananjay Mishra Date: Fri, 10 Oct 2025 02:47:39 +0000 Subject: [PATCH 4/6] fix lint issue --- github/github-accessors.go | 16 ++++++++++++++++ github/github-accessors_test.go | 22 ++++++++++++++++++++++ github/orgs_immutable_releases.go | 2 +- 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/github/github-accessors.go b/github/github-accessors.go index 3cf86116374..7d38c90500a 100644 --- a/github/github-accessors.go +++ b/github/github-accessors.go @@ -10886,6 +10886,22 @@ func (i *IDPGroup) GetGroupName() string { return *i.GroupName } +// GetEnforcedRepositories returns the EnforcedRepositories field if it's non-nil, zero value otherwise. +func (i *ImmutableReleaseRepository) GetEnforcedRepositories() string { + if i == nil || i.EnforcedRepositories == nil { + return "" + } + return *i.EnforcedRepositories +} + +// GetEnforcedRepositories returns the EnforcedRepositories field if it's non-nil, zero value otherwise. +func (i *ImmutableReleaseSettings) GetEnforcedRepositories() string { + if i == nil || i.EnforcedRepositories == nil { + return "" + } + return *i.EnforcedRepositories +} + // GetSelectedRepositoriesURL returns the SelectedRepositoriesURL field if it's non-nil, zero value otherwise. func (i *ImmutableReleaseSettings) GetSelectedRepositoriesURL() string { if i == nil || i.SelectedRepositoriesURL == nil { diff --git a/github/github-accessors_test.go b/github/github-accessors_test.go index 3184b549c5b..1b5963e7014 100644 --- a/github/github-accessors_test.go +++ b/github/github-accessors_test.go @@ -14121,6 +14121,28 @@ func TestIDPGroup_GetGroupName(tt *testing.T) { i.GetGroupName() } +func TestImmutableReleaseRepository_GetEnforcedRepositories(tt *testing.T) { + tt.Parallel() + var zeroValue string + i := &ImmutableReleaseRepository{EnforcedRepositories: &zeroValue} + i.GetEnforcedRepositories() + i = &ImmutableReleaseRepository{} + i.GetEnforcedRepositories() + i = nil + i.GetEnforcedRepositories() +} + +func TestImmutableReleaseSettings_GetEnforcedRepositories(tt *testing.T) { + tt.Parallel() + var zeroValue string + i := &ImmutableReleaseSettings{EnforcedRepositories: &zeroValue} + i.GetEnforcedRepositories() + i = &ImmutableReleaseSettings{} + i.GetEnforcedRepositories() + i = nil + i.GetEnforcedRepositories() +} + func TestImmutableReleaseSettings_GetSelectedRepositoriesURL(tt *testing.T) { tt.Parallel() var zeroValue string diff --git a/github/orgs_immutable_releases.go b/github/orgs_immutable_releases.go index aaaeedb5aef..0c71d3b6dfc 100644 --- a/github/orgs_immutable_releases.go +++ b/github/orgs_immutable_releases.go @@ -56,7 +56,7 @@ func (s *OrganizationsService) GetImmutableReleasesSettings(ctx context.Context, // // GitHub API docs: https://docs.github.com/rest/orgs/orgs#set-immutable-releases-settings-for-an-organization // -// meta:operation PUT /orgs/{org}/settings/immutable-releases +//meta:operation PUT /orgs/{org}/settings/immutable-releases func (s *OrganizationsService) SetImmutableReleasesPolicy(ctx context.Context, org string, opts ImmutableReleaseRepository) (*Response, error) { u := fmt.Sprintf("orgs/%v/settings/immutable-releases", org) From 9e52284e0413677acec689d11aa676731d8aca1e Mon Sep 17 00:00:00 2001 From: Dhananjay Mishra Date: Fri, 10 Oct 2025 03:00:42 +0000 Subject: [PATCH 5/6] Wrap selected_repository_ids in JSON object --- github/orgs_immutable_releases.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/github/orgs_immutable_releases.go b/github/orgs_immutable_releases.go index 0c71d3b6dfc..f031dba6553 100644 --- a/github/orgs_immutable_releases.go +++ b/github/orgs_immutable_releases.go @@ -28,6 +28,11 @@ type ImmutableReleaseRepository struct { SelectedRepositoryIDs []int64 `json:"selected_repository_ids,omitempty"` } +// setImmutableReleasesRepositoriesOptions represents the request body for setting repositories. +type setImmutableReleasesRepositoriesOptions struct { + SelectedRepositoryIDs []int64 `json:"selected_repository_ids"` +} + // GetImmutableReleasesSettings gets immutable releases settings for an organization. // // This endpoint returns the immutable releases configuration that applies to repositories within the given organization. @@ -112,7 +117,11 @@ func (s *OrganizationsService) ListImmutableReleaseRepositories(ctx context.Cont func (s *OrganizationsService) SetImmutableReleaseRepositories(ctx context.Context, org string, repositoryIDs []int64) (*Response, error) { u := fmt.Sprintf("orgs/%v/settings/immutable-releases/repositories", org) - req, err := s.client.NewRequest("PUT", u, repositoryIDs) + body := &setImmutableReleasesRepositoriesOptions{ + SelectedRepositoryIDs: repositoryIDs, + } + + req, err := s.client.NewRequest("PUT", u, body) if err != nil { return nil, err } From 211940299593258bc85e5b54a6a37d3f51af0417 Mon Sep 17 00:00:00 2001 From: Dhananjay Mishra Date: Fri, 10 Oct 2025 11:58:15 +0000 Subject: [PATCH 6/6] fix test --- github/orgs_immutable_releases.go | 6 ++--- github/orgs_immutable_releases_test.go | 36 ++++++++++++-------------- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/github/orgs_immutable_releases.go b/github/orgs_immutable_releases.go index f031dba6553..968b9d2b9ad 100644 --- a/github/orgs_immutable_releases.go +++ b/github/orgs_immutable_releases.go @@ -19,7 +19,7 @@ type ImmutableReleaseSettings struct { SelectedRepositoriesURL *string `json:"selected_repositories_url,omitempty"` } -// ImmutableReleaseRepository for seting the immutable releases policy for repositories in an organization. +// ImmutableReleaseRepository is for setting the immutable releases policy for repositories in an organization. type ImmutableReleaseRepository struct { // EnforcedRepositories specifies how immutable releases are enforced in the organization. Possible values include "all", "none", or "selected". EnforcedRepositories *string `json:"enforced_repositories,omitempty"` @@ -57,12 +57,12 @@ func (s *OrganizationsService) GetImmutableReleasesSettings(ctx context.Context, return settings, resp, nil } -// SetImmutableReleasesPolicy sets immutable releases settings for an organization. +// UpdateImmutableReleasesSettings sets immutable releases settings for an organization. // // GitHub API docs: https://docs.github.com/rest/orgs/orgs#set-immutable-releases-settings-for-an-organization // //meta:operation PUT /orgs/{org}/settings/immutable-releases -func (s *OrganizationsService) SetImmutableReleasesPolicy(ctx context.Context, org string, opts ImmutableReleaseRepository) (*Response, error) { +func (s *OrganizationsService) UpdateImmutableReleasesSettings(ctx context.Context, org string, opts ImmutableReleaseRepository) (*Response, error) { u := fmt.Sprintf("orgs/%v/settings/immutable-releases", org) req, err := s.client.NewRequest("PUT", u, opts) diff --git a/github/orgs_immutable_releases_test.go b/github/orgs_immutable_releases_test.go index 9e47e4fac80..eeb76e89f4f 100644 --- a/github/orgs_immutable_releases_test.go +++ b/github/orgs_immutable_releases_test.go @@ -58,7 +58,7 @@ func TestOrganizationsService_GetImmutableReleasesSettings(t *testing.T) { }) } -func TestOrganizationsService_SetImmutableReleasesPolicy(t *testing.T) { +func TestOrganizationsService_UpdateImmutableReleasesSettings(t *testing.T) { t.Parallel() client, mux, _ := setup(t) @@ -69,13 +69,9 @@ func TestOrganizationsService_SetImmutableReleasesPolicy(t *testing.T) { mux.HandleFunc("/orgs/o/settings/immutable-releases", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") - // Decode request body into map var gotBody map[string]any - if err := json.NewDecoder(r.Body).Decode(&gotBody); err != nil { - t.Fatalf("Failed to decode request body: %v", err) - } + assertNilError(t, json.NewDecoder(r.Body).Decode(&gotBody)) - // Expected body wantBody := map[string]any{ "enforced_repositories": "selected", } @@ -84,29 +80,29 @@ func TestOrganizationsService_SetImmutableReleasesPolicy(t *testing.T) { t.Errorf("Request body = %+v, want %+v", gotBody, wantBody) } - w.WriteHeader(http.StatusOK) + w.WriteHeader(http.StatusNoContent) fmt.Fprint(w, `{"enforced_repositories":"selected"}`) }) ctx := t.Context() - resp, err := client.Organizations.SetImmutableReleasesPolicy(ctx, "o", input) + resp, err := client.Organizations.UpdateImmutableReleasesSettings(ctx, "o", input) if err != nil { - t.Errorf("Organizations.SetImmutableReleasesPolicy returned error: %v", err) + t.Errorf("Organizations.UpdateImmutableReleasesSettings returned error: %v", err) } - if resp.StatusCode != http.StatusOK { - t.Errorf("Expected status 200 OK, got %v", resp.StatusCode) + if resp.StatusCode != http.StatusNoContent { + t.Errorf("Expected status 204 No Content, got %v", resp.StatusCode) } - const methodName = "SetImmutableReleasesPolicy" + const methodName = "UpdateImmutableReleasesSettings" testBadOptions(t, methodName, func() error { - _, err := client.Organizations.SetImmutableReleasesPolicy(ctx, "\n", input) + _, err := client.Organizations.UpdateImmutableReleasesSettings(ctx, "\n", input) return err }) testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - resp, err := client.Organizations.SetImmutableReleasesPolicy(ctx, "o", input) + resp, err := client.Organizations.UpdateImmutableReleasesSettings(ctx, "o", input) return resp, err }) } @@ -171,16 +167,16 @@ func TestOrganizationsService_SetImmutableReleaseRepositories(t *testing.T) { mux.HandleFunc("/orgs/o/settings/immutable-releases/repositories", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") - var gotBody []int64 + var gotBody setImmutableReleasesRepositoriesOptions if err := json.NewDecoder(r.Body).Decode(&gotBody); err != nil { t.Fatalf("Failed to decode request body: %v", err) } - if !cmp.Equal(gotBody, input) { - t.Errorf("Request body = %+v, want %+v", gotBody, input) + if !cmp.Equal(gotBody.SelectedRepositoryIDs, input) { + t.Errorf("Request body = %+v, want %+v", gotBody.SelectedRepositoryIDs, input) } - w.WriteHeader(http.StatusOK) + w.WriteHeader(http.StatusNoContent) }) ctx := t.Context() @@ -189,8 +185,8 @@ func TestOrganizationsService_SetImmutableReleaseRepositories(t *testing.T) { t.Fatalf("SetImmutableReleaseRepositories returned error: %v", err) } - if resp.StatusCode != http.StatusOK { - t.Errorf("Expected status 200 OK, got %v", resp.StatusCode) + if resp.StatusCode != http.StatusNoContent { + t.Errorf("Expected status 204 No Content, got %v", resp.StatusCode) } const methodName = "SetImmutableReleaseRepositories"