github.com/google/go-github/v65@v65.0.0/github/repos_rules.go (about)

     1  // Copyright 2023 The go-github AUTHORS. All rights reserved.
     2  //
     3  // Use of this source code is governed by a BSD-style
     4  // license that can be found in the LICENSE file.
     5  
     6  package github
     7  
     8  import (
     9  	"context"
    10  	"encoding/json"
    11  	"fmt"
    12  )
    13  
    14  // BypassActor represents the bypass actors from a ruleset.
    15  type BypassActor struct {
    16  	ActorID *int64 `json:"actor_id,omitempty"`
    17  	// Possible values for ActorType are: RepositoryRole, Team, Integration, OrganizationAdmin
    18  	ActorType *string `json:"actor_type,omitempty"`
    19  	// Possible values for BypassMode are: always, pull_request
    20  	BypassMode *string `json:"bypass_mode,omitempty"`
    21  }
    22  
    23  // RulesetLink represents a single link object from GitHub ruleset request _links.
    24  type RulesetLink struct {
    25  	HRef *string `json:"href,omitempty"`
    26  }
    27  
    28  // RulesetLinks represents the "_links" object in a Ruleset.
    29  type RulesetLinks struct {
    30  	Self *RulesetLink `json:"self,omitempty"`
    31  }
    32  
    33  // RulesetRefConditionParameters represents the conditions object for ref_names.
    34  type RulesetRefConditionParameters struct {
    35  	Include []string `json:"include"`
    36  	Exclude []string `json:"exclude"`
    37  }
    38  
    39  // RulesetRepositoryNamesConditionParameters represents the conditions object for repository_names.
    40  type RulesetRepositoryNamesConditionParameters struct {
    41  	Include   []string `json:"include"`
    42  	Exclude   []string `json:"exclude"`
    43  	Protected *bool    `json:"protected,omitempty"`
    44  }
    45  
    46  // RulesetRepositoryIDsConditionParameters represents the conditions object for repository_ids.
    47  type RulesetRepositoryIDsConditionParameters struct {
    48  	RepositoryIDs []int64 `json:"repository_ids,omitempty"`
    49  }
    50  
    51  // RulesetRepositoryPropertyTargetParameters represents a repository_property name and values to be used for targeting.
    52  type RulesetRepositoryPropertyTargetParameters struct {
    53  	Name   string   `json:"name"`
    54  	Values []string `json:"property_values"`
    55  	Source string   `json:"source"`
    56  }
    57  
    58  // RulesetRepositoryPropertyConditionParameters represents the conditions object for repository_property.
    59  type RulesetRepositoryPropertyConditionParameters struct {
    60  	Include []RulesetRepositoryPropertyTargetParameters `json:"include"`
    61  	Exclude []RulesetRepositoryPropertyTargetParameters `json:"exclude"`
    62  }
    63  
    64  // RulesetConditions represents the conditions object in a ruleset.
    65  // Set either RepositoryName or RepositoryID or RepositoryProperty, not more than one.
    66  type RulesetConditions struct {
    67  	RefName            *RulesetRefConditionParameters                `json:"ref_name,omitempty"`
    68  	RepositoryName     *RulesetRepositoryNamesConditionParameters    `json:"repository_name,omitempty"`
    69  	RepositoryID       *RulesetRepositoryIDsConditionParameters      `json:"repository_id,omitempty"`
    70  	RepositoryProperty *RulesetRepositoryPropertyConditionParameters `json:"repository_property,omitempty"`
    71  }
    72  
    73  // RulePatternParameters represents the rule pattern parameters.
    74  type RulePatternParameters struct {
    75  	Name *string `json:"name,omitempty"`
    76  	// If Negate is true, the rule will fail if the pattern matches.
    77  	Negate *bool `json:"negate,omitempty"`
    78  	// Possible values for Operator are: starts_with, ends_with, contains, regex
    79  	Operator string `json:"operator"`
    80  	Pattern  string `json:"pattern"`
    81  }
    82  
    83  // RuleFileParameters represents a list of file paths.
    84  type RuleFileParameters struct {
    85  	RestrictedFilePaths *[]string `json:"restricted_file_paths"`
    86  }
    87  
    88  // UpdateAllowsFetchAndMergeRuleParameters represents the update rule parameters.
    89  type UpdateAllowsFetchAndMergeRuleParameters struct {
    90  	UpdateAllowsFetchAndMerge bool `json:"update_allows_fetch_and_merge"`
    91  }
    92  
    93  // RequiredDeploymentEnvironmentsRuleParameters represents the required_deployments rule parameters.
    94  type RequiredDeploymentEnvironmentsRuleParameters struct {
    95  	RequiredDeploymentEnvironments []string `json:"required_deployment_environments"`
    96  }
    97  
    98  // PullRequestRuleParameters represents the pull_request rule parameters.
    99  type PullRequestRuleParameters struct {
   100  	DismissStaleReviewsOnPush      bool `json:"dismiss_stale_reviews_on_push"`
   101  	RequireCodeOwnerReview         bool `json:"require_code_owner_review"`
   102  	RequireLastPushApproval        bool `json:"require_last_push_approval"`
   103  	RequiredApprovingReviewCount   int  `json:"required_approving_review_count"`
   104  	RequiredReviewThreadResolution bool `json:"required_review_thread_resolution"`
   105  }
   106  
   107  // RuleRequiredStatusChecks represents the RequiredStatusChecks for the RequiredStatusChecksRuleParameters object.
   108  type RuleRequiredStatusChecks struct {
   109  	Context       string `json:"context"`
   110  	IntegrationID *int64 `json:"integration_id,omitempty"`
   111  }
   112  
   113  // MergeQueueRuleParameters represents the merge_queue rule parameters.
   114  type MergeQueueRuleParameters struct {
   115  	CheckResponseTimeoutMinutes int `json:"check_response_timeout_minutes"`
   116  	// Possible values for GroupingStrategy are: ALLGREEN, HEADGREEN
   117  	GroupingStrategy  string `json:"grouping_strategy"`
   118  	MaxEntriesToBuild int    `json:"max_entries_to_build"`
   119  	MaxEntriesToMerge int    `json:"max_entries_to_merge"`
   120  	// Possible values for MergeMethod are: MERGE, SQUASH, REBASE
   121  	MergeMethod                  string `json:"merge_method"`
   122  	MinEntriesToMerge            int    `json:"min_entries_to_merge"`
   123  	MinEntriesToMergeWaitMinutes int    `json:"min_entries_to_merge_wait_minutes"`
   124  }
   125  
   126  // RequiredStatusChecksRuleParameters represents the required_status_checks rule parameters.
   127  type RequiredStatusChecksRuleParameters struct {
   128  	DoNotEnforceOnCreate             bool                       `json:"do_not_enforce_on_create"`
   129  	RequiredStatusChecks             []RuleRequiredStatusChecks `json:"required_status_checks"`
   130  	StrictRequiredStatusChecksPolicy bool                       `json:"strict_required_status_checks_policy"`
   131  }
   132  
   133  // RuleRequiredWorkflow represents the Workflow for the RequireWorkflowsRuleParameters object.
   134  type RuleRequiredWorkflow struct {
   135  	Path         string  `json:"path"`
   136  	Ref          *string `json:"ref,omitempty"`
   137  	RepositoryID *int64  `json:"repository_id,omitempty"`
   138  	Sha          *string `json:"sha,omitempty"`
   139  }
   140  
   141  // RequiredWorkflowsRuleParameters represents the workflows rule parameters.
   142  type RequiredWorkflowsRuleParameters struct {
   143  	RequiredWorkflows []*RuleRequiredWorkflow `json:"workflows"`
   144  }
   145  
   146  // RepositoryRule represents a GitHub Rule.
   147  type RepositoryRule struct {
   148  	Type              string           `json:"type"`
   149  	Parameters        *json.RawMessage `json:"parameters,omitempty"`
   150  	RulesetSourceType string           `json:"ruleset_source_type"`
   151  	RulesetSource     string           `json:"ruleset_source"`
   152  	RulesetID         int64            `json:"ruleset_id"`
   153  }
   154  
   155  // UnmarshalJSON implements the json.Unmarshaler interface.
   156  // This helps us handle the fact that RepositoryRule parameter field can be of numerous types.
   157  func (r *RepositoryRule) UnmarshalJSON(data []byte) error {
   158  	type rule RepositoryRule
   159  	var RepositoryRule rule
   160  	if err := json.Unmarshal(data, &RepositoryRule); err != nil {
   161  		return err
   162  	}
   163  
   164  	r.RulesetID = RepositoryRule.RulesetID
   165  	r.RulesetSourceType = RepositoryRule.RulesetSourceType
   166  	r.RulesetSource = RepositoryRule.RulesetSource
   167  	r.Type = RepositoryRule.Type
   168  
   169  	switch RepositoryRule.Type {
   170  	case "creation", "deletion", "non_fast_forward", "required_linear_history", "required_signatures":
   171  		r.Parameters = nil
   172  	case "update":
   173  		if RepositoryRule.Parameters == nil {
   174  			r.Parameters = nil
   175  			return nil
   176  		}
   177  		params := UpdateAllowsFetchAndMergeRuleParameters{}
   178  		if err := json.Unmarshal(*RepositoryRule.Parameters, &params); err != nil {
   179  			return err
   180  		}
   181  
   182  		bytes, _ := json.Marshal(params)
   183  		rawParams := json.RawMessage(bytes)
   184  
   185  		r.Parameters = &rawParams
   186  	case "merge_queue":
   187  		if RepositoryRule.Parameters == nil {
   188  			r.Parameters = nil
   189  			return nil
   190  		}
   191  		params := MergeQueueRuleParameters{}
   192  		if err := json.Unmarshal(*RepositoryRule.Parameters, &params); err != nil {
   193  			return err
   194  		}
   195  
   196  		bytes, _ := json.Marshal(params)
   197  		rawParams := json.RawMessage(bytes)
   198  
   199  		r.Parameters = &rawParams
   200  	case "required_deployments":
   201  		params := RequiredDeploymentEnvironmentsRuleParameters{}
   202  		if err := json.Unmarshal(*RepositoryRule.Parameters, &params); err != nil {
   203  			return err
   204  		}
   205  
   206  		bytes, _ := json.Marshal(params)
   207  		rawParams := json.RawMessage(bytes)
   208  
   209  		r.Parameters = &rawParams
   210  	case "commit_message_pattern", "commit_author_email_pattern", "committer_email_pattern", "branch_name_pattern", "tag_name_pattern":
   211  		params := RulePatternParameters{}
   212  		if err := json.Unmarshal(*RepositoryRule.Parameters, &params); err != nil {
   213  			return err
   214  		}
   215  
   216  		bytes, _ := json.Marshal(params)
   217  		rawParams := json.RawMessage(bytes)
   218  
   219  		r.Parameters = &rawParams
   220  	case "pull_request":
   221  		params := PullRequestRuleParameters{}
   222  		if err := json.Unmarshal(*RepositoryRule.Parameters, &params); err != nil {
   223  			return err
   224  		}
   225  
   226  		bytes, _ := json.Marshal(params)
   227  		rawParams := json.RawMessage(bytes)
   228  
   229  		r.Parameters = &rawParams
   230  	case "required_status_checks":
   231  		params := RequiredStatusChecksRuleParameters{}
   232  		if err := json.Unmarshal(*RepositoryRule.Parameters, &params); err != nil {
   233  			return err
   234  		}
   235  
   236  		bytes, _ := json.Marshal(params)
   237  		rawParams := json.RawMessage(bytes)
   238  
   239  		r.Parameters = &rawParams
   240  	case "workflows":
   241  		params := RequiredWorkflowsRuleParameters{}
   242  		if err := json.Unmarshal(*RepositoryRule.Parameters, &params); err != nil {
   243  			return err
   244  		}
   245  
   246  		bytes, _ := json.Marshal(params)
   247  		rawParams := json.RawMessage(bytes)
   248  
   249  		r.Parameters = &rawParams
   250  	case "file_path_restriction":
   251  		params := RuleFileParameters{}
   252  		if err := json.Unmarshal(*RepositoryRule.Parameters, &params); err != nil {
   253  			return err
   254  		}
   255  		bytes, _ := json.Marshal(params)
   256  		rawParams := json.RawMessage(bytes)
   257  
   258  		r.Parameters = &rawParams
   259  	default:
   260  		r.Type = ""
   261  		r.Parameters = nil
   262  		return fmt.Errorf("RepositoryRule.Type %q is not yet implemented, unable to unmarshal (%#v)", RepositoryRule.Type, RepositoryRule)
   263  	}
   264  
   265  	return nil
   266  }
   267  
   268  // NewMergeQueueRule creates a rule to only allow merges via a merge queue.
   269  func NewMergeQueueRule(params *MergeQueueRuleParameters) (rule *RepositoryRule) {
   270  	if params != nil {
   271  		bytes, _ := json.Marshal(params)
   272  
   273  		rawParams := json.RawMessage(bytes)
   274  
   275  		return &RepositoryRule{
   276  			Type:       "merge_queue",
   277  			Parameters: &rawParams,
   278  		}
   279  	}
   280  	return &RepositoryRule{
   281  		Type: "merge_queue",
   282  	}
   283  }
   284  
   285  // NewCreationRule creates a rule to only allow users with bypass permission to create matching refs.
   286  func NewCreationRule() (rule *RepositoryRule) {
   287  	return &RepositoryRule{
   288  		Type: "creation",
   289  	}
   290  }
   291  
   292  // NewUpdateRule creates a rule to only allow users with bypass permission to update matching refs.
   293  func NewUpdateRule(params *UpdateAllowsFetchAndMergeRuleParameters) (rule *RepositoryRule) {
   294  	if params != nil {
   295  		bytes, _ := json.Marshal(params)
   296  
   297  		rawParams := json.RawMessage(bytes)
   298  
   299  		return &RepositoryRule{
   300  			Type:       "update",
   301  			Parameters: &rawParams,
   302  		}
   303  	}
   304  	return &RepositoryRule{
   305  		Type: "update",
   306  	}
   307  }
   308  
   309  // NewDeletionRule creates a rule to only allow users with bypass permissions to delete matching refs.
   310  func NewDeletionRule() (rule *RepositoryRule) {
   311  	return &RepositoryRule{
   312  		Type: "deletion",
   313  	}
   314  }
   315  
   316  // NewRequiredLinearHistoryRule creates a rule to prevent merge commits from being pushed to matching branches.
   317  func NewRequiredLinearHistoryRule() (rule *RepositoryRule) {
   318  	return &RepositoryRule{
   319  		Type: "required_linear_history",
   320  	}
   321  }
   322  
   323  // NewRequiredDeploymentsRule creates a rule to require environments to be successfully deployed before they can be merged into the matching branches.
   324  func NewRequiredDeploymentsRule(params *RequiredDeploymentEnvironmentsRuleParameters) (rule *RepositoryRule) {
   325  	bytes, _ := json.Marshal(params)
   326  
   327  	rawParams := json.RawMessage(bytes)
   328  
   329  	return &RepositoryRule{
   330  		Type:       "required_deployments",
   331  		Parameters: &rawParams,
   332  	}
   333  }
   334  
   335  // NewRequiredSignaturesRule creates a rule a to require commits pushed to matching branches to have verified signatures.
   336  func NewRequiredSignaturesRule() (rule *RepositoryRule) {
   337  	return &RepositoryRule{
   338  		Type: "required_signatures",
   339  	}
   340  }
   341  
   342  // NewPullRequestRule creates a rule to require all commits be made to a non-target branch and submitted via a pull request before they can be merged.
   343  func NewPullRequestRule(params *PullRequestRuleParameters) (rule *RepositoryRule) {
   344  	bytes, _ := json.Marshal(params)
   345  
   346  	rawParams := json.RawMessage(bytes)
   347  
   348  	return &RepositoryRule{
   349  		Type:       "pull_request",
   350  		Parameters: &rawParams,
   351  	}
   352  }
   353  
   354  // NewRequiredStatusChecksRule creates a rule to require which status checks must pass before branches can be merged into a branch rule.
   355  func NewRequiredStatusChecksRule(params *RequiredStatusChecksRuleParameters) (rule *RepositoryRule) {
   356  	bytes, _ := json.Marshal(params)
   357  
   358  	rawParams := json.RawMessage(bytes)
   359  
   360  	return &RepositoryRule{
   361  		Type:       "required_status_checks",
   362  		Parameters: &rawParams,
   363  	}
   364  }
   365  
   366  // NewNonFastForwardRule creates a rule as part to prevent users with push access from force pushing to matching branches.
   367  func NewNonFastForwardRule() (rule *RepositoryRule) {
   368  	return &RepositoryRule{
   369  		Type: "non_fast_forward",
   370  	}
   371  }
   372  
   373  // NewCommitMessagePatternRule creates a rule to restrict commit message patterns being pushed to matching branches.
   374  func NewCommitMessagePatternRule(params *RulePatternParameters) (rule *RepositoryRule) {
   375  	bytes, _ := json.Marshal(params)
   376  
   377  	rawParams := json.RawMessage(bytes)
   378  
   379  	return &RepositoryRule{
   380  		Type:       "commit_message_pattern",
   381  		Parameters: &rawParams,
   382  	}
   383  }
   384  
   385  // NewCommitAuthorEmailPatternRule creates a rule to restrict commits with author email patterns being merged into matching branches.
   386  func NewCommitAuthorEmailPatternRule(params *RulePatternParameters) (rule *RepositoryRule) {
   387  	bytes, _ := json.Marshal(params)
   388  
   389  	rawParams := json.RawMessage(bytes)
   390  
   391  	return &RepositoryRule{
   392  		Type:       "commit_author_email_pattern",
   393  		Parameters: &rawParams,
   394  	}
   395  }
   396  
   397  // NewCommitterEmailPatternRule creates a rule to restrict commits with committer email patterns being merged into matching branches.
   398  func NewCommitterEmailPatternRule(params *RulePatternParameters) (rule *RepositoryRule) {
   399  	bytes, _ := json.Marshal(params)
   400  
   401  	rawParams := json.RawMessage(bytes)
   402  
   403  	return &RepositoryRule{
   404  		Type:       "committer_email_pattern",
   405  		Parameters: &rawParams,
   406  	}
   407  }
   408  
   409  // NewBranchNamePatternRule creates a rule to restrict branch patterns from being merged into matching branches.
   410  func NewBranchNamePatternRule(params *RulePatternParameters) (rule *RepositoryRule) {
   411  	bytes, _ := json.Marshal(params)
   412  
   413  	rawParams := json.RawMessage(bytes)
   414  
   415  	return &RepositoryRule{
   416  		Type:       "branch_name_pattern",
   417  		Parameters: &rawParams,
   418  	}
   419  }
   420  
   421  // NewTagNamePatternRule creates a rule to restrict tag patterns contained in non-target branches from being merged into matching branches.
   422  func NewTagNamePatternRule(params *RulePatternParameters) (rule *RepositoryRule) {
   423  	bytes, _ := json.Marshal(params)
   424  
   425  	rawParams := json.RawMessage(bytes)
   426  
   427  	return &RepositoryRule{
   428  		Type:       "tag_name_pattern",
   429  		Parameters: &rawParams,
   430  	}
   431  }
   432  
   433  // NewRequiredWorkflowsRule creates a rule to require which status checks must pass before branches can be merged into a branch rule.
   434  func NewRequiredWorkflowsRule(params *RequiredWorkflowsRuleParameters) (rule *RepositoryRule) {
   435  	bytes, _ := json.Marshal(params)
   436  
   437  	rawParams := json.RawMessage(bytes)
   438  
   439  	return &RepositoryRule{
   440  		Type:       "workflows",
   441  		Parameters: &rawParams,
   442  	}
   443  }
   444  
   445  // NewFilePathRestrictionRule creates a rule to restrict file paths from being pushed to.
   446  func NewFilePathRestrictionRule(params *RuleFileParameters) (rule *RepositoryRule) {
   447  	bytes, _ := json.Marshal(params)
   448  
   449  	rawParams := json.RawMessage(bytes)
   450  
   451  	return &RepositoryRule{
   452  		Type:       "file_path_restriction",
   453  		Parameters: &rawParams,
   454  	}
   455  }
   456  
   457  // Ruleset represents a GitHub ruleset object.
   458  type Ruleset struct {
   459  	ID   *int64 `json:"id,omitempty"`
   460  	Name string `json:"name"`
   461  	// Possible values for Target are branch, tag
   462  	Target *string `json:"target,omitempty"`
   463  	// Possible values for SourceType are: Repository, Organization
   464  	SourceType *string `json:"source_type,omitempty"`
   465  	Source     string  `json:"source"`
   466  	// Possible values for Enforcement are: disabled, active, evaluate
   467  	Enforcement  string             `json:"enforcement"`
   468  	BypassActors []*BypassActor     `json:"bypass_actors,omitempty"`
   469  	NodeID       *string            `json:"node_id,omitempty"`
   470  	Links        *RulesetLinks      `json:"_links,omitempty"`
   471  	Conditions   *RulesetConditions `json:"conditions,omitempty"`
   472  	Rules        []*RepositoryRule  `json:"rules,omitempty"`
   473  }
   474  
   475  // rulesetNoOmitBypassActors represents a GitHub ruleset object. The struct does not omit bypassActors if the field is nil or an empty array is passed.
   476  type rulesetNoOmitBypassActors struct {
   477  	ID   *int64 `json:"id,omitempty"`
   478  	Name string `json:"name"`
   479  	// Possible values for Target are branch, tag
   480  	Target *string `json:"target,omitempty"`
   481  	// Possible values for SourceType are: Repository, Organization
   482  	SourceType *string `json:"source_type,omitempty"`
   483  	Source     string  `json:"source"`
   484  	// Possible values for Enforcement are: disabled, active, evaluate
   485  	Enforcement  string             `json:"enforcement"`
   486  	BypassActors []*BypassActor     `json:"bypass_actors"`
   487  	NodeID       *string            `json:"node_id,omitempty"`
   488  	Links        *RulesetLinks      `json:"_links,omitempty"`
   489  	Conditions   *RulesetConditions `json:"conditions,omitempty"`
   490  	Rules        []*RepositoryRule  `json:"rules,omitempty"`
   491  }
   492  
   493  // GetRulesForBranch gets all the rules that apply to the specified branch.
   494  //
   495  // GitHub API docs: https://docs.github.com/rest/repos/rules#get-rules-for-a-branch
   496  //
   497  //meta:operation GET /repos/{owner}/{repo}/rules/branches/{branch}
   498  func (s *RepositoriesService) GetRulesForBranch(ctx context.Context, owner, repo, branch string) ([]*RepositoryRule, *Response, error) {
   499  	u := fmt.Sprintf("repos/%v/%v/rules/branches/%v", owner, repo, branch)
   500  
   501  	req, err := s.client.NewRequest("GET", u, nil)
   502  	if err != nil {
   503  		return nil, nil, err
   504  	}
   505  
   506  	var rules []*RepositoryRule
   507  	resp, err := s.client.Do(ctx, req, &rules)
   508  	if err != nil {
   509  		return nil, resp, err
   510  	}
   511  
   512  	return rules, resp, nil
   513  }
   514  
   515  // GetAllRulesets gets all the rules that apply to the specified repository.
   516  // If includesParents is true, rulesets configured at the organization level that apply to the repository will be returned.
   517  //
   518  // GitHub API docs: https://docs.github.com/rest/repos/rules#get-all-repository-rulesets
   519  //
   520  //meta:operation GET /repos/{owner}/{repo}/rulesets
   521  func (s *RepositoriesService) GetAllRulesets(ctx context.Context, owner, repo string, includesParents bool) ([]*Ruleset, *Response, error) {
   522  	u := fmt.Sprintf("repos/%v/%v/rulesets?includes_parents=%v", owner, repo, includesParents)
   523  
   524  	req, err := s.client.NewRequest("GET", u, nil)
   525  	if err != nil {
   526  		return nil, nil, err
   527  	}
   528  
   529  	var ruleset []*Ruleset
   530  	resp, err := s.client.Do(ctx, req, &ruleset)
   531  	if err != nil {
   532  		return nil, resp, err
   533  	}
   534  
   535  	return ruleset, resp, nil
   536  }
   537  
   538  // CreateRuleset creates a ruleset for the specified repository.
   539  //
   540  // GitHub API docs: https://docs.github.com/rest/repos/rules#create-a-repository-ruleset
   541  //
   542  //meta:operation POST /repos/{owner}/{repo}/rulesets
   543  func (s *RepositoriesService) CreateRuleset(ctx context.Context, owner, repo string, rs *Ruleset) (*Ruleset, *Response, error) {
   544  	u := fmt.Sprintf("repos/%v/%v/rulesets", owner, repo)
   545  
   546  	req, err := s.client.NewRequest("POST", u, rs)
   547  	if err != nil {
   548  		return nil, nil, err
   549  	}
   550  
   551  	var ruleset *Ruleset
   552  	resp, err := s.client.Do(ctx, req, &ruleset)
   553  	if err != nil {
   554  		return nil, resp, err
   555  	}
   556  
   557  	return ruleset, resp, nil
   558  }
   559  
   560  // GetRuleset gets a ruleset for the specified repository.
   561  // If includesParents is true, rulesets configured at the organization level that apply to the repository will be returned.
   562  //
   563  // GitHub API docs: https://docs.github.com/rest/repos/rules#get-a-repository-ruleset
   564  //
   565  //meta:operation GET /repos/{owner}/{repo}/rulesets/{ruleset_id}
   566  func (s *RepositoriesService) GetRuleset(ctx context.Context, owner, repo string, rulesetID int64, includesParents bool) (*Ruleset, *Response, error) {
   567  	u := fmt.Sprintf("repos/%v/%v/rulesets/%v?includes_parents=%v", owner, repo, rulesetID, includesParents)
   568  
   569  	req, err := s.client.NewRequest("GET", u, nil)
   570  	if err != nil {
   571  		return nil, nil, err
   572  	}
   573  
   574  	var ruleset *Ruleset
   575  	resp, err := s.client.Do(ctx, req, &ruleset)
   576  	if err != nil {
   577  		return nil, resp, err
   578  	}
   579  
   580  	return ruleset, resp, nil
   581  }
   582  
   583  // UpdateRuleset updates a ruleset for the specified repository.
   584  //
   585  // GitHub API docs: https://docs.github.com/rest/repos/rules#update-a-repository-ruleset
   586  //
   587  //meta:operation PUT /repos/{owner}/{repo}/rulesets/{ruleset_id}
   588  func (s *RepositoriesService) UpdateRuleset(ctx context.Context, owner, repo string, rulesetID int64, rs *Ruleset) (*Ruleset, *Response, error) {
   589  	u := fmt.Sprintf("repos/%v/%v/rulesets/%v", owner, repo, rulesetID)
   590  
   591  	req, err := s.client.NewRequest("PUT", u, rs)
   592  	if err != nil {
   593  		return nil, nil, err
   594  	}
   595  
   596  	var ruleset *Ruleset
   597  	resp, err := s.client.Do(ctx, req, &ruleset)
   598  	if err != nil {
   599  		return nil, resp, err
   600  	}
   601  
   602  	return ruleset, resp, nil
   603  }
   604  
   605  // UpdateRulesetNoBypassActor updates a ruleset for the specified repository.
   606  //
   607  // This function is necessary as the UpdateRuleset function does not marshal ByPassActor if passed as nil or an empty array.
   608  //
   609  // GitHub API docs: https://docs.github.com/rest/repos/rules#update-a-repository-ruleset
   610  //
   611  //meta:operation PUT /repos/{owner}/{repo}/rulesets/{ruleset_id}
   612  func (s *RepositoriesService) UpdateRulesetNoBypassActor(ctx context.Context, owner, repo string, rulesetID int64, rs *Ruleset) (*Ruleset, *Response, error) {
   613  	u := fmt.Sprintf("repos/%v/%v/rulesets/%v", owner, repo, rulesetID)
   614  
   615  	rsNoBypassActor := &rulesetNoOmitBypassActors{}
   616  
   617  	if rs != nil {
   618  		rsNoBypassActor = &rulesetNoOmitBypassActors{
   619  			ID:           rs.ID,
   620  			Name:         rs.Name,
   621  			Target:       rs.Target,
   622  			SourceType:   rs.SourceType,
   623  			Source:       rs.Source,
   624  			Enforcement:  rs.Enforcement,
   625  			BypassActors: rs.BypassActors,
   626  			NodeID:       rs.NodeID,
   627  			Links:        rs.Links,
   628  			Conditions:   rs.Conditions,
   629  			Rules:        rs.Rules,
   630  		}
   631  	}
   632  
   633  	req, err := s.client.NewRequest("PUT", u, rsNoBypassActor)
   634  	if err != nil {
   635  		return nil, nil, err
   636  	}
   637  
   638  	var ruleSet *Ruleset
   639  	resp, err := s.client.Do(ctx, req, &ruleSet)
   640  	if err != nil {
   641  		return nil, resp, err
   642  	}
   643  
   644  	return ruleSet, resp, nil
   645  }
   646  
   647  // DeleteRuleset deletes a ruleset for the specified repository.
   648  //
   649  // GitHub API docs: https://docs.github.com/rest/repos/rules#delete-a-repository-ruleset
   650  //
   651  //meta:operation DELETE /repos/{owner}/{repo}/rulesets/{ruleset_id}
   652  func (s *RepositoriesService) DeleteRuleset(ctx context.Context, owner, repo string, rulesetID int64) (*Response, error) {
   653  	u := fmt.Sprintf("repos/%v/%v/rulesets/%v", owner, repo, rulesetID)
   654  
   655  	req, err := s.client.NewRequest("DELETE", u, nil)
   656  	if err != nil {
   657  		return nil, err
   658  	}
   659  
   660  	return s.client.Do(ctx, req, nil)
   661  }