github.com/google/go-github/v53@v53.2.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: Team, Integration
    18  	ActorType *string `json:"actor_type,omitempty"`
    19  }
    20  
    21  // RulesetLink represents a single link object from GitHub ruleset request _links.
    22  type RulesetLink struct {
    23  	HRef *string `json:"href,omitempty"`
    24  }
    25  
    26  // RulesetLinks represents the "_links" object in a Ruleset.
    27  type RulesetLinks struct {
    28  	Self *RulesetLink `json:"self,omitempty"`
    29  }
    30  
    31  // RulesetRefConditionParameters represents the conditions object for ref_names.
    32  type RulesetRefConditionParameters struct {
    33  	Include []string `json:"include"`
    34  	Exclude []string `json:"exclude"`
    35  }
    36  
    37  // RulesetRepositoryConditionParameters represents the conditions object for repository_names.
    38  type RulesetRepositoryConditionParameters struct {
    39  	Include   []string `json:"include,omitempty"`
    40  	Exclude   []string `json:"exclude,omitempty"`
    41  	Protected *bool    `json:"protected,omitempty"`
    42  }
    43  
    44  // RulesetCondition represents the conditions object in a ruleset.
    45  type RulesetConditions struct {
    46  	RefName        *RulesetRefConditionParameters        `json:"ref_name,omitempty"`
    47  	RepositoryName *RulesetRepositoryConditionParameters `json:"repository_name,omitempty"`
    48  }
    49  
    50  // RulePatternParameters represents the rule pattern parameters.
    51  type RulePatternParameters struct {
    52  	Name *string `json:"name,omitempty"`
    53  	// If Negate is true, the rule will fail if the pattern matches.
    54  	Negate *bool `json:"negate,omitempty"`
    55  	// Possible values for Operator are: starts_with, ends_with, contains, regex
    56  	Operator string `json:"operator"`
    57  	Pattern  string `json:"pattern"`
    58  }
    59  
    60  // UpdateAllowsFetchAndMergeRuleParameters represents the update rule parameters.
    61  type UpdateAllowsFetchAndMergeRuleParameters struct {
    62  	UpdateAllowsFetchAndMerge bool `json:"update_allows_fetch_and_merge"`
    63  }
    64  
    65  // RequiredDeploymentEnvironmentsRuleParameters represents the required_deployments rule parameters.
    66  type RequiredDeploymentEnvironmentsRuleParameters struct {
    67  	RequiredDeploymentEnvironments []string `json:"required_deployment_environments"`
    68  }
    69  
    70  // PullRequestRuleParameters represents the pull_request rule parameters.
    71  type PullRequestRuleParameters struct {
    72  	DismissStaleReviewsOnPush      bool `json:"dismiss_stale_reviews_on_push"`
    73  	RequireCodeOwnerReview         bool `json:"require_code_owner_review"`
    74  	RequireLastPushApproval        bool `json:"require_last_push_approval"`
    75  	RequiredApprovingReviewCount   int  `json:"required_approving_review_count"`
    76  	RequiredReviewThreadResolution bool `json:"required_review_thread_resolution"`
    77  }
    78  
    79  // RuleRequiredStatusChecks represents the RequiredStatusChecks for the RequiredStatusChecksRuleParameters object.
    80  type RuleRequiredStatusChecks struct {
    81  	Context       string `json:"context"`
    82  	IntegrationID *int64 `json:"integration_id,omitempty"`
    83  }
    84  
    85  // RequiredStatusChecksRuleParameters represents the required_status_checks rule parameters.
    86  type RequiredStatusChecksRuleParameters struct {
    87  	RequiredStatusChecks             []RuleRequiredStatusChecks `json:"required_status_checks"`
    88  	StrictRequiredStatusChecksPolicy bool                       `json:"strict_required_status_checks_policy"`
    89  }
    90  
    91  // RepositoryRule represents a GitHub Rule.
    92  type RepositoryRule struct {
    93  	Type       string           `json:"type"`
    94  	Parameters *json.RawMessage `json:"parameters,omitempty"`
    95  }
    96  
    97  // UnmarshalJSON implements the json.Unmarshaler interface.
    98  // This helps us handle the fact that RepositoryRule parameter field can be of numerous types.
    99  func (r *RepositoryRule) UnmarshalJSON(data []byte) error {
   100  	type rule RepositoryRule
   101  	var RepositoryRule rule
   102  	if err := json.Unmarshal(data, &RepositoryRule); err != nil {
   103  		return err
   104  	}
   105  
   106  	r.Type = RepositoryRule.Type
   107  
   108  	switch RepositoryRule.Type {
   109  	case "creation", "deletion", "required_linear_history", "required_signatures", "non_fast_forward":
   110  		r.Parameters = nil
   111  	case "update":
   112  		params := UpdateAllowsFetchAndMergeRuleParameters{}
   113  		if err := json.Unmarshal(*RepositoryRule.Parameters, &params); err != nil {
   114  			return err
   115  		}
   116  
   117  		bytes, _ := json.Marshal(params)
   118  		rawParams := json.RawMessage(bytes)
   119  
   120  		r.Parameters = &rawParams
   121  	case "required_deployments":
   122  		params := RequiredDeploymentEnvironmentsRuleParameters{}
   123  		if err := json.Unmarshal(*RepositoryRule.Parameters, &params); err != nil {
   124  			return err
   125  		}
   126  
   127  		bytes, _ := json.Marshal(params)
   128  		rawParams := json.RawMessage(bytes)
   129  
   130  		r.Parameters = &rawParams
   131  	case "commit_message_pattern", "commit_author_email_pattern", "committer_email_pattern", "branch_name_pattern", "tag_name_pattern":
   132  		params := RulePatternParameters{}
   133  		if err := json.Unmarshal(*RepositoryRule.Parameters, &params); err != nil {
   134  			return err
   135  		}
   136  
   137  		bytes, _ := json.Marshal(params)
   138  		rawParams := json.RawMessage(bytes)
   139  
   140  		r.Parameters = &rawParams
   141  	case "pull_request":
   142  		params := PullRequestRuleParameters{}
   143  		if err := json.Unmarshal(*RepositoryRule.Parameters, &params); err != nil {
   144  			return err
   145  		}
   146  
   147  		bytes, _ := json.Marshal(params)
   148  		rawParams := json.RawMessage(bytes)
   149  
   150  		r.Parameters = &rawParams
   151  	case "required_status_checks":
   152  		params := RequiredStatusChecksRuleParameters{}
   153  		if err := json.Unmarshal(*RepositoryRule.Parameters, &params); err != nil {
   154  			return err
   155  		}
   156  
   157  		bytes, _ := json.Marshal(params)
   158  		rawParams := json.RawMessage(bytes)
   159  
   160  		r.Parameters = &rawParams
   161  	default:
   162  		r.Type = ""
   163  		r.Parameters = nil
   164  		return fmt.Errorf("RepositoryRule.Type %T is not yet implemented, unable to unmarshal", RepositoryRule.Type)
   165  	}
   166  
   167  	return nil
   168  }
   169  
   170  // NewCreationRule creates a rule to only allow users with bypass permission to create matching refs.
   171  func NewCreationRule() (rule *RepositoryRule) {
   172  	return &RepositoryRule{
   173  		Type: "creation",
   174  	}
   175  }
   176  
   177  // NewUpdateRule creates a rule to only allow users with bypass permission to update matching refs.
   178  func NewUpdateRule(params *UpdateAllowsFetchAndMergeRuleParameters) (rule *RepositoryRule) {
   179  	bytes, _ := json.Marshal(params)
   180  
   181  	rawParams := json.RawMessage(bytes)
   182  
   183  	return &RepositoryRule{
   184  		Type:       "update",
   185  		Parameters: &rawParams,
   186  	}
   187  }
   188  
   189  // NewDeletionRule creates a rule to only allow users with bypass permissions to delete matching refs.
   190  func NewDeletionRule() (rule *RepositoryRule) {
   191  	return &RepositoryRule{
   192  		Type: "deletion",
   193  	}
   194  }
   195  
   196  // NewRequiredLinearHistoryRule creates a rule to prevent merge commits from being pushed to matching branches.
   197  func NewRequiredLinearHistoryRule() (rule *RepositoryRule) {
   198  	return &RepositoryRule{
   199  		Type: "required_linear_history",
   200  	}
   201  }
   202  
   203  // NewRequiredDeploymentsRule creates a rule to require environments to be successfully deployed before they can be merged into the matching branches.
   204  func NewRequiredDeploymentsRule(params *RequiredDeploymentEnvironmentsRuleParameters) (rule *RepositoryRule) {
   205  	bytes, _ := json.Marshal(params)
   206  
   207  	rawParams := json.RawMessage(bytes)
   208  
   209  	return &RepositoryRule{
   210  		Type:       "required_deployments",
   211  		Parameters: &rawParams,
   212  	}
   213  }
   214  
   215  // NewRequiredSignaturesRule creates a rule a to require commits pushed to matching branches to have verified signatures.
   216  func NewRequiredSignaturesRule() (rule *RepositoryRule) {
   217  	return &RepositoryRule{
   218  		Type: "required_signatures",
   219  	}
   220  }
   221  
   222  // 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.
   223  func NewPullRequestRule(params *PullRequestRuleParameters) (rule *RepositoryRule) {
   224  	bytes, _ := json.Marshal(params)
   225  
   226  	rawParams := json.RawMessage(bytes)
   227  
   228  	return &RepositoryRule{
   229  		Type:       "pull_request",
   230  		Parameters: &rawParams,
   231  	}
   232  }
   233  
   234  // NewRequiredStatusChecksRule creates a rule to require which status checks must pass before branches can be merged into a branch rule.
   235  func NewRequiredStatusChecksRule(params *RequiredStatusChecksRuleParameters) (rule *RepositoryRule) {
   236  	bytes, _ := json.Marshal(params)
   237  
   238  	rawParams := json.RawMessage(bytes)
   239  
   240  	return &RepositoryRule{
   241  		Type:       "required_status_checks",
   242  		Parameters: &rawParams,
   243  	}
   244  }
   245  
   246  // NewNonFastForwardRule creates a rule as part to prevent users with push access from force pushing to matching branches.
   247  func NewNonFastForwardRule() (rule *RepositoryRule) {
   248  	return &RepositoryRule{
   249  		Type: "non_fast_forward",
   250  	}
   251  }
   252  
   253  // NewCommitMessagePatternRule creates a rule to restrict commit message patterns being pushed to matching branches.
   254  func NewCommitMessagePatternRule(params *RulePatternParameters) (rule *RepositoryRule) {
   255  	bytes, _ := json.Marshal(params)
   256  
   257  	rawParams := json.RawMessage(bytes)
   258  
   259  	return &RepositoryRule{
   260  		Type:       "commit_message_pattern",
   261  		Parameters: &rawParams,
   262  	}
   263  }
   264  
   265  // NewCommitAuthorEmailPatternRule creates a rule to restrict commits with author email patterns being merged into matching branches.
   266  func NewCommitAuthorEmailPatternRule(params *RulePatternParameters) (rule *RepositoryRule) {
   267  	bytes, _ := json.Marshal(params)
   268  
   269  	rawParams := json.RawMessage(bytes)
   270  
   271  	return &RepositoryRule{
   272  		Type:       "commit_author_email_pattern",
   273  		Parameters: &rawParams,
   274  	}
   275  }
   276  
   277  // NewCommitterEmailPatternRule creates a rule to restrict commits with committer email patterns being merged into matching branches.
   278  func NewCommitterEmailPatternRule(params *RulePatternParameters) (rule *RepositoryRule) {
   279  	bytes, _ := json.Marshal(params)
   280  
   281  	rawParams := json.RawMessage(bytes)
   282  
   283  	return &RepositoryRule{
   284  		Type:       "committer_email_pattern",
   285  		Parameters: &rawParams,
   286  	}
   287  }
   288  
   289  // NewBranchNamePatternRule creates a rule to restrict branch patterns from being merged into matching branches.
   290  func NewBranchNamePatternRule(params *RulePatternParameters) (rule *RepositoryRule) {
   291  	bytes, _ := json.Marshal(params)
   292  
   293  	rawParams := json.RawMessage(bytes)
   294  
   295  	return &RepositoryRule{
   296  		Type:       "branch_name_pattern",
   297  		Parameters: &rawParams,
   298  	}
   299  }
   300  
   301  // NewTagNamePatternRule creates a rule to restrict tag patterns contained in non-target branches from being merged into matching branches.
   302  func NewTagNamePatternRule(params *RulePatternParameters) (rule *RepositoryRule) {
   303  	bytes, _ := json.Marshal(params)
   304  
   305  	rawParams := json.RawMessage(bytes)
   306  
   307  	return &RepositoryRule{
   308  		Type:       "tag_name_pattern",
   309  		Parameters: &rawParams,
   310  	}
   311  }
   312  
   313  // Ruleset represents a GitHub ruleset object.
   314  type Ruleset struct {
   315  	ID   int64  `json:"id"`
   316  	Name string `json:"name"`
   317  	// Possible values for Target are branch, tag
   318  	Target *string `json:"target,omitempty"`
   319  	// Possible values for SourceType are: Repository, Organization
   320  	SourceType *string `json:"source_type,omitempty"`
   321  	Source     string  `json:"source"`
   322  	// Possible values for Enforcement are: disabled, active, evaluate
   323  	Enforcement string `json:"enforcement"`
   324  	// Possible values for BypassMode are: none, repository, organization
   325  	BypassMode   *string            `json:"bypass_mode,omitempty"`
   326  	BypassActors []*BypassActor     `json:"bypass_actors,omitempty"`
   327  	NodeID       *string            `json:"node_id,omitempty"`
   328  	Links        *RulesetLinks      `json:"_links,omitempty"`
   329  	Conditions   *RulesetConditions `json:"conditions,omitempty"`
   330  	Rules        []*RepositoryRule  `json:"rules,omitempty"`
   331  }
   332  
   333  // GetRulesForBranch gets all the rules that apply to the specified branch.
   334  //
   335  // GitHub API docs: https://docs.github.com/en/rest/repos/rules#get-rules-for-a-branch
   336  func (s *RepositoriesService) GetRulesForBranch(ctx context.Context, owner, repo, branch string) ([]*RepositoryRule, *Response, error) {
   337  	u := fmt.Sprintf("repos/%v/%v/rules/branches/%v", owner, repo, branch)
   338  
   339  	req, err := s.client.NewRequest("GET", u, nil)
   340  	if err != nil {
   341  		return nil, nil, err
   342  	}
   343  
   344  	var rules []*RepositoryRule
   345  	resp, err := s.client.Do(ctx, req, &rules)
   346  	if err != nil {
   347  		return nil, resp, err
   348  	}
   349  
   350  	return rules, resp, nil
   351  }
   352  
   353  // GetAllRulesets gets all the rules that apply to the specified repository.
   354  // If includesParents is true, rulesets configured at the organization level that apply to the repository will be returned.
   355  //
   356  // GitHub API docs: https://docs.github.com/en/rest/repos/rules#get-all-repository-rulesets
   357  func (s *RepositoriesService) GetAllRulesets(ctx context.Context, owner, repo string, includesParents bool) ([]*Ruleset, *Response, error) {
   358  	u := fmt.Sprintf("repos/%v/%v/rulesets?includes_parents=%v", owner, repo, includesParents)
   359  
   360  	req, err := s.client.NewRequest("GET", u, nil)
   361  	if err != nil {
   362  		return nil, nil, err
   363  	}
   364  
   365  	var ruleset []*Ruleset
   366  	resp, err := s.client.Do(ctx, req, &ruleset)
   367  	if err != nil {
   368  		return nil, resp, err
   369  	}
   370  
   371  	return ruleset, resp, nil
   372  }
   373  
   374  // CreateRuleset creates a ruleset for the specified repository.
   375  //
   376  // GitHub API docs: https://docs.github.com/en/rest/repos/rules#create-a-repository-ruleset
   377  func (s *RepositoriesService) CreateRuleset(ctx context.Context, owner, repo string, rs *Ruleset) (*Ruleset, *Response, error) {
   378  	u := fmt.Sprintf("repos/%v/%v/rulesets", owner, repo)
   379  
   380  	req, err := s.client.NewRequest("POST", u, rs)
   381  	if err != nil {
   382  		return nil, nil, err
   383  	}
   384  
   385  	var ruleset *Ruleset
   386  	resp, err := s.client.Do(ctx, req, &ruleset)
   387  	if err != nil {
   388  		return nil, resp, err
   389  	}
   390  
   391  	return ruleset, resp, nil
   392  }
   393  
   394  // GetRuleset gets a ruleset for the specified repository.
   395  // If includesParents is true, rulesets configured at the organization level that apply to the repository will be returned.
   396  //
   397  // GitHub API docs: https://docs.github.com/en/rest/repos/rules#get-a-repository-ruleset
   398  func (s *RepositoriesService) GetRuleset(ctx context.Context, owner, repo string, rulesetID int64, includesParents bool) (*Ruleset, *Response, error) {
   399  	u := fmt.Sprintf("repos/%v/%v/rulesets/%v?includes_parents=%v", owner, repo, rulesetID, includesParents)
   400  
   401  	req, err := s.client.NewRequest("GET", u, nil)
   402  	if err != nil {
   403  		return nil, nil, err
   404  	}
   405  
   406  	var ruleset *Ruleset
   407  	resp, err := s.client.Do(ctx, req, &ruleset)
   408  	if err != nil {
   409  		return nil, resp, err
   410  	}
   411  
   412  	return ruleset, resp, nil
   413  }
   414  
   415  // UpdateRuleset updates a ruleset for the specified repository.
   416  //
   417  // GitHub API docs: https://docs.github.com/en/rest/repos/rules#update-a-repository-ruleset
   418  func (s *RepositoriesService) UpdateRuleset(ctx context.Context, owner, repo string, rulesetID int64, rs *Ruleset) (*Ruleset, *Response, error) {
   419  	u := fmt.Sprintf("repos/%v/%v/rulesets/%v", owner, repo, rulesetID)
   420  
   421  	req, err := s.client.NewRequest("PUT", u, rs)
   422  	if err != nil {
   423  		return nil, nil, err
   424  	}
   425  
   426  	var ruleset *Ruleset
   427  	resp, err := s.client.Do(ctx, req, &ruleset)
   428  	if err != nil {
   429  		return nil, resp, err
   430  	}
   431  
   432  	return ruleset, resp, nil
   433  }
   434  
   435  // DeleteRuleset deletes a ruleset for the specified repository.
   436  //
   437  // GitHub API docs: https://docs.github.com/en/rest/repos/rules#delete-a-repository-ruleset
   438  func (s *RepositoriesService) DeleteRuleset(ctx context.Context, owner, repo string, rulesetID int64) (*Response, error) {
   439  	u := fmt.Sprintf("repos/%v/%v/rulesets/%v", owner, repo, rulesetID)
   440  
   441  	req, err := s.client.NewRequest("DELETE", u, nil)
   442  	if err != nil {
   443  		return nil, err
   444  	}
   445  
   446  	return s.client.Do(ctx, req, nil)
   447  }