From 6b67c18f87b57ab331bbfb523b5d85c9a2ffff0e Mon Sep 17 00:00:00 2001 From: Iurii Date: Fri, 2 Oct 2026 18:11:46 +0300 Subject: [PATCH 1/2] feat: Add actions policies endpoints --- github/actions_policies.go | 283 +++++++++++++++++++++ github/actions_policies_test.go | 428 ++++++++++++++++++++++++++++++++ github/github-accessors.go | 240 ++++++++++++++++++ github/github-accessors_test.go | 279 +++++++++++++++++++++ github/github-iterators.go | 70 ++++++ github/github-iterators_test.go | 144 +++++++++++ openapi_operations.yaml | 20 ++ 7 files changed, 1464 insertions(+) create mode 100644 github/actions_policies.go create mode 100644 github/actions_policies_test.go diff --git a/github/actions_policies.go b/github/actions_policies.go new file mode 100644 index 00000000000..ad21bddfe54 --- /dev/null +++ b/github/actions_policies.go @@ -0,0 +1,283 @@ +// Copyright 2026 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" +) + +// ActionsPolicyTarget represents a GitHub Actions policy target. +type ActionsPolicyTarget string + +// ActionsPolicyTargetActions is the target used by GitHub Actions policies. +const ActionsPolicyTargetActions ActionsPolicyTarget = "actions" + +// ActionsPolicyRuleType represents a GitHub Actions policy rule type. +type ActionsPolicyRuleType string + +// GitHub Actions policy rule types. +const ( + ActionsPolicyRuleTypeRestrictActionsActors ActionsPolicyRuleType = "restrict_actions_actors" + ActionsPolicyRuleTypeRestrictActionEvents ActionsPolicyRuleType = "restrict_action_events" +) + +// ActionsPolicyActorType represents the type of an actor allowed to trigger Actions workflows. +type ActionsPolicyActorType string + +// GitHub Actions policy actor types. +const ( + ActionsPolicyActorTypeUser ActionsPolicyActorType = "User" + ActionsPolicyActorTypeBot ActionsPolicyActorType = "Bot" + ActionsPolicyActorTypeTeam ActionsPolicyActorType = "Team" + ActionsPolicyActorTypeBusinessTeam ActionsPolicyActorType = "BusinessTeam" + ActionsPolicyActorTypeEnterpriseTeam ActionsPolicyActorType = "EnterpriseTeam" + ActionsPolicyActorTypeIntegrationInstallation ActionsPolicyActorType = "IntegrationInstallation" + ActionsPolicyActorTypeApp ActionsPolicyActorType = "App" + ActionsPolicyActorTypeRepositoryRole ActionsPolicyActorType = "RepositoryRole" +) + +// ActionsPolicy represents a GitHub Actions policy. +// +// GitHub API docs: https://docs.github.com/rest/actions/policies?apiVersion=2026-03-10 +type ActionsPolicy struct { + ID *int64 `json:"id,omitempty"` + Name *string `json:"name,omitempty"` + Target *ActionsPolicyTarget `json:"target,omitempty"` + SourceType *RulesetSourceType `json:"source_type,omitempty"` + Source *string `json:"source,omitempty"` + Enforcement *RulesetEnforcement `json:"enforcement,omitempty"` + Conditions *ActionsPolicyConditions `json:"conditions,omitempty"` + Rules []*ActionsPolicyRule `json:"rules,omitzero"` + NodeID *string `json:"node_id,omitempty"` + Links *RepositoryRulesetLinks `json:"_links,omitempty"` + CreatedAt *Timestamp `json:"created_at,omitempty"` + UpdatedAt *Timestamp `json:"updated_at,omitempty"` +} + +// ActionsPolicyConditions represents the conditions object in an Actions policy. +// Organization policies may use one repository selector and an optional workflow path selector. +// Policies inherited from higher levels can also contain organization selectors. +type ActionsPolicyConditions struct { + RepositoryID *RepositoryRulesetRepositoryIDsConditionParameters `json:"repository_id,omitempty"` + RepositoryName *RepositoryRulesetRepositoryNamesConditionParameters `json:"repository_name,omitempty"` + RepositoryProperty *RepositoryRulesetRepositoryPropertyConditionParameters `json:"repository_property,omitempty"` + OrganizationID *RepositoryRulesetOrganizationIDsConditionParameters `json:"organization_id,omitempty"` + OrganizationName *RepositoryRulesetOrganizationNamesConditionParameters `json:"organization_name,omitempty"` + OrganizationProperty *RepositoryRulesetOrganizationPropertyConditionParameters `json:"organization_property,omitempty"` + WorkflowPath *ActionsPolicyWorkflowPathConditionParameters `json:"workflow_path,omitempty"` +} + +// ActionsPolicyWorkflowPathConditionParameters represents a workflow_path condition in an Actions policy. +type ActionsPolicyWorkflowPathConditionParameters struct { + Include []string `json:"include"` + Exclude []string `json:"exclude"` +} + +// ActionsPolicyRule represents a rule in an Actions policy. +type ActionsPolicyRule struct { + Type ActionsPolicyRuleType `json:"type"` + Parameters *ActionsPolicyRuleParameters `json:"parameters,omitempty"` +} + +// ActionsPolicyRuleParameters represents the parameters for an Actions policy rule. +// AllowedActors is used by restrict_actions_actors; AllowedEvents is used by restrict_action_events. +type ActionsPolicyRuleParameters struct { + AllowedActors []*ActionsPolicyActor `json:"allowed_actors,omitzero"` + AllowedEvents []string `json:"allowed_events,omitzero"` +} + +// ActionsPolicyActor represents an actor authorized to trigger Actions workflows. +type ActionsPolicyActor struct { + ID int64 `json:"id"` + Type ActionsPolicyActorType `json:"type"` +} + +// ActionsPolicyList represents a list of GitHub Actions policies. +type ActionsPolicyList struct { + TotalCount int `json:"total_count"` + Policies []*ActionsPolicy `json:"policies"` +} + +// ActionsPolicyListOptions specifies optional parameters for listing Actions policies. +type ActionsPolicyListOptions struct { + // HasParents controls whether policies configured at higher levels are included. + HasParents *bool `url:"has_parents,omitempty"` + ListOptions +} + +func (s *ActionsService) listPolicies(ctx context.Context, u string, opts *ActionsPolicyListOptions) (*ActionsPolicyList, *Response, error) { + u, err := addOptions(u, opts) + if err != nil { + return nil, nil, err + } + + req, err := s.client.NewRequest(ctx, "GET", u, nil, WithVersion(api20260310)) + if err != nil { + return nil, nil, err + } + + var policies *ActionsPolicyList + resp, err := s.client.Do(req, &policies) + if err != nil { + return nil, resp, err + } + + return policies, resp, nil +} + +func (s *ActionsService) createPolicy(ctx context.Context, u string, body ActionsPolicy) (*ActionsPolicy, *Response, error) { + req, err := s.client.NewRequest(ctx, "POST", u, body, WithVersion(api20260310)) + if err != nil { + return nil, nil, err + } + + var policy *ActionsPolicy + resp, err := s.client.Do(req, &policy) + if err != nil { + return nil, resp, err + } + + return policy, resp, nil +} + +func (s *ActionsService) getPolicy(ctx context.Context, u string) (*ActionsPolicy, *Response, error) { + req, err := s.client.NewRequest(ctx, "GET", u, nil, WithVersion(api20260310)) + if err != nil { + return nil, nil, err + } + + var policy *ActionsPolicy + resp, err := s.client.Do(req, &policy) + if err != nil { + return nil, resp, err + } + + return policy, resp, nil +} + +func (s *ActionsService) updatePolicy(ctx context.Context, u string, body ActionsPolicy) (*ActionsPolicy, *Response, error) { + req, err := s.client.NewRequest(ctx, "PUT", u, body, WithVersion(api20260310)) + if err != nil { + return nil, nil, err + } + + var policy *ActionsPolicy + resp, err := s.client.Do(req, &policy) + if err != nil { + return nil, resp, err + } + + return policy, resp, nil +} + +func (s *ActionsService) deletePolicy(ctx context.Context, u string) (*Response, error) { + req, err := s.client.NewRequest(ctx, "DELETE", u, nil, WithVersion(api20260310)) + if err != nil { + return nil, err + } + return s.client.Do(req, nil) +} + +// ListOrganizationPolicies lists all Actions policies for an organization. +// +// GitHub API docs: https://docs.github.com/rest/actions/policies?apiVersion=2026-03-10#list-organization-actions-policies +// +//meta:operation GET /orgs/{org}/actions/policies +func (s *ActionsService) ListOrganizationPolicies(ctx context.Context, org string, opts *ActionsPolicyListOptions) (*ActionsPolicyList, *Response, error) { + u := fmt.Sprintf("orgs/%v/actions/policies", org) + return s.listPolicies(ctx, u, opts) +} + +// CreateOrganizationPolicy creates an Actions policy for an organization. +// +// GitHub API docs: https://docs.github.com/rest/actions/policies?apiVersion=2026-03-10#create-an-organization-actions-policy +// +//meta:operation POST /orgs/{org}/actions/policies +func (s *ActionsService) CreateOrganizationPolicy(ctx context.Context, org string, body ActionsPolicy) (*ActionsPolicy, *Response, error) { + u := fmt.Sprintf("orgs/%v/actions/policies", org) + return s.createPolicy(ctx, u, body) +} + +// GetOrganizationPolicy gets a specific Actions policy for an organization. +// +// GitHub API docs: https://docs.github.com/rest/actions/policies?apiVersion=2026-03-10#get-an-organization-actions-policy +// +//meta:operation GET /orgs/{org}/actions/policies/{policy_id} +func (s *ActionsService) GetOrganizationPolicy(ctx context.Context, org string, policyID int64) (*ActionsPolicy, *Response, error) { + u := fmt.Sprintf("orgs/%v/actions/policies/%v", org, policyID) + return s.getPolicy(ctx, u) +} + +// UpdateOrganizationPolicy updates an Actions policy for an organization. +// +// GitHub API docs: https://docs.github.com/rest/actions/policies?apiVersion=2026-03-10#update-an-organization-actions-policy +// +//meta:operation PUT /orgs/{org}/actions/policies/{policy_id} +func (s *ActionsService) UpdateOrganizationPolicy(ctx context.Context, org string, policyID int64, body ActionsPolicy) (*ActionsPolicy, *Response, error) { + u := fmt.Sprintf("orgs/%v/actions/policies/%v", org, policyID) + return s.updatePolicy(ctx, u, body) +} + +// DeleteOrganizationPolicy deletes an Actions policy for an organization. +// +// GitHub API docs: https://docs.github.com/rest/actions/policies?apiVersion=2026-03-10#delete-an-organization-actions-policy +// +//meta:operation DELETE /orgs/{org}/actions/policies/{policy_id} +func (s *ActionsService) DeleteOrganizationPolicy(ctx context.Context, org string, policyID int64) (*Response, error) { + u := fmt.Sprintf("orgs/%v/actions/policies/%v", org, policyID) + return s.deletePolicy(ctx, u) +} + +// ListRepositoryPolicies lists all Actions policies for a repository. +// +// GitHub API docs: https://docs.github.com/rest/actions/policies?apiVersion=2026-03-10#list-repository-actions-policies +// +//meta:operation GET /repos/{owner}/{repo}/actions/policies +func (s *ActionsService) ListRepositoryPolicies(ctx context.Context, owner, repo string, opts *ActionsPolicyListOptions) (*ActionsPolicyList, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/actions/policies", owner, repo) + return s.listPolicies(ctx, u, opts) +} + +// CreateRepositoryPolicy creates an Actions policy for a repository. +// +// GitHub API docs: https://docs.github.com/rest/actions/policies?apiVersion=2026-03-10#create-a-repository-actions-policy +// +//meta:operation POST /repos/{owner}/{repo}/actions/policies +func (s *ActionsService) CreateRepositoryPolicy(ctx context.Context, owner, repo string, body ActionsPolicy) (*ActionsPolicy, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/actions/policies", owner, repo) + return s.createPolicy(ctx, u, body) +} + +// GetRepositoryPolicy gets a specific Actions policy for a repository. +// +// GitHub API docs: https://docs.github.com/rest/actions/policies?apiVersion=2026-03-10#get-a-repository-actions-policy +// +//meta:operation GET /repos/{owner}/{repo}/actions/policies/{policy_id} +func (s *ActionsService) GetRepositoryPolicy(ctx context.Context, owner, repo string, policyID int64) (*ActionsPolicy, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/actions/policies/%v", owner, repo, policyID) + return s.getPolicy(ctx, u) +} + +// UpdateRepositoryPolicy updates an Actions policy for a repository. +// +// GitHub API docs: https://docs.github.com/rest/actions/policies?apiVersion=2026-03-10#update-a-repository-actions-policy +// +//meta:operation PUT /repos/{owner}/{repo}/actions/policies/{policy_id} +func (s *ActionsService) UpdateRepositoryPolicy(ctx context.Context, owner, repo string, policyID int64, body ActionsPolicy) (*ActionsPolicy, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/actions/policies/%v", owner, repo, policyID) + return s.updatePolicy(ctx, u, body) +} + +// DeleteRepositoryPolicy deletes an Actions policy for a repository. +// +// GitHub API docs: https://docs.github.com/rest/actions/policies?apiVersion=2026-03-10#delete-a-repository-actions-policy +// +//meta:operation DELETE /repos/{owner}/{repo}/actions/policies/{policy_id} +func (s *ActionsService) DeleteRepositoryPolicy(ctx context.Context, owner, repo string, policyID int64) (*Response, error) { + u := fmt.Sprintf("repos/%v/%v/actions/policies/%v", owner, repo, policyID) + return s.deletePolicy(ctx, u) +} diff --git a/github/actions_policies_test.go b/github/actions_policies_test.go new file mode 100644 index 00000000000..275b665c0f9 --- /dev/null +++ b/github/actions_policies_test.go @@ -0,0 +1,428 @@ +// Copyright 2026 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 ( + "fmt" + "net/http" + "testing" + + "github.com/google/go-cmp/cmp" +) + +const actionsPolicyResponseJSON = `{ + "id": 1, + "name": "Require approved actors", + "target": "actions", + "source_type": "Organization", + "source": "o", + "enforcement": "active", + "conditions": { + "repository_name": {"include": ["~ALL"], "exclude": []}, + "workflow_path": {"include": [".github/workflows/*.yml"], "exclude": []} + }, + "rules": [ + {"type": "restrict_actions_actors", "parameters": {"allowed_actors": [{"id": 1234, "type": "Team"}]}}, + {"type": "restrict_action_events", "parameters": {"allowed_events": ["push", "pull_request"]}} + ], + "node_id": "RUL_lA" +}` + +func testActionsPolicy() *ActionsPolicy { + return &ActionsPolicy{ + ID: new(int64(1)), + Name: new("Require approved actors"), + Target: new(ActionsPolicyTargetActions), + SourceType: new(RulesetSourceTypeOrganization), + Source: new("o"), + Enforcement: new(RulesetEnforcementActive), + Conditions: &ActionsPolicyConditions{ + RepositoryName: &RepositoryRulesetRepositoryNamesConditionParameters{ + Include: []string{"~ALL"}, + Exclude: []string{}, + }, + WorkflowPath: &ActionsPolicyWorkflowPathConditionParameters{ + Include: []string{".github/workflows/*.yml"}, + Exclude: []string{}, + }, + }, + Rules: []*ActionsPolicyRule{ + { + Type: ActionsPolicyRuleTypeRestrictActionsActors, + Parameters: &ActionsPolicyRuleParameters{ + AllowedActors: []*ActionsPolicyActor{{ID: 1234, Type: ActionsPolicyActorTypeTeam}}, + }, + }, + { + Type: ActionsPolicyRuleTypeRestrictActionEvents, + Parameters: &ActionsPolicyRuleParameters{ + AllowedEvents: []string{"push", "pull_request"}, + }, + }, + }, + NodeID: new("RUL_lA"), + } +} + +func TestActionsService_ListOrganizationPolicies(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/orgs/o/actions/policies", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testHeader(t, r, "X-Github-Api-Version", api20260310) + testFormValues(t, r, values{"page": "2", "per_page": "50", "has_parents": "false"}) + fmt.Fprintf(w, `{"total_count":1,"policies":[%s]}`, actionsPolicyResponseJSON) + }) + + ctx := t.Context() + got, _, err := client.Actions.ListOrganizationPolicies(ctx, "o", &ActionsPolicyListOptions{ + HasParents: new(false), + ListOptions: ListOptions{ + Page: 2, + PerPage: 50, + }, + }) + if err != nil { + t.Errorf("Actions.ListOrganizationPolicies returned error: %v", err) + } + want := &ActionsPolicyList{TotalCount: 1, Policies: []*ActionsPolicy{testActionsPolicy()}} + if !cmp.Equal(got, want) { + t.Errorf("Actions.ListOrganizationPolicies returned %+v, want %+v", got, want) + } + + const methodName = "ListOrganizationPolicies" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Actions.ListOrganizationPolicies(ctx, "\n", nil) + return err + }) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Actions.ListOrganizationPolicies(ctx, "o", nil) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestActionsService_CreateOrganizationPolicy(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + input := ActionsPolicy{ + Name: new("Require approved actors"), + Enforcement: new(RulesetEnforcementActive), + Rules: []*ActionsPolicyRule{{ + Type: ActionsPolicyRuleTypeRestrictActionsActors, + Parameters: &ActionsPolicyRuleParameters{ + AllowedActors: []*ActionsPolicyActor{{ID: 1234, Type: ActionsPolicyActorTypeTeam}}, + }, + }}, + } + + mux.HandleFunc("/orgs/o/actions/policies", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "POST") + testHeader(t, r, "X-Github-Api-Version", api20260310) + testJSONBody(t, r, input) + w.WriteHeader(http.StatusCreated) + fmt.Fprint(w, actionsPolicyResponseJSON) + }) + + ctx := t.Context() + got, _, err := client.Actions.CreateOrganizationPolicy(ctx, "o", input) + if err != nil { + t.Errorf("Actions.CreateOrganizationPolicy returned error: %v", err) + } + if want := testActionsPolicy(); !cmp.Equal(got, want) { + t.Errorf("Actions.CreateOrganizationPolicy returned %+v, want %+v", got, want) + } + + const methodName = "CreateOrganizationPolicy" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Actions.CreateOrganizationPolicy(ctx, "\n", input) + return err + }) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Actions.CreateOrganizationPolicy(ctx, "o", input) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestActionsService_GetOrganizationPolicy(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/orgs/o/actions/policies/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testHeader(t, r, "X-Github-Api-Version", api20260310) + fmt.Fprint(w, actionsPolicyResponseJSON) + }) + + ctx := t.Context() + got, _, err := client.Actions.GetOrganizationPolicy(ctx, "o", 1) + if err != nil { + t.Errorf("Actions.GetOrganizationPolicy returned error: %v", err) + } + if want := testActionsPolicy(); !cmp.Equal(got, want) { + t.Errorf("Actions.GetOrganizationPolicy returned %+v, want %+v", got, want) + } + + const methodName = "GetOrganizationPolicy" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Actions.GetOrganizationPolicy(ctx, "\n", 1) + return err + }) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Actions.GetOrganizationPolicy(ctx, "o", 1) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestActionsService_UpdateOrganizationPolicy(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + input := ActionsPolicy{Name: new("Updated policy"), Enforcement: new(RulesetEnforcementActive)} + mux.HandleFunc("/orgs/o/actions/policies/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PUT") + testHeader(t, r, "X-Github-Api-Version", api20260310) + testJSONBody(t, r, input) + fmt.Fprint(w, actionsPolicyResponseJSON) + }) + + ctx := t.Context() + got, _, err := client.Actions.UpdateOrganizationPolicy(ctx, "o", 1, input) + if err != nil { + t.Errorf("Actions.UpdateOrganizationPolicy returned error: %v", err) + } + if want := testActionsPolicy(); !cmp.Equal(got, want) { + t.Errorf("Actions.UpdateOrganizationPolicy returned %+v, want %+v", got, want) + } + + const methodName = "UpdateOrganizationPolicy" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Actions.UpdateOrganizationPolicy(ctx, "\n", 1, input) + return err + }) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Actions.UpdateOrganizationPolicy(ctx, "o", 1, input) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestActionsService_DeleteOrganizationPolicy(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/orgs/o/actions/policies/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + testHeader(t, r, "X-Github-Api-Version", api20260310) + w.WriteHeader(http.StatusNoContent) + }) + + ctx := t.Context() + if _, err := client.Actions.DeleteOrganizationPolicy(ctx, "o", 1); err != nil { + t.Errorf("Actions.DeleteOrganizationPolicy returned error: %v", err) + } + + const methodName = "DeleteOrganizationPolicy" + testBadOptions(t, methodName, func() (err error) { + _, err = client.Actions.DeleteOrganizationPolicy(ctx, "\n", 1) + return err + }) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + return client.Actions.DeleteOrganizationPolicy(ctx, "o", 1) + }) +} + +func TestActionsService_ListRepositoryPolicies(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/repos/o/r/actions/policies", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testHeader(t, r, "X-Github-Api-Version", api20260310) + testFormValues(t, r, values{"has_parents": "true"}) + fmt.Fprintf(w, `{"total_count":1,"policies":[%s]}`, actionsPolicyResponseJSON) + }) + + ctx := t.Context() + got, _, err := client.Actions.ListRepositoryPolicies(ctx, "o", "r", &ActionsPolicyListOptions{HasParents: new(true)}) + if err != nil { + t.Errorf("Actions.ListRepositoryPolicies returned error: %v", err) + } + want := &ActionsPolicyList{TotalCount: 1, Policies: []*ActionsPolicy{testActionsPolicy()}} + if !cmp.Equal(got, want) { + t.Errorf("Actions.ListRepositoryPolicies returned %+v, want %+v", got, want) + } + + const methodName = "ListRepositoryPolicies" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Actions.ListRepositoryPolicies(ctx, "\n", "\n", nil) + return err + }) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Actions.ListRepositoryPolicies(ctx, "o", "r", nil) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestActionsService_CreateRepositoryPolicy(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + input := ActionsPolicy{ + Name: new("Require approved events"), + Enforcement: new(RulesetEnforcementActive), + Conditions: &ActionsPolicyConditions{ + WorkflowPath: &ActionsPolicyWorkflowPathConditionParameters{ + Include: []string{".github/workflows/*.yml"}, + Exclude: []string{}, + }, + }, + Rules: []*ActionsPolicyRule{{ + Type: ActionsPolicyRuleTypeRestrictActionEvents, + Parameters: &ActionsPolicyRuleParameters{ + AllowedEvents: []string{"push"}, + }, + }}, + } + + mux.HandleFunc("/repos/o/r/actions/policies", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "POST") + testHeader(t, r, "X-Github-Api-Version", api20260310) + testJSONBody(t, r, input) + w.WriteHeader(http.StatusCreated) + fmt.Fprint(w, actionsPolicyResponseJSON) + }) + + ctx := t.Context() + got, _, err := client.Actions.CreateRepositoryPolicy(ctx, "o", "r", input) + if err != nil { + t.Errorf("Actions.CreateRepositoryPolicy returned error: %v", err) + } + if want := testActionsPolicy(); !cmp.Equal(got, want) { + t.Errorf("Actions.CreateRepositoryPolicy returned %+v, want %+v", got, want) + } + + const methodName = "CreateRepositoryPolicy" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Actions.CreateRepositoryPolicy(ctx, "\n", "\n", input) + return err + }) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Actions.CreateRepositoryPolicy(ctx, "o", "r", input) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestActionsService_GetRepositoryPolicy(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/repos/o/r/actions/policies/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + testHeader(t, r, "X-Github-Api-Version", api20260310) + fmt.Fprint(w, actionsPolicyResponseJSON) + }) + + ctx := t.Context() + got, _, err := client.Actions.GetRepositoryPolicy(ctx, "o", "r", 1) + if err != nil { + t.Errorf("Actions.GetRepositoryPolicy returned error: %v", err) + } + if want := testActionsPolicy(); !cmp.Equal(got, want) { + t.Errorf("Actions.GetRepositoryPolicy returned %+v, want %+v", got, want) + } + + const methodName = "GetRepositoryPolicy" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Actions.GetRepositoryPolicy(ctx, "\n", "\n", 1) + return err + }) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Actions.GetRepositoryPolicy(ctx, "o", "r", 1) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestActionsService_UpdateRepositoryPolicy(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + input := ActionsPolicy{Name: new("Updated repository policy"), Enforcement: new(RulesetEnforcementEvaluate)} + mux.HandleFunc("/repos/o/r/actions/policies/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "PUT") + testHeader(t, r, "X-Github-Api-Version", api20260310) + testJSONBody(t, r, input) + fmt.Fprint(w, actionsPolicyResponseJSON) + }) + + ctx := t.Context() + got, _, err := client.Actions.UpdateRepositoryPolicy(ctx, "o", "r", 1, input) + if err != nil { + t.Errorf("Actions.UpdateRepositoryPolicy returned error: %v", err) + } + if want := testActionsPolicy(); !cmp.Equal(got, want) { + t.Errorf("Actions.UpdateRepositoryPolicy returned %+v, want %+v", got, want) + } + + const methodName = "UpdateRepositoryPolicy" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Actions.UpdateRepositoryPolicy(ctx, "\n", "\n", 1, input) + return err + }) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Actions.UpdateRepositoryPolicy(ctx, "o", "r", 1, input) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestActionsService_DeleteRepositoryPolicy(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + + mux.HandleFunc("/repos/o/r/actions/policies/1", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "DELETE") + testHeader(t, r, "X-Github-Api-Version", api20260310) + w.WriteHeader(http.StatusNoContent) + }) + + ctx := t.Context() + if _, err := client.Actions.DeleteRepositoryPolicy(ctx, "o", "r", 1); err != nil { + t.Errorf("Actions.DeleteRepositoryPolicy returned error: %v", err) + } + + const methodName = "DeleteRepositoryPolicy" + testBadOptions(t, methodName, func() (err error) { + _, err = client.Actions.DeleteRepositoryPolicy(ctx, "\n", "\n", 1) + return err + }) + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + return client.Actions.DeleteRepositoryPolicy(ctx, "o", "r", 1) + }) +} diff --git a/github/github-accessors.go b/github/github-accessors.go index 36bd2823cff..e97db1e396a 100644 --- a/github/github-accessors.go +++ b/github/github-accessors.go @@ -478,6 +478,246 @@ func (a *ActionsPermissionsRepository) GetSHAPinningRequired() bool { return *a.SHAPinningRequired } +// GetConditions returns the Conditions field. +func (a *ActionsPolicy) GetConditions() *ActionsPolicyConditions { + if a == nil { + return nil + } + return a.Conditions +} + +// GetCreatedAt returns the CreatedAt field if it's non-nil, zero value otherwise. +func (a *ActionsPolicy) GetCreatedAt() Timestamp { + if a == nil || a.CreatedAt == nil { + return Timestamp{} + } + return *a.CreatedAt +} + +// GetEnforcement returns the Enforcement field. +func (a *ActionsPolicy) GetEnforcement() *RulesetEnforcement { + if a == nil { + return nil + } + return a.Enforcement +} + +// GetID returns the ID field if it's non-nil, zero value otherwise. +func (a *ActionsPolicy) GetID() int64 { + if a == nil || a.ID == nil { + return 0 + } + return *a.ID +} + +// GetLinks returns the Links field. +func (a *ActionsPolicy) GetLinks() *RepositoryRulesetLinks { + if a == nil { + return nil + } + return a.Links +} + +// GetName returns the Name field if it's non-nil, zero value otherwise. +func (a *ActionsPolicy) GetName() string { + if a == nil || a.Name == nil { + return "" + } + return *a.Name +} + +// GetNodeID returns the NodeID field if it's non-nil, zero value otherwise. +func (a *ActionsPolicy) GetNodeID() string { + if a == nil || a.NodeID == nil { + return "" + } + return *a.NodeID +} + +// GetRules returns the Rules slice if it's non-nil, nil otherwise. +func (a *ActionsPolicy) GetRules() []*ActionsPolicyRule { + if a == nil || a.Rules == nil { + return nil + } + return a.Rules +} + +// GetSource returns the Source field if it's non-nil, zero value otherwise. +func (a *ActionsPolicy) GetSource() string { + if a == nil || a.Source == nil { + return "" + } + return *a.Source +} + +// GetSourceType returns the SourceType field. +func (a *ActionsPolicy) GetSourceType() *RulesetSourceType { + if a == nil { + return nil + } + return a.SourceType +} + +// GetTarget returns the Target field. +func (a *ActionsPolicy) GetTarget() *ActionsPolicyTarget { + if a == nil { + return nil + } + return a.Target +} + +// GetUpdatedAt returns the UpdatedAt field if it's non-nil, zero value otherwise. +func (a *ActionsPolicy) GetUpdatedAt() Timestamp { + if a == nil || a.UpdatedAt == nil { + return Timestamp{} + } + return *a.UpdatedAt +} + +// GetID returns the ID field. +func (a *ActionsPolicyActor) GetID() int64 { + if a == nil { + return 0 + } + return a.ID +} + +// GetType returns the Type field. +func (a *ActionsPolicyActor) GetType() ActionsPolicyActorType { + if a == nil { + return "" + } + return a.Type +} + +// GetOrganizationID returns the OrganizationID field. +func (a *ActionsPolicyConditions) GetOrganizationID() *RepositoryRulesetOrganizationIDsConditionParameters { + if a == nil { + return nil + } + return a.OrganizationID +} + +// GetOrganizationName returns the OrganizationName field. +func (a *ActionsPolicyConditions) GetOrganizationName() *RepositoryRulesetOrganizationNamesConditionParameters { + if a == nil { + return nil + } + return a.OrganizationName +} + +// GetOrganizationProperty returns the OrganizationProperty field. +func (a *ActionsPolicyConditions) GetOrganizationProperty() *RepositoryRulesetOrganizationPropertyConditionParameters { + if a == nil { + return nil + } + return a.OrganizationProperty +} + +// GetRepositoryID returns the RepositoryID field. +func (a *ActionsPolicyConditions) GetRepositoryID() *RepositoryRulesetRepositoryIDsConditionParameters { + if a == nil { + return nil + } + return a.RepositoryID +} + +// GetRepositoryName returns the RepositoryName field. +func (a *ActionsPolicyConditions) GetRepositoryName() *RepositoryRulesetRepositoryNamesConditionParameters { + if a == nil { + return nil + } + return a.RepositoryName +} + +// GetRepositoryProperty returns the RepositoryProperty field. +func (a *ActionsPolicyConditions) GetRepositoryProperty() *RepositoryRulesetRepositoryPropertyConditionParameters { + if a == nil { + return nil + } + return a.RepositoryProperty +} + +// GetWorkflowPath returns the WorkflowPath field. +func (a *ActionsPolicyConditions) GetWorkflowPath() *ActionsPolicyWorkflowPathConditionParameters { + if a == nil { + return nil + } + return a.WorkflowPath +} + +// GetPolicies returns the Policies slice if it's non-nil, nil otherwise. +func (a *ActionsPolicyList) GetPolicies() []*ActionsPolicy { + if a == nil || a.Policies == nil { + return nil + } + return a.Policies +} + +// GetTotalCount returns the TotalCount field. +func (a *ActionsPolicyList) GetTotalCount() int { + if a == nil { + return 0 + } + return a.TotalCount +} + +// GetHasParents returns the HasParents field if it's non-nil, zero value otherwise. +func (a *ActionsPolicyListOptions) GetHasParents() bool { + if a == nil || a.HasParents == nil { + return false + } + return *a.HasParents +} + +// GetParameters returns the Parameters field. +func (a *ActionsPolicyRule) GetParameters() *ActionsPolicyRuleParameters { + if a == nil { + return nil + } + return a.Parameters +} + +// GetType returns the Type field. +func (a *ActionsPolicyRule) GetType() ActionsPolicyRuleType { + if a == nil { + return "" + } + return a.Type +} + +// GetAllowedActors returns the AllowedActors slice if it's non-nil, nil otherwise. +func (a *ActionsPolicyRuleParameters) GetAllowedActors() []*ActionsPolicyActor { + if a == nil || a.AllowedActors == nil { + return nil + } + return a.AllowedActors +} + +// GetAllowedEvents returns the AllowedEvents slice if it's non-nil, nil otherwise. +func (a *ActionsPolicyRuleParameters) GetAllowedEvents() []string { + if a == nil || a.AllowedEvents == nil { + return nil + } + return a.AllowedEvents +} + +// GetExclude returns the Exclude slice if it's non-nil, nil otherwise. +func (a *ActionsPolicyWorkflowPathConditionParameters) GetExclude() []string { + if a == nil || a.Exclude == nil { + return nil + } + return a.Exclude +} + +// GetInclude returns the Include slice if it's non-nil, nil otherwise. +func (a *ActionsPolicyWorkflowPathConditionParameters) GetInclude() []string { + if a == nil || a.Include == nil { + return nil + } + return a.Include +} + // GetName returns the Name field if it's non-nil, zero value otherwise. func (a *ActionsUpdateOrgVariableRequest) GetName() string { if a == nil || a.Name == nil { diff --git a/github/github-accessors_test.go b/github/github-accessors_test.go index e3724a9cbbd..b38bc5581d6 100644 --- a/github/github-accessors_test.go +++ b/github/github-accessors_test.go @@ -590,6 +590,285 @@ func TestActionsPermissionsRepository_GetSHAPinningRequired(tt *testing.T) { a.GetSHAPinningRequired() } +func TestActionsPolicy_GetConditions(tt *testing.T) { + tt.Parallel() + a := &ActionsPolicy{} + a.GetConditions() + a = nil + a.GetConditions() +} + +func TestActionsPolicy_GetCreatedAt(tt *testing.T) { + tt.Parallel() + var zeroValue Timestamp + a := &ActionsPolicy{CreatedAt: &zeroValue} + a.GetCreatedAt() + a = &ActionsPolicy{} + a.GetCreatedAt() + a = nil + a.GetCreatedAt() +} + +func TestActionsPolicy_GetEnforcement(tt *testing.T) { + tt.Parallel() + a := &ActionsPolicy{} + a.GetEnforcement() + a = nil + a.GetEnforcement() +} + +func TestActionsPolicy_GetID(tt *testing.T) { + tt.Parallel() + var zeroValue int64 + a := &ActionsPolicy{ID: &zeroValue} + a.GetID() + a = &ActionsPolicy{} + a.GetID() + a = nil + a.GetID() +} + +func TestActionsPolicy_GetLinks(tt *testing.T) { + tt.Parallel() + a := &ActionsPolicy{} + a.GetLinks() + a = nil + a.GetLinks() +} + +func TestActionsPolicy_GetName(tt *testing.T) { + tt.Parallel() + var zeroValue string + a := &ActionsPolicy{Name: &zeroValue} + a.GetName() + a = &ActionsPolicy{} + a.GetName() + a = nil + a.GetName() +} + +func TestActionsPolicy_GetNodeID(tt *testing.T) { + tt.Parallel() + var zeroValue string + a := &ActionsPolicy{NodeID: &zeroValue} + a.GetNodeID() + a = &ActionsPolicy{} + a.GetNodeID() + a = nil + a.GetNodeID() +} + +func TestActionsPolicy_GetRules(tt *testing.T) { + tt.Parallel() + zeroValue := []*ActionsPolicyRule{} + a := &ActionsPolicy{Rules: zeroValue} + a.GetRules() + a = &ActionsPolicy{} + a.GetRules() + a = nil + a.GetRules() +} + +func TestActionsPolicy_GetSource(tt *testing.T) { + tt.Parallel() + var zeroValue string + a := &ActionsPolicy{Source: &zeroValue} + a.GetSource() + a = &ActionsPolicy{} + a.GetSource() + a = nil + a.GetSource() +} + +func TestActionsPolicy_GetSourceType(tt *testing.T) { + tt.Parallel() + a := &ActionsPolicy{} + a.GetSourceType() + a = nil + a.GetSourceType() +} + +func TestActionsPolicy_GetTarget(tt *testing.T) { + tt.Parallel() + a := &ActionsPolicy{} + a.GetTarget() + a = nil + a.GetTarget() +} + +func TestActionsPolicy_GetUpdatedAt(tt *testing.T) { + tt.Parallel() + var zeroValue Timestamp + a := &ActionsPolicy{UpdatedAt: &zeroValue} + a.GetUpdatedAt() + a = &ActionsPolicy{} + a.GetUpdatedAt() + a = nil + a.GetUpdatedAt() +} + +func TestActionsPolicyActor_GetID(tt *testing.T) { + tt.Parallel() + a := &ActionsPolicyActor{} + a.GetID() + a = nil + a.GetID() +} + +func TestActionsPolicyActor_GetType(tt *testing.T) { + tt.Parallel() + a := &ActionsPolicyActor{} + a.GetType() + a = nil + a.GetType() +} + +func TestActionsPolicyConditions_GetOrganizationID(tt *testing.T) { + tt.Parallel() + a := &ActionsPolicyConditions{} + a.GetOrganizationID() + a = nil + a.GetOrganizationID() +} + +func TestActionsPolicyConditions_GetOrganizationName(tt *testing.T) { + tt.Parallel() + a := &ActionsPolicyConditions{} + a.GetOrganizationName() + a = nil + a.GetOrganizationName() +} + +func TestActionsPolicyConditions_GetOrganizationProperty(tt *testing.T) { + tt.Parallel() + a := &ActionsPolicyConditions{} + a.GetOrganizationProperty() + a = nil + a.GetOrganizationProperty() +} + +func TestActionsPolicyConditions_GetRepositoryID(tt *testing.T) { + tt.Parallel() + a := &ActionsPolicyConditions{} + a.GetRepositoryID() + a = nil + a.GetRepositoryID() +} + +func TestActionsPolicyConditions_GetRepositoryName(tt *testing.T) { + tt.Parallel() + a := &ActionsPolicyConditions{} + a.GetRepositoryName() + a = nil + a.GetRepositoryName() +} + +func TestActionsPolicyConditions_GetRepositoryProperty(tt *testing.T) { + tt.Parallel() + a := &ActionsPolicyConditions{} + a.GetRepositoryProperty() + a = nil + a.GetRepositoryProperty() +} + +func TestActionsPolicyConditions_GetWorkflowPath(tt *testing.T) { + tt.Parallel() + a := &ActionsPolicyConditions{} + a.GetWorkflowPath() + a = nil + a.GetWorkflowPath() +} + +func TestActionsPolicyList_GetPolicies(tt *testing.T) { + tt.Parallel() + zeroValue := []*ActionsPolicy{} + a := &ActionsPolicyList{Policies: zeroValue} + a.GetPolicies() + a = &ActionsPolicyList{} + a.GetPolicies() + a = nil + a.GetPolicies() +} + +func TestActionsPolicyList_GetTotalCount(tt *testing.T) { + tt.Parallel() + a := &ActionsPolicyList{} + a.GetTotalCount() + a = nil + a.GetTotalCount() +} + +func TestActionsPolicyListOptions_GetHasParents(tt *testing.T) { + tt.Parallel() + var zeroValue bool + a := &ActionsPolicyListOptions{HasParents: &zeroValue} + a.GetHasParents() + a = &ActionsPolicyListOptions{} + a.GetHasParents() + a = nil + a.GetHasParents() +} + +func TestActionsPolicyRule_GetParameters(tt *testing.T) { + tt.Parallel() + a := &ActionsPolicyRule{} + a.GetParameters() + a = nil + a.GetParameters() +} + +func TestActionsPolicyRule_GetType(tt *testing.T) { + tt.Parallel() + a := &ActionsPolicyRule{} + a.GetType() + a = nil + a.GetType() +} + +func TestActionsPolicyRuleParameters_GetAllowedActors(tt *testing.T) { + tt.Parallel() + zeroValue := []*ActionsPolicyActor{} + a := &ActionsPolicyRuleParameters{AllowedActors: zeroValue} + a.GetAllowedActors() + a = &ActionsPolicyRuleParameters{} + a.GetAllowedActors() + a = nil + a.GetAllowedActors() +} + +func TestActionsPolicyRuleParameters_GetAllowedEvents(tt *testing.T) { + tt.Parallel() + zeroValue := []string{} + a := &ActionsPolicyRuleParameters{AllowedEvents: zeroValue} + a.GetAllowedEvents() + a = &ActionsPolicyRuleParameters{} + a.GetAllowedEvents() + a = nil + a.GetAllowedEvents() +} + +func TestActionsPolicyWorkflowPathConditionParameters_GetExclude(tt *testing.T) { + tt.Parallel() + zeroValue := []string{} + a := &ActionsPolicyWorkflowPathConditionParameters{Exclude: zeroValue} + a.GetExclude() + a = &ActionsPolicyWorkflowPathConditionParameters{} + a.GetExclude() + a = nil + a.GetExclude() +} + +func TestActionsPolicyWorkflowPathConditionParameters_GetInclude(tt *testing.T) { + tt.Parallel() + zeroValue := []string{} + a := &ActionsPolicyWorkflowPathConditionParameters{Include: zeroValue} + a.GetInclude() + a = &ActionsPolicyWorkflowPathConditionParameters{} + a.GetInclude() + a = nil + a.GetInclude() +} + func TestActionsUpdateOrgVariableRequest_GetName(tt *testing.T) { tt.Parallel() var zeroValue string diff --git a/github/github-iterators.go b/github/github-iterators.go index e13e78e2e4c..d66fd9baded 100644 --- a/github/github-iterators.go +++ b/github/github-iterators.go @@ -364,6 +364,41 @@ func (s *ActionsService) ListOrgVariablesIter(ctx context.Context, org string, o } } +// ListOrganizationPoliciesIter returns an iterator that paginates through all results of ListOrganizationPolicies. +func (s *ActionsService) ListOrganizationPoliciesIter(ctx context.Context, org string, opts *ActionsPolicyListOptions) iter.Seq2[*ActionsPolicy, error] { + return func(yield func(*ActionsPolicy, error) bool) { + // Create a copy of opts to avoid mutating the caller's struct + if opts == nil { + opts = &ActionsPolicyListOptions{} + } else { + opts = new(*opts) + } + + for { + results, resp, err := s.ListOrganizationPolicies(ctx, org, opts) + if err != nil { + yield(nil, err) + return + } + + var iterItems []*ActionsPolicy + if results != nil { + iterItems = results.Policies + } + for _, item := range iterItems { + if !yield(item, nil) { + return + } + } + + if resp.NextPage == 0 { + break + } + opts.ListOptions.Page = resp.NextPage + } + } +} + // ListOrganizationRunnerGroupsIter returns an iterator that paginates through all results of ListOrganizationRunnerGroups. func (s *ActionsService) ListOrganizationRunnerGroupsIter(ctx context.Context, org string, opts *ListOrgRunnerGroupOptions) iter.Seq2[*RunnerGroup, error] { return func(yield func(*RunnerGroup, error) bool) { @@ -644,6 +679,41 @@ func (s *ActionsService) ListRepositoryAccessRunnerGroupIter(ctx context.Context } } +// ListRepositoryPoliciesIter returns an iterator that paginates through all results of ListRepositoryPolicies. +func (s *ActionsService) ListRepositoryPoliciesIter(ctx context.Context, owner string, repo string, opts *ActionsPolicyListOptions) iter.Seq2[*ActionsPolicy, error] { + return func(yield func(*ActionsPolicy, error) bool) { + // Create a copy of opts to avoid mutating the caller's struct + if opts == nil { + opts = &ActionsPolicyListOptions{} + } else { + opts = new(*opts) + } + + for { + results, resp, err := s.ListRepositoryPolicies(ctx, owner, repo, opts) + if err != nil { + yield(nil, err) + return + } + + var iterItems []*ActionsPolicy + if results != nil { + iterItems = results.Policies + } + for _, item := range iterItems { + if !yield(item, nil) { + return + } + } + + if resp.NextPage == 0 { + break + } + opts.ListOptions.Page = resp.NextPage + } + } +} + // ListRepositoryWorkflowRunsIter returns an iterator that paginates through all results of ListRepositoryWorkflowRuns. func (s *ActionsService) ListRepositoryWorkflowRunsIter(ctx context.Context, owner string, repo string, opts *ListWorkflowRunsOptions) iter.Seq2[*WorkflowRun, error] { return func(yield func(*WorkflowRun, error) bool) { diff --git a/github/github-iterators_test.go b/github/github-iterators_test.go index 1d8e536d4c3..d689ef2959c 100644 --- a/github/github-iterators_test.go +++ b/github/github-iterators_test.go @@ -735,6 +735,78 @@ func TestActionsService_ListOrgVariablesIter(t *testing.T) { } } +func TestActionsService_ListOrganizationPoliciesIter(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + var callNum int + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + callNum++ + switch callNum { + case 1: + w.Header().Set("Link", `; rel="next"`) + fmt.Fprint(w, `{"policies": [{},{},{}]}`) + case 2: + fmt.Fprint(w, `{"policies": [{},{},{},{}]}`) + case 3: + fmt.Fprint(w, `{"policies": [{},{}]}`) + case 4: + w.WriteHeader(http.StatusNotFound) + case 5: + fmt.Fprint(w, `{"policies": [{},{}]}`) + } + }) + + iter := client.Actions.ListOrganizationPoliciesIter(t.Context(), "", nil) + var gotItems int + for _, err := range iter { + gotItems++ + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + } + if want := 7; gotItems != want { + t.Errorf("client.Actions.ListOrganizationPoliciesIter call 1 got %v items; want %v", gotItems, want) + } + + opts := &ActionsPolicyListOptions{} + iter = client.Actions.ListOrganizationPoliciesIter(t.Context(), "", opts) + gotItems = 0 + for _, err := range iter { + gotItems++ + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + } + if want := 2; gotItems != want { + t.Errorf("client.Actions.ListOrganizationPoliciesIter call 2 got %v items; want %v", gotItems, want) + } + + iter = client.Actions.ListOrganizationPoliciesIter(t.Context(), "", nil) + gotItems = 0 + for _, err := range iter { + gotItems++ + if err == nil { + t.Error("expected error; got nil") + } + } + if gotItems != 1 { + t.Errorf("client.Actions.ListOrganizationPoliciesIter call 3 got %v items; want 1 (an error)", gotItems) + } + + iter = client.Actions.ListOrganizationPoliciesIter(t.Context(), "", nil) + gotItems = 0 + iter(func(item *ActionsPolicy, err error) bool { + gotItems++ + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + return false + }) + if gotItems != 1 { + t.Errorf("client.Actions.ListOrganizationPoliciesIter call 4 got %v items; want 1 (an error)", gotItems) + } +} + func TestActionsService_ListOrganizationRunnerGroupsIter(t *testing.T) { t.Parallel() client, mux, _ := setup(t) @@ -1311,6 +1383,78 @@ func TestActionsService_ListRepositoryAccessRunnerGroupIter(t *testing.T) { } } +func TestActionsService_ListRepositoryPoliciesIter(t *testing.T) { + t.Parallel() + client, mux, _ := setup(t) + var callNum int + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + callNum++ + switch callNum { + case 1: + w.Header().Set("Link", `; rel="next"`) + fmt.Fprint(w, `{"policies": [{},{},{}]}`) + case 2: + fmt.Fprint(w, `{"policies": [{},{},{},{}]}`) + case 3: + fmt.Fprint(w, `{"policies": [{},{}]}`) + case 4: + w.WriteHeader(http.StatusNotFound) + case 5: + fmt.Fprint(w, `{"policies": [{},{}]}`) + } + }) + + iter := client.Actions.ListRepositoryPoliciesIter(t.Context(), "", "", nil) + var gotItems int + for _, err := range iter { + gotItems++ + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + } + if want := 7; gotItems != want { + t.Errorf("client.Actions.ListRepositoryPoliciesIter call 1 got %v items; want %v", gotItems, want) + } + + opts := &ActionsPolicyListOptions{} + iter = client.Actions.ListRepositoryPoliciesIter(t.Context(), "", "", opts) + gotItems = 0 + for _, err := range iter { + gotItems++ + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + } + if want := 2; gotItems != want { + t.Errorf("client.Actions.ListRepositoryPoliciesIter call 2 got %v items; want %v", gotItems, want) + } + + iter = client.Actions.ListRepositoryPoliciesIter(t.Context(), "", "", nil) + gotItems = 0 + for _, err := range iter { + gotItems++ + if err == nil { + t.Error("expected error; got nil") + } + } + if gotItems != 1 { + t.Errorf("client.Actions.ListRepositoryPoliciesIter call 3 got %v items; want 1 (an error)", gotItems) + } + + iter = client.Actions.ListRepositoryPoliciesIter(t.Context(), "", "", nil) + gotItems = 0 + iter(func(item *ActionsPolicy, err error) bool { + gotItems++ + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + return false + }) + if gotItems != 1 { + t.Errorf("client.Actions.ListRepositoryPoliciesIter call 4 got %v items; want 1 (an error)", gotItems) + } +} + func TestActionsService_ListRepositoryWorkflowRunsIter(t *testing.T) { t.Parallel() client, mux, _ := setup(t) diff --git a/openapi_operations.yaml b/openapi_operations.yaml index b5d8fa61152..a53b770ba0d 100644 --- a/openapi_operations.yaml +++ b/openapi_operations.yaml @@ -79,6 +79,16 @@ operations: operation_overrides: - name: GET /meta documentation_url: https://docs.github.com/rest/meta/meta#get-github-meta-information + - name: GET /orgs/{org}/actions/policies + documentation_url: https://docs.github.com/rest/actions/policies?apiVersion=2026-03-10#list-organization-actions-policies + - name: POST /orgs/{org}/actions/policies + documentation_url: https://docs.github.com/rest/actions/policies?apiVersion=2026-03-10#create-an-organization-actions-policy + - name: DELETE /orgs/{org}/actions/policies/{policy_id} + documentation_url: https://docs.github.com/rest/actions/policies?apiVersion=2026-03-10#delete-an-organization-actions-policy + - name: GET /orgs/{org}/actions/policies/{policy_id} + documentation_url: https://docs.github.com/rest/actions/policies?apiVersion=2026-03-10#get-an-organization-actions-policy + - name: PUT /orgs/{org}/actions/policies/{policy_id} + documentation_url: https://docs.github.com/rest/actions/policies?apiVersion=2026-03-10#update-an-organization-actions-policy - name: GET /orgs/{org}/agents/secrets documentation_url: https://docs.github.com/rest/agents/secrets?apiVersion=2026-03-10#list-organization-secrets - name: GET /orgs/{org}/agents/secrets/public-key @@ -127,6 +137,16 @@ operation_overrides: documentation_url: https://docs.github.com/rest/private-registries/organization-configurations?apiVersion=2026-03-10#get-a-private-registry-for-an-organization - name: PATCH /orgs/{org}/private-registries/{secret_name} documentation_url: https://docs.github.com/rest/private-registries/organization-configurations?apiVersion=2026-03-10#update-a-private-registry-for-an-organization + - name: GET /repos/{owner}/{repo}/actions/policies + documentation_url: https://docs.github.com/rest/actions/policies?apiVersion=2026-03-10#list-repository-actions-policies + - name: POST /repos/{owner}/{repo}/actions/policies + documentation_url: https://docs.github.com/rest/actions/policies?apiVersion=2026-03-10#create-a-repository-actions-policy + - name: DELETE /repos/{owner}/{repo}/actions/policies/{policy_id} + documentation_url: https://docs.github.com/rest/actions/policies?apiVersion=2026-03-10#delete-a-repository-actions-policy + - name: GET /repos/{owner}/{repo}/actions/policies/{policy_id} + documentation_url: https://docs.github.com/rest/actions/policies?apiVersion=2026-03-10#get-a-repository-actions-policy + - name: PUT /repos/{owner}/{repo}/actions/policies/{policy_id} + documentation_url: https://docs.github.com/rest/actions/policies?apiVersion=2026-03-10#update-a-repository-actions-policy - name: GET /repos/{owner}/{repo}/agents/organization-secrets documentation_url: https://docs.github.com/rest/agents/secrets?apiVersion=2026-03-10#list-repository-organization-secrets - name: GET /repos/{owner}/{repo}/agents/secrets From 9076c758479ee204e6952b1ad3993e806f48f6a6 Mon Sep 17 00:00:00 2001 From: Iurii Date: Sat, 3 Oct 2026 10:48:07 +0300 Subject: [PATCH 2/2] fix: address linter and coverage issues --- .golangci.yml | 1 + github/actions_policies_test.go | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index e082c3d283b..cce9660e96f 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -349,6 +349,7 @@ linters: - ActionsCacheListOptions.Key - ActionsCacheListOptions.Ref - ActionsCacheListOptions.Sort + - ActionsPolicyListOptions.HasParents - ActiveCommittersListOptions.AdvancedSecurityProduct - AnalysesListOptions.Ref - AnalysesListOptions.SarifID diff --git a/github/actions_policies_test.go b/github/actions_policies_test.go index 275b665c0f9..b61ea3ce2ab 100644 --- a/github/actions_policies_test.go +++ b/github/actions_policies_test.go @@ -75,7 +75,7 @@ func TestActionsService_ListOrganizationPolicies(t *testing.T) { testMethod(t, r, "GET") testHeader(t, r, "X-Github-Api-Version", api20260310) testFormValues(t, r, values{"page": "2", "per_page": "50", "has_parents": "false"}) - fmt.Fprintf(w, `{"total_count":1,"policies":[%s]}`, actionsPolicyResponseJSON) + fmt.Fprintf(w, `{"total_count":1,"policies":[%v]}`, actionsPolicyResponseJSON) }) ctx := t.Context() @@ -96,7 +96,7 @@ func TestActionsService_ListOrganizationPolicies(t *testing.T) { const methodName = "ListOrganizationPolicies" testBadOptions(t, methodName, func() (err error) { - _, _, err = client.Actions.ListOrganizationPolicies(ctx, "\n", nil) + _, _, err = client.Actions.ListOrganizationPolicies(ctx, "\n", &ActionsPolicyListOptions{}) return err }) testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { @@ -255,7 +255,7 @@ func TestActionsService_ListRepositoryPolicies(t *testing.T) { testMethod(t, r, "GET") testHeader(t, r, "X-Github-Api-Version", api20260310) testFormValues(t, r, values{"has_parents": "true"}) - fmt.Fprintf(w, `{"total_count":1,"policies":[%s]}`, actionsPolicyResponseJSON) + fmt.Fprintf(w, `{"total_count":1,"policies":[%v]}`, actionsPolicyResponseJSON) }) ctx := t.Context()