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