From 896a9d8abfeedb0e866350b956a326109d3fc2fe Mon Sep 17 00:00:00 2001 From: maishivamhoo123 Date: Tue, 23 Dec 2025 02:15:27 +0530 Subject: [PATCH 1/4] github: use omitzero for RepositoryRuleset.BypassActors --- github/enterprise_rules.go | 30 +--------- github/enterprise_rules_test.go | 67 ----------------------- github/orgs_rules.go | 30 +--------- github/orgs_rules_test.go | 58 -------------------- github/repos_rules.go | 90 ------------------------------ github/repos_rules_test.go | 97 --------------------------------- github/rules.go | 2 +- 7 files changed, 7 insertions(+), 367 deletions(-) diff --git a/github/enterprise_rules.go b/github/enterprise_rules.go index 33485824f7e..03906b721e1 100644 --- a/github/enterprise_rules.go +++ b/github/enterprise_rules.go @@ -76,38 +76,14 @@ func (s *EnterpriseService) UpdateRepositoryRuleset(ctx context.Context, enterpr return rs, resp, nil } -// UpdateRepositoryRulesetClearBypassActor clears the bypass actors for a repository ruleset for the specified enterprise. -// -// This function is necessary as the UpdateRepositoryRuleset function does not marshal ByPassActor if passed as an empty array. -// -// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/enterprise-admin/rules#update-an-enterprise-repository-ruleset -// -//meta:operation PUT /enterprises/{enterprise}/rulesets/{ruleset_id} -func (s *EnterpriseService) UpdateRepositoryRulesetClearBypassActor(ctx context.Context, enterprise string, rulesetID int64) (*Response, error) { - u := fmt.Sprintf("enterprises/%v/rulesets/%v", enterprise, rulesetID) - - rsClearBypassActor := rulesetClearBypassActors{ - BypassActors: []*BypassActor{}, - } - - req, err := s.client.NewRequest("PUT", u, rsClearBypassActor) - if err != nil { - return nil, err - } - - resp, err := s.client.Do(ctx, req, nil) - if err != nil { - return resp, err - } - - return resp, nil -} - // DeleteRepositoryRuleset deletes a repository ruleset from the specified enterprise. // // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/enterprise-admin/rules#delete-an-enterprise-repository-ruleset // +// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/enterprise-admin/rules#update-an-enterprise-repository-ruleset +// //meta:operation DELETE /enterprises/{enterprise}/rulesets/{ruleset_id} +//meta:operation PUT /enterprises/{enterprise}/rulesets/{ruleset_id} func (s *EnterpriseService) DeleteRepositoryRuleset(ctx context.Context, enterprise string, rulesetID int64) (*Response, error) { u := fmt.Sprintf("enterprises/%v/rulesets/%v", enterprise, rulesetID) diff --git a/github/enterprise_rules_test.go b/github/enterprise_rules_test.go index b72c758a53b..ea227825dc7 100644 --- a/github/enterprise_rules_test.go +++ b/github/enterprise_rules_test.go @@ -1769,73 +1769,6 @@ func TestEnterpriseService_UpdateRepositoryRuleset(t *testing.T) { }) } -func TestEnterpriseService_UpdateRepositoryRulesetClearBypassActor(t *testing.T) { - t.Parallel() - client, mux, _ := setup(t) - - mux.HandleFunc("/enterprises/e/rulesets/84", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "PUT") - testBody(t, r, `{"bypass_actors":[]}`+"\n") - fmt.Fprint(w, `{ - "id": 84, - "name": "test ruleset", - "target": "branch", - "source_type": "Enterprise", - "source": "e", - "enforcement": "active", - "bypass_mode": "none", - "conditions": { - "organization_name": { - "include": [ - "important_organization", - "another_important_organization" - ], - "exclude": [ - "unimportant_organization" - ] - }, - "repository_name": { - "include": [ - "important_repository", - "another_important_repository" - ], - "exclude": [ - "unimportant_repository" - ], - "protected": true - }, - "ref_name": { - "include": [ - "refs/heads/main", - "refs/heads/master" - ], - "exclude": [ - "refs/heads/dev*" - ] - } - }, - "rules": [ - { - "type": "creation" - } - ] - }`) - }) - - ctx := t.Context() - - _, err := client.Enterprise.UpdateRepositoryRulesetClearBypassActor(ctx, "e", 84) - if err != nil { - t.Errorf("Enterprise.UpdateRepositoryRulesetClearBypassActor returned error: %v \n", err) - } - - const methodName = "UpdateRepositoryRulesetClearBypassActor" - - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - return client.Enterprise.UpdateRepositoryRulesetClearBypassActor(ctx, "e", 84) - }) -} - func TestEnterpriseService_DeleteRepositoryRuleset(t *testing.T) { t.Parallel() client, mux, _ := setup(t) diff --git a/github/orgs_rules.go b/github/orgs_rules.go index 2b6a79387e3..75e003a73a2 100644 --- a/github/orgs_rules.go +++ b/github/orgs_rules.go @@ -103,38 +103,14 @@ func (s *OrganizationsService) UpdateRepositoryRuleset(ctx context.Context, org return rs, resp, nil } -// UpdateRepositoryRulesetClearBypassActor clears the bypass actors for a repository ruleset for the specified organization. -// -// This function is necessary as the UpdateRepositoryRuleset function does not marshal ByPassActor if passed as an empty array. -// -// GitHub API docs: https://docs.github.com/rest/orgs/rules#update-an-organization-repository-ruleset -// -//meta:operation PUT /orgs/{org}/rulesets/{ruleset_id} -func (s *OrganizationsService) UpdateRepositoryRulesetClearBypassActor(ctx context.Context, org string, rulesetID int64) (*Response, error) { - u := fmt.Sprintf("orgs/%v/rulesets/%v", org, rulesetID) - - rsClearBypassActor := rulesetClearBypassActors{ - BypassActors: []*BypassActor{}, - } - - req, err := s.client.NewRequest("PUT", u, rsClearBypassActor) - if err != nil { - return nil, err - } - - resp, err := s.client.Do(ctx, req, nil) - if err != nil { - return resp, err - } - - return resp, nil -} - // DeleteRepositoryRuleset deletes a repository ruleset from the specified organization. // // GitHub API docs: https://docs.github.com/rest/orgs/rules#delete-an-organization-repository-ruleset // +// GitHub API docs: https://docs.github.com/rest/orgs/rules#update-an-organization-repository-ruleset +// //meta:operation DELETE /orgs/{org}/rulesets/{ruleset_id} +//meta:operation PUT /orgs/{org}/rulesets/{ruleset_id} func (s *OrganizationsService) DeleteRepositoryRuleset(ctx context.Context, org string, rulesetID int64) (*Response, error) { u := fmt.Sprintf("orgs/%v/rulesets/%v", org, rulesetID) diff --git a/github/orgs_rules_test.go b/github/orgs_rules_test.go index 03f634ab4d8..12dedde99c1 100644 --- a/github/orgs_rules_test.go +++ b/github/orgs_rules_test.go @@ -1587,64 +1587,6 @@ func TestOrganizationsService_UpdateRepositoryRulesetWithRepoProp(t *testing.T) }) } -func TestOrganizationsService_UpdateRepositoryRulesetClearBypassActor(t *testing.T) { - t.Parallel() - client, mux, _ := setup(t) - - mux.HandleFunc("/orgs/o/rulesets/21", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "PUT") - testBody(t, r, `{"bypass_actors":[]}`+"\n") - fmt.Fprint(w, `{ - "id": 21, - "name": "test ruleset", - "target": "branch", - "source_type": "Organization", - "source": "o", - "enforcement": "active", - "bypass_mode": "none", - "conditions": { - "repository_name": { - "include": [ - "important_repository", - "another_important_repository" - ], - "exclude": [ - "unimportant_repository" - ], - "protected": true - }, - "ref_name": { - "include": [ - "refs/heads/main", - "refs/heads/master" - ], - "exclude": [ - "refs/heads/dev*" - ] - } - }, - "rules": [ - { - "type": "creation" - } - ] - }`) - }) - - ctx := t.Context() - - _, err := client.Organizations.UpdateRepositoryRulesetClearBypassActor(ctx, "o", 21) - if err != nil { - t.Errorf("Organizations.UpdateRepositoryRulesetClearBypassActor returned error: %v \n", err) - } - - const methodName = "UpdateRepositoryRulesetClearBypassActor" - - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - return client.Organizations.UpdateRepositoryRulesetClearBypassActor(ctx, "o", 21) - }) -} - func TestOrganizationsService_DeleteRepositoryRuleset(t *testing.T) { t.Parallel() client, mux, _ := setup(t) diff --git a/github/repos_rules.go b/github/repos_rules.go index 8c1f4980e3f..b02df31316d 100644 --- a/github/repos_rules.go +++ b/github/repos_rules.go @@ -10,29 +10,6 @@ import ( "fmt" ) -// rulesetNoOmitBypassActors represents a GitHub ruleset object. The struct does not omit bypassActors if the field is nil or an empty array is passed. -type rulesetNoOmitBypassActors struct { - ID *int64 `json:"id,omitempty"` - Name string `json:"name"` - Target *RulesetTarget `json:"target,omitempty"` - SourceType *RulesetSourceType `json:"source_type,omitempty"` - Source string `json:"source"` - Enforcement RulesetEnforcement `json:"enforcement"` - BypassActors []*BypassActor `json:"bypass_actors"` - CurrentUserCanBypass *BypassMode `json:"current_user_can_bypass,omitempty"` - NodeID *string `json:"node_id,omitempty"` - Links *RepositoryRulesetLinks `json:"_links,omitempty"` - Conditions *RepositoryRulesetConditions `json:"conditions,omitempty"` - Rules *RepositoryRulesetRules `json:"rules,omitempty"` - UpdatedAt *Timestamp `json:"updated_at,omitempty"` - CreatedAt *Timestamp `json:"created_at,omitempty"` -} - -// rulesetClearBypassActors is used to clear the bypass actors when modifying a GitHub ruleset object. -type rulesetClearBypassActors struct { - BypassActors []*BypassActor `json:"bypass_actors"` -} - // GetRulesForBranch gets all the repository rules that apply to the specified branch. // // GitHub API docs: https://docs.github.com/rest/repos/rules#get-rules-for-a-branch @@ -164,73 +141,6 @@ func (s *RepositoriesService) UpdateRuleset(ctx context.Context, owner, repo str return rs, resp, nil } -// UpdateRulesetClearBypassActor clears the bypass actors for a repository ruleset for the specified repository. -// -// This function is necessary as the UpdateRuleset function does not marshal ByPassActor if passed as an empty array. -// -// GitHub API docs: https://docs.github.com/rest/repos/rules#update-a-repository-ruleset -// -//meta:operation PUT /repos/{owner}/{repo}/rulesets/{ruleset_id} -func (s *RepositoriesService) UpdateRulesetClearBypassActor(ctx context.Context, owner, repo string, rulesetID int64) (*Response, error) { - u := fmt.Sprintf("repos/%v/%v/rulesets/%v", owner, repo, rulesetID) - - rsClearBypassActor := rulesetClearBypassActors{ - BypassActors: []*BypassActor{}, - } - - req, err := s.client.NewRequest("PUT", u, rsClearBypassActor) - if err != nil { - return nil, err - } - - resp, err := s.client.Do(ctx, req, nil) - if err != nil { - return resp, err - } - - return resp, nil -} - -// UpdateRulesetNoBypassActor updates a repository ruleset for the specified repository. -// -// This function is necessary as the UpdateRuleset function does not marshal ByPassActor if passed as an empty array. -// -// Deprecated: Use UpdateRulesetClearBypassActor instead. -// -// GitHub API docs: https://docs.github.com/rest/repos/rules#update-a-repository-ruleset -// -//meta:operation PUT /repos/{owner}/{repo}/rulesets/{ruleset_id} -func (s *RepositoriesService) UpdateRulesetNoBypassActor(ctx context.Context, owner, repo string, rulesetID int64, ruleset RepositoryRuleset) (*RepositoryRuleset, *Response, error) { - u := fmt.Sprintf("repos/%v/%v/rulesets/%v", owner, repo, rulesetID) - - rsNoBypassActor := rulesetNoOmitBypassActors{ - ID: ruleset.ID, - Name: ruleset.Name, - Target: ruleset.Target, - SourceType: ruleset.SourceType, - Source: ruleset.Source, - Enforcement: ruleset.Enforcement, - BypassActors: ruleset.BypassActors, - NodeID: ruleset.NodeID, - Links: ruleset.Links, - Conditions: ruleset.Conditions, - Rules: ruleset.Rules, - } - - req, err := s.client.NewRequest("PUT", u, rsNoBypassActor) - if err != nil { - return nil, nil, err - } - - var rs *RepositoryRuleset - resp, err := s.client.Do(ctx, req, &rs) - if err != nil { - return nil, resp, err - } - - return rs, resp, nil -} - // DeleteRuleset deletes a repository ruleset for the specified repository. // // GitHub API docs: https://docs.github.com/rest/repos/rules#delete-a-repository-ruleset diff --git a/github/repos_rules_test.go b/github/repos_rules_test.go index 4b93d0bf14e..efc102b67a7 100644 --- a/github/repos_rules_test.go +++ b/github/repos_rules_test.go @@ -454,103 +454,6 @@ func TestRepositoriesService_UpdateRuleset(t *testing.T) { }) } -func TestRepositoriesService_UpdateRulesetClearBypassActor(t *testing.T) { - t.Parallel() - client, mux, _ := setup(t) - - mux.HandleFunc("/repos/o/repo/rulesets/42", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "PUT") - testBody(t, r, `{"bypass_actors":[]}`+"\n") - fmt.Fprint(w, `{ - "id": 42, - "name": "ruleset", - "source_type": "Repository", - "source": "o/repo", - "enforcement": "active" - "conditions": { - "ref_name": { - "include": [ - "refs/heads/main", - "refs/heads/master" - ], - "exclude": [ - "refs/heads/dev*" - ] - } - }, - "rules": [ - { - "type": "creation" - } - ] - }`) - }) - - ctx := t.Context() - - _, err := client.Repositories.UpdateRulesetClearBypassActor(ctx, "o", "repo", 42) - if err != nil { - t.Errorf("Repositories.UpdateRulesetClearBypassActor returned error: %v \n", err) - } - - const methodName = "UpdateRulesetClearBypassActor" - - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - return client.Repositories.UpdateRulesetClearBypassActor(ctx, "o", "repo", 42) - }) -} - -func TestRepositoriesService_UpdateRulesetNoBypassActor(t *testing.T) { - t.Parallel() - client, mux, _ := setup(t) - - rs := RepositoryRuleset{ - Name: "ruleset", - Source: "o/repo", - Enforcement: RulesetEnforcementActive, - } - - mux.HandleFunc("/repos/o/repo/rulesets/42", func(w http.ResponseWriter, r *http.Request) { - testMethod(t, r, "PUT") - fmt.Fprint(w, `{ - "id": 42, - "name": "ruleset", - "source_type": "Repository", - "source": "o/repo", - "enforcement": "active" - }`) - }) - - ctx := t.Context() - - ruleSet, _, err := client.Repositories.UpdateRulesetNoBypassActor(ctx, "o", "repo", 42, rs) - if err != nil { - t.Errorf("Repositories.UpdateRulesetNoBypassActor returned error: %v \n", err) - } - - want := &RepositoryRuleset{ - ID: Ptr(int64(42)), - Name: "ruleset", - SourceType: Ptr(RulesetSourceTypeRepository), - Source: "o/repo", - Enforcement: RulesetEnforcementActive, - } - - if !cmp.Equal(ruleSet, want) { - t.Errorf("Repositories.UpdateRulesetNoBypassActor returned %+v, want %+v", ruleSet, want) - } - - const methodName = "UpdateRulesetNoBypassActor" - - testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { - got, resp, err := client.Repositories.UpdateRulesetNoBypassActor(ctx, "o", "repo", 42, RepositoryRuleset{}) - if got != nil { - t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) - } - return resp, err - }) -} - func TestRepositoriesService_DeleteRuleset(t *testing.T) { t.Parallel() client, mux, _ := setup(t) diff --git a/github/rules.go b/github/rules.go index 420f4feb509..99b4c3aa2a9 100644 --- a/github/rules.go +++ b/github/rules.go @@ -192,7 +192,7 @@ type RepositoryRuleset struct { SourceType *RulesetSourceType `json:"source_type,omitempty"` Source string `json:"source"` Enforcement RulesetEnforcement `json:"enforcement"` - BypassActors []*BypassActor `json:"bypass_actors,omitempty"` + BypassActors []*BypassActor `json:"bypass_actors,omitzero"` CurrentUserCanBypass *BypassMode `json:"current_user_can_bypass,omitempty"` NodeID *string `json:"node_id,omitempty"` Links *RepositoryRulesetLinks `json:"_links,omitempty"` From b554c5aa40d5318c6305f936238971a2d011cb89 Mon Sep 17 00:00:00 2001 From: maishivamhoo123 Date: Tue, 23 Dec 2025 08:35:57 +0530 Subject: [PATCH 2/4] test: add tests for omitzero behavior on BypassActors --- github/enterprise_rules_test.go | 58 +++++++++++++++++++++++++ github/orgs_rules_test.go | 75 +++++++++++++++++++++++++++++++++ github/repos_rules_test.go | 73 ++++++++++++++++++++++++++++++++ 3 files changed, 206 insertions(+) diff --git a/github/enterprise_rules_test.go b/github/enterprise_rules_test.go index ea227825dc7..19ae2620265 100644 --- a/github/enterprise_rules_test.go +++ b/github/enterprise_rules_test.go @@ -6,6 +6,7 @@ package github import ( + "encoding/json" "fmt" "net/http" "testing" @@ -384,6 +385,63 @@ func TestEnterpriseService_CreateRepositoryRuleset_OrgNameRepoName(t *testing.T) }) } +func TestEnterpriseService_UpdateRepositoryRuleset_OmitZero_Nil(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/enterprises/e/rulesets/84", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PUT") + + // Verify "bypass_actors" key is NOT present + var v map[string]any + if err := json.NewDecoder(r.Body).Decode(&v); err != nil { + t.Errorf("could not decode body: %v", err) + } + + if _, ok := v["bypass_actors"]; ok { + t.Error("Request body contained 'bypass_actors', expected it to be omitted") + } + + fmt.Fprint(w, `{"id": 84, "name": "test ruleset"}`) + }) + + ctx := t.Context() + input := RepositoryRuleset{ + Name: "test ruleset", + BypassActors: nil, + } + + _, _, err := client.Enterprise.UpdateRepositoryRuleset(ctx, "e", 84, input) + if err != nil { + t.Errorf("Enterprise.UpdateRepositoryRuleset returned error: %v", err) + } +} + +func TestEnterpriseService_UpdateRepositoryRuleset_OmitZero_EmptySlice(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/enterprises/e/rulesets/84", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PUT") + + // FIXED: Added "source":"" and "enforcement":"" to match actual JSON output + testBody(t, r, `{"name":"test ruleset","source":"","enforcement":"","bypass_actors":[]}`+"\n") + + fmt.Fprint(w, `{"id": 84, "name": "test ruleset", "bypass_actors": []}`) + }) + + ctx := t.Context() + input := RepositoryRuleset{ + Name: "test ruleset", + BypassActors: []*BypassActor{}, + } + + _, _, err := client.Enterprise.UpdateRepositoryRuleset(ctx, "e", 84, input) + if err != nil { + t.Errorf("Enterprise.UpdateRepositoryRuleset returned error: %v", err) + } +} + func TestEnterpriseService_CreateRepositoryRuleset_OrgNameRepoProperty(t *testing.T) { t.Parallel() client, mux, _ := setup(t) diff --git a/github/orgs_rules_test.go b/github/orgs_rules_test.go index 12dedde99c1..d1856a06653 100644 --- a/github/orgs_rules_test.go +++ b/github/orgs_rules_test.go @@ -6,6 +6,7 @@ package github import ( + "encoding/json" "fmt" "net/http" "testing" @@ -1587,6 +1588,80 @@ func TestOrganizationsService_UpdateRepositoryRulesetWithRepoProp(t *testing.T) }) } +func TestOrganizationsService_UpdateRepositoryRuleset_OmitZero_Nil(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + // Scenario 1: User passes nil (zero value). + mux.HandleFunc("/orgs/o/rulesets/21", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PUT") + + // Verify "bypass_actors" key is NOT present in the JSON body + var v map[string]any + if err := json.NewDecoder(r.Body).Decode(&v); err != nil { + t.Errorf("could not decode body: %v", err) + } + + if _, ok := v["bypass_actors"]; ok { + t.Error("Request body contained 'bypass_actors', expected it to be omitted for nil input") + } + + fmt.Fprint(w, `{ + "id": 21, + "name": "test ruleset", + "source_type": "Organization", + "source": "o", + "enforcement": "active" + }`) + }) + + ctx := t.Context() + input := RepositoryRuleset{ + Name: "test ruleset", + Enforcement: RulesetEnforcementActive, + BypassActors: nil, // Explicitly nil (Zero Value) + } + + _, _, err := client.Organizations.UpdateRepositoryRuleset(ctx, "o", 21, input) + if err != nil { + t.Errorf("Organizations.UpdateRepositoryRuleset returned error: %v", err) + } +} + +func TestOrganizationsService_UpdateRepositoryRuleset_OmitZero_EmptySlice(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + // Scenario 2: User passes empty slice. + mux.HandleFunc("/orgs/o/rulesets/21", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PUT") + + // FIXED: Added "source":"" to match the actual JSON output + testBody(t, r, `{"name":"test ruleset","source":"","enforcement":"active","bypass_actors":[]}`+"\n") + + fmt.Fprint(w, `{ + "id": 21, + "name": "test ruleset", + "source_type": "Organization", + "source": "o", + "enforcement": "active", + "bypass_actors": [] + }`) + }) + + ctx := t.Context() + input := RepositoryRuleset{ + Name: "test ruleset", + Enforcement: RulesetEnforcementActive, + BypassActors: []*BypassActor{}, + } + + _, _, err := client.Organizations.UpdateRepositoryRuleset(ctx, "o", 21, input) + if err != nil { + t.Errorf("Organizations.UpdateRepositoryRuleset returned error: %v", err) + } +} + func TestOrganizationsService_DeleteRepositoryRuleset(t *testing.T) { t.Parallel() client, mux, _ := setup(t) diff --git a/github/repos_rules_test.go b/github/repos_rules_test.go index efc102b67a7..a99e0d9699c 100644 --- a/github/repos_rules_test.go +++ b/github/repos_rules_test.go @@ -6,6 +6,7 @@ package github import ( + "encoding/json" "fmt" "net/http" "testing" @@ -63,6 +64,78 @@ func TestRepositoriesService_GetRulesForBranch(t *testing.T) { }) } +func TestRepositoriesService_UpdateRuleset_OmitZero_Nil(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + // Scenario 1: User passes nil (zero value). + mux.HandleFunc("/repos/o/repo/rulesets/42", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PUT") + + // Verify "bypass_actors" key is NOT present in the JSON body + var v map[string]any + if err := json.NewDecoder(r.Body).Decode(&v); err != nil { + t.Errorf("could not decode body: %v", err) + } + + if _, ok := v["bypass_actors"]; ok { + t.Error("Request body contained 'bypass_actors', expected it to be omitted for nil input") + } + + fmt.Fprint(w, `{ + "id": 42, + "name": "ruleset", + "source": "o/repo", + "enforcement": "active" + }`) + }) + + ctx := t.Context() + input := RepositoryRuleset{ + Name: "ruleset", + Enforcement: RulesetEnforcementActive, + BypassActors: nil, // Explicitly nil (Zero Value) + } + + _, _, err := client.Repositories.UpdateRuleset(ctx, "o", "repo", 42, input) + if err != nil { + t.Errorf("Repositories.UpdateRuleset returned error: %v", err) + } +} + +func TestRepositoriesService_UpdateRuleset_OmitZero_EmptySlice(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + // Scenario 2: User passes empty slice (non-zero value). + mux.HandleFunc("/repos/o/repo/rulesets/42", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PUT") + + // FIXED: Added "source":"" to match the actual JSON output + testBody(t, r, `{"name":"ruleset","source":"","enforcement":"active","bypass_actors":[]}`+"\n") + + fmt.Fprint(w, `{ + "id": 42, + "name": "ruleset", + "source": "o/repo", + "enforcement": "active", + "bypass_actors": [] + }`) + }) + + ctx := t.Context() + input := RepositoryRuleset{ + Name: "ruleset", + Enforcement: RulesetEnforcementActive, + BypassActors: []*BypassActor{}, + } + + _, _, err := client.Repositories.UpdateRuleset(ctx, "o", "repo", 42, input) + if err != nil { + t.Errorf("Repositories.UpdateRuleset returned error: %v", err) + } +} + func TestRepositoriesService_GetRulesForBranch_ListOptions(t *testing.T) { t.Parallel() client, mux, _ := setup(t) From 5775ee80f418242ad90dd3d7a9395fc8b2aaac9d Mon Sep 17 00:00:00 2001 From: maishivamhoo123 Date: Tue, 23 Dec 2025 17:37:05 +0530 Subject: [PATCH 3/4] Address review comments: remove artifact comments and fix meta tags --- github/enterprise_rules.go | 3 --- github/enterprise_rules_test.go | 2 -- github/orgs_rules.go | 3 --- github/orgs_rules_test.go | 6 +----- github/repos_rules_test.go | 4 +--- 5 files changed, 2 insertions(+), 16 deletions(-) diff --git a/github/enterprise_rules.go b/github/enterprise_rules.go index 03906b721e1..3cd3ee4e85e 100644 --- a/github/enterprise_rules.go +++ b/github/enterprise_rules.go @@ -80,10 +80,7 @@ func (s *EnterpriseService) UpdateRepositoryRuleset(ctx context.Context, enterpr // // GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/enterprise-admin/rules#delete-an-enterprise-repository-ruleset // -// GitHub API docs: https://docs.github.com/enterprise-cloud@latest/rest/enterprise-admin/rules#update-an-enterprise-repository-ruleset -// //meta:operation DELETE /enterprises/{enterprise}/rulesets/{ruleset_id} -//meta:operation PUT /enterprises/{enterprise}/rulesets/{ruleset_id} func (s *EnterpriseService) DeleteRepositoryRuleset(ctx context.Context, enterprise string, rulesetID int64) (*Response, error) { u := fmt.Sprintf("enterprises/%v/rulesets/%v", enterprise, rulesetID) diff --git a/github/enterprise_rules_test.go b/github/enterprise_rules_test.go index 19ae2620265..724a2e61036 100644 --- a/github/enterprise_rules_test.go +++ b/github/enterprise_rules_test.go @@ -392,7 +392,6 @@ func TestEnterpriseService_UpdateRepositoryRuleset_OmitZero_Nil(t *testing.T) { mux.HandleFunc("/enterprises/e/rulesets/84", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") - // Verify "bypass_actors" key is NOT present var v map[string]any if err := json.NewDecoder(r.Body).Decode(&v); err != nil { t.Errorf("could not decode body: %v", err) @@ -424,7 +423,6 @@ func TestEnterpriseService_UpdateRepositoryRuleset_OmitZero_EmptySlice(t *testin mux.HandleFunc("/enterprises/e/rulesets/84", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") - // FIXED: Added "source":"" and "enforcement":"" to match actual JSON output testBody(t, r, `{"name":"test ruleset","source":"","enforcement":"","bypass_actors":[]}`+"\n") fmt.Fprint(w, `{"id": 84, "name": "test ruleset", "bypass_actors": []}`) diff --git a/github/orgs_rules.go b/github/orgs_rules.go index 75e003a73a2..26012091a46 100644 --- a/github/orgs_rules.go +++ b/github/orgs_rules.go @@ -107,10 +107,7 @@ func (s *OrganizationsService) UpdateRepositoryRuleset(ctx context.Context, org // // GitHub API docs: https://docs.github.com/rest/orgs/rules#delete-an-organization-repository-ruleset // -// GitHub API docs: https://docs.github.com/rest/orgs/rules#update-an-organization-repository-ruleset -// //meta:operation DELETE /orgs/{org}/rulesets/{ruleset_id} -//meta:operation PUT /orgs/{org}/rulesets/{ruleset_id} func (s *OrganizationsService) DeleteRepositoryRuleset(ctx context.Context, org string, rulesetID int64) (*Response, error) { u := fmt.Sprintf("orgs/%v/rulesets/%v", org, rulesetID) diff --git a/github/orgs_rules_test.go b/github/orgs_rules_test.go index d1856a06653..1c70947931e 100644 --- a/github/orgs_rules_test.go +++ b/github/orgs_rules_test.go @@ -1592,11 +1592,9 @@ func TestOrganizationsService_UpdateRepositoryRuleset_OmitZero_Nil(t *testing.T) t.Parallel() client, mux, _ := setup(t) - // Scenario 1: User passes nil (zero value). mux.HandleFunc("/orgs/o/rulesets/21", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") - // Verify "bypass_actors" key is NOT present in the JSON body var v map[string]any if err := json.NewDecoder(r.Body).Decode(&v); err != nil { t.Errorf("could not decode body: %v", err) @@ -1619,7 +1617,7 @@ func TestOrganizationsService_UpdateRepositoryRuleset_OmitZero_Nil(t *testing.T) input := RepositoryRuleset{ Name: "test ruleset", Enforcement: RulesetEnforcementActive, - BypassActors: nil, // Explicitly nil (Zero Value) + BypassActors: nil, } _, _, err := client.Organizations.UpdateRepositoryRuleset(ctx, "o", 21, input) @@ -1632,11 +1630,9 @@ func TestOrganizationsService_UpdateRepositoryRuleset_OmitZero_EmptySlice(t *tes t.Parallel() client, mux, _ := setup(t) - // Scenario 2: User passes empty slice. mux.HandleFunc("/orgs/o/rulesets/21", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") - // FIXED: Added "source":"" to match the actual JSON output testBody(t, r, `{"name":"test ruleset","source":"","enforcement":"active","bypass_actors":[]}`+"\n") fmt.Fprint(w, `{ diff --git a/github/repos_rules_test.go b/github/repos_rules_test.go index a99e0d9699c..bff9bd7f62e 100644 --- a/github/repos_rules_test.go +++ b/github/repos_rules_test.go @@ -68,11 +68,9 @@ func TestRepositoriesService_UpdateRuleset_OmitZero_Nil(t *testing.T) { t.Parallel() client, mux, _ := setup(t) - // Scenario 1: User passes nil (zero value). mux.HandleFunc("/repos/o/repo/rulesets/42", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") - // Verify "bypass_actors" key is NOT present in the JSON body var v map[string]any if err := json.NewDecoder(r.Body).Decode(&v); err != nil { t.Errorf("could not decode body: %v", err) @@ -94,7 +92,7 @@ func TestRepositoriesService_UpdateRuleset_OmitZero_Nil(t *testing.T) { input := RepositoryRuleset{ Name: "ruleset", Enforcement: RulesetEnforcementActive, - BypassActors: nil, // Explicitly nil (Zero Value) + BypassActors: nil, } _, _, err := client.Repositories.UpdateRuleset(ctx, "o", "repo", 42, input) From 1493c7dcb73100b7d57513800fa7a83c170fab01 Mon Sep 17 00:00:00 2001 From: Shivam Kumar <155747305+maishivamhoo123@users.noreply.github.com> Date: Tue, 23 Dec 2025 17:53:44 +0530 Subject: [PATCH 4/4] Update github/repos_rules_test.go Co-authored-by: Oleksandr Redko --- github/repos_rules_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/github/repos_rules_test.go b/github/repos_rules_test.go index bff9bd7f62e..c8cd936e275 100644 --- a/github/repos_rules_test.go +++ b/github/repos_rules_test.go @@ -109,7 +109,6 @@ func TestRepositoriesService_UpdateRuleset_OmitZero_EmptySlice(t *testing.T) { mux.HandleFunc("/repos/o/repo/rulesets/42", func(w http.ResponseWriter, r *http.Request) { testMethod(t, r, "PUT") - // FIXED: Added "source":"" to match the actual JSON output testBody(t, r, `{"name":"ruleset","source":"","enforcement":"active","bypass_actors":[]}`+"\n") fmt.Fprint(w, `{