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