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, ¶ms); 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, ¶ms); 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, ¶ms); 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, ¶ms); 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, ¶ms); 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 }