github.com/google/go-github/v69@v69.2.0/github/rules_test.go (about) 1 // Copyright 2025 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 "encoding/json" 10 "testing" 11 12 "github.com/google/go-cmp/cmp" 13 ) 14 15 func TestRulesetRules(t *testing.T) { 16 t.Parallel() 17 tests := []struct { 18 name string 19 rules *RepositoryRulesetRules 20 json string 21 }{ 22 {"empty", &RepositoryRulesetRules{}, `[]`}, 23 { 24 "single_rule_with_empty_params", 25 &RepositoryRulesetRules{Creation: &EmptyRuleParameters{}}, 26 `[{"type":"creation"}]`, 27 }, 28 { 29 "single_rule_with_required_params", 30 &RepositoryRulesetRules{ 31 RequiredDeployments: &RequiredDeploymentsRuleParameters{ 32 RequiredDeploymentEnvironments: []string{"test"}, 33 }, 34 }, 35 `[{"type":"required_deployments","parameters":{"required_deployment_environments":["test"]}}]`, 36 }, 37 { 38 "all_rules_with_required_params", 39 &RepositoryRulesetRules{ 40 Creation: &EmptyRuleParameters{}, 41 Update: &UpdateRuleParameters{}, 42 Deletion: &EmptyRuleParameters{}, 43 RequiredLinearHistory: &EmptyRuleParameters{}, 44 MergeQueue: &MergeQueueRuleParameters{ 45 CheckResponseTimeoutMinutes: 5, 46 GroupingStrategy: MergeGroupingStrategyAllGreen, 47 MaxEntriesToBuild: 10, 48 MaxEntriesToMerge: 20, 49 MergeMethod: MergeMethodSquash, 50 MinEntriesToMerge: 1, 51 MinEntriesToMergeWaitMinutes: 15, 52 }, 53 RequiredDeployments: &RequiredDeploymentsRuleParameters{ 54 RequiredDeploymentEnvironments: []string{"test1", "test2"}, 55 }, 56 RequiredSignatures: &EmptyRuleParameters{}, 57 PullRequest: &PullRequestRuleParameters{ 58 AllowedMergeMethods: []MergeMethod{ 59 MergeMethodSquash, 60 MergeMethodRebase, 61 }, 62 DismissStaleReviewsOnPush: true, 63 RequireCodeOwnerReview: true, 64 RequireLastPushApproval: true, 65 RequiredApprovingReviewCount: 2, 66 RequiredReviewThreadResolution: true, 67 }, 68 RequiredStatusChecks: &RequiredStatusChecksRuleParameters{ 69 RequiredStatusChecks: []*RuleStatusCheck{ 70 {Context: "test1"}, 71 {Context: "test2"}, 72 }, 73 StrictRequiredStatusChecksPolicy: true, 74 }, 75 NonFastForward: &EmptyRuleParameters{}, 76 CommitMessagePattern: &PatternRuleParameters{ 77 Operator: PatternRuleOperatorStartsWith, 78 Pattern: "test", 79 }, 80 CommitAuthorEmailPattern: &PatternRuleParameters{ 81 Operator: PatternRuleOperatorStartsWith, 82 Pattern: "test", 83 }, 84 CommitterEmailPattern: &PatternRuleParameters{ 85 Operator: PatternRuleOperatorStartsWith, 86 Pattern: "test", 87 }, 88 BranchNamePattern: &PatternRuleParameters{ 89 Operator: PatternRuleOperatorStartsWith, 90 Pattern: "test", 91 }, 92 TagNamePattern: &PatternRuleParameters{ 93 Operator: PatternRuleOperatorStartsWith, 94 Pattern: "test", 95 }, 96 FilePathRestriction: &FilePathRestrictionRuleParameters{ 97 RestrictedFilePaths: []string{"test1", "test2"}, 98 }, 99 MaxFilePathLength: &MaxFilePathLengthRuleParameters{MaxFilePathLength: 512}, 100 FileExtensionRestriction: &FileExtensionRestrictionRuleParameters{ 101 RestrictedFileExtensions: []string{".exe", ".pkg"}, 102 }, 103 MaxFileSize: &MaxFileSizeRuleParameters{MaxFileSize: 1024}, 104 Workflows: &WorkflowsRuleParameters{ 105 Workflows: []*RuleWorkflow{ 106 {Path: ".github/workflows/test1.yaml"}, 107 {Path: ".github/workflows/test2.yaml"}, 108 }, 109 }, 110 CodeScanning: &CodeScanningRuleParameters{ 111 CodeScanningTools: []*RuleCodeScanningTool{ 112 { 113 AlertsThreshold: CodeScanningAlertsThresholdAll, 114 SecurityAlertsThreshold: CodeScanningSecurityAlertsThresholdAll, 115 Tool: "test", 116 }, 117 { 118 AlertsThreshold: CodeScanningAlertsThresholdNone, 119 SecurityAlertsThreshold: CodeScanningSecurityAlertsThresholdNone, 120 Tool: "test", 121 }, 122 }, 123 }, 124 }, 125 `[{"type":"creation"},{"type":"update"},{"type":"deletion"},{"type":"required_linear_history"},{"type":"merge_queue","parameters":{"check_response_timeout_minutes":5,"grouping_strategy":"ALLGREEN","max_entries_to_build":10,"max_entries_to_merge":20,"merge_method":"squash","min_entries_to_merge":1,"min_entries_to_merge_wait_minutes":15}},{"type":"required_deployments","parameters":{"required_deployment_environments":["test1","test2"]}},{"type":"required_signatures"},{"type":"pull_request","parameters":{"allowed_merge_methods":["squash","rebase"],"dismiss_stale_reviews_on_push":true,"require_code_owner_review":true,"require_last_push_approval":true,"required_approving_review_count":2,"required_review_thread_resolution":true}},{"type":"required_status_checks","parameters":{"required_status_checks":[{"context":"test1"},{"context":"test2"}],"strict_required_status_checks_policy":true}},{"type":"non_fast_forward"},{"type":"commit_message_pattern","parameters":{"operator":"starts_with","pattern":"test"}},{"type":"commit_author_email_pattern","parameters":{"operator":"starts_with","pattern":"test"}},{"type":"committer_email_pattern","parameters":{"operator":"starts_with","pattern":"test"}},{"type":"branch_name_pattern","parameters":{"operator":"starts_with","pattern":"test"}},{"type":"tag_name_pattern","parameters":{"operator":"starts_with","pattern":"test"}},{"type":"file_path_restriction","parameters":{"restricted_file_paths":["test1","test2"]}},{"type":"max_file_path_length","parameters":{"max_file_path_length":512}},{"type":"file_extension_restriction","parameters":{"restricted_file_extensions":[".exe",".pkg"]}},{"type":"max_file_size","parameters":{"max_file_size":1024}},{"type":"workflows","parameters":{"workflows":[{"path":".github/workflows/test1.yaml"},{"path":".github/workflows/test2.yaml"}]}},{"type":"code_scanning","parameters":{"code_scanning_tools":[{"alerts_threshold":"all","security_alerts_threshold":"all","tool":"test"},{"alerts_threshold":"none","security_alerts_threshold":"none","tool":"test"}]}}]`, 126 }, 127 { 128 "all_rules_with_all_params", 129 &RepositoryRulesetRules{ 130 Creation: &EmptyRuleParameters{}, 131 Update: &UpdateRuleParameters{UpdateAllowsFetchAndMerge: true}, 132 Deletion: &EmptyRuleParameters{}, 133 RequiredLinearHistory: &EmptyRuleParameters{}, 134 MergeQueue: &MergeQueueRuleParameters{ 135 CheckResponseTimeoutMinutes: 5, 136 GroupingStrategy: MergeGroupingStrategyAllGreen, 137 MaxEntriesToBuild: 10, 138 MaxEntriesToMerge: 20, 139 MergeMethod: MergeMethodSquash, 140 MinEntriesToMerge: 1, 141 MinEntriesToMergeWaitMinutes: 15, 142 }, 143 RequiredDeployments: &RequiredDeploymentsRuleParameters{ 144 RequiredDeploymentEnvironments: []string{"test1", "test2"}, 145 }, 146 RequiredSignatures: &EmptyRuleParameters{}, 147 PullRequest: &PullRequestRuleParameters{ 148 AllowedMergeMethods: []MergeMethod{ 149 MergeMethodSquash, 150 MergeMethodRebase, 151 }, 152 DismissStaleReviewsOnPush: true, 153 RequireCodeOwnerReview: true, 154 RequireLastPushApproval: true, 155 RequiredApprovingReviewCount: 2, 156 RequiredReviewThreadResolution: true, 157 }, 158 RequiredStatusChecks: &RequiredStatusChecksRuleParameters{ 159 DoNotEnforceOnCreate: Ptr(true), 160 RequiredStatusChecks: []*RuleStatusCheck{ 161 {Context: "test1", IntegrationID: Ptr(int64(1))}, 162 {Context: "test2", IntegrationID: Ptr(int64(2))}, 163 }, 164 StrictRequiredStatusChecksPolicy: true, 165 }, 166 NonFastForward: &EmptyRuleParameters{}, 167 CommitMessagePattern: &PatternRuleParameters{ 168 Name: Ptr("cmp"), 169 Negate: Ptr(false), 170 Operator: PatternRuleOperatorStartsWith, 171 Pattern: "test", 172 }, 173 CommitAuthorEmailPattern: &PatternRuleParameters{ 174 Name: Ptr("caep"), 175 Negate: Ptr(false), 176 Operator: PatternRuleOperatorStartsWith, 177 Pattern: "test", 178 }, 179 CommitterEmailPattern: &PatternRuleParameters{ 180 Name: Ptr("cep"), 181 Negate: Ptr(false), 182 Operator: PatternRuleOperatorStartsWith, 183 Pattern: "test", 184 }, 185 BranchNamePattern: &PatternRuleParameters{ 186 Name: Ptr("bp"), 187 Negate: Ptr(false), 188 Operator: PatternRuleOperatorStartsWith, 189 Pattern: "test", 190 }, 191 TagNamePattern: &PatternRuleParameters{ 192 Name: Ptr("tp"), 193 Negate: Ptr(false), 194 Operator: PatternRuleOperatorStartsWith, 195 Pattern: "test", 196 }, 197 FilePathRestriction: &FilePathRestrictionRuleParameters{ 198 RestrictedFilePaths: []string{"test1", "test2"}, 199 }, 200 MaxFilePathLength: &MaxFilePathLengthRuleParameters{MaxFilePathLength: 512}, 201 FileExtensionRestriction: &FileExtensionRestrictionRuleParameters{ 202 RestrictedFileExtensions: []string{".exe", ".pkg"}, 203 }, 204 MaxFileSize: &MaxFileSizeRuleParameters{MaxFileSize: 1024}, 205 Workflows: &WorkflowsRuleParameters{ 206 DoNotEnforceOnCreate: Ptr(true), 207 Workflows: []*RuleWorkflow{ 208 { 209 Path: ".github/workflows/test1.yaml", 210 Ref: Ptr("main"), 211 RepositoryID: Ptr(int64(1)), 212 SHA: Ptr("aaaa"), 213 }, 214 { 215 Path: ".github/workflows/test2.yaml", 216 Ref: Ptr("main"), 217 RepositoryID: Ptr(int64(2)), 218 SHA: Ptr("bbbb"), 219 }, 220 }, 221 }, 222 CodeScanning: &CodeScanningRuleParameters{ 223 CodeScanningTools: []*RuleCodeScanningTool{ 224 { 225 AlertsThreshold: CodeScanningAlertsThresholdAll, 226 SecurityAlertsThreshold: CodeScanningSecurityAlertsThresholdAll, 227 Tool: "test", 228 }, 229 { 230 AlertsThreshold: CodeScanningAlertsThresholdNone, 231 SecurityAlertsThreshold: CodeScanningSecurityAlertsThresholdNone, 232 Tool: "test", 233 }, 234 }, 235 }, 236 }, 237 `[{"type":"creation"},{"type":"update","parameters":{"update_allows_fetch_and_merge":true}},{"type":"deletion"},{"type":"required_linear_history"},{"type":"merge_queue","parameters":{"check_response_timeout_minutes":5,"grouping_strategy":"ALLGREEN","max_entries_to_build":10,"max_entries_to_merge":20,"merge_method":"squash","min_entries_to_merge":1,"min_entries_to_merge_wait_minutes":15}},{"type":"required_deployments","parameters":{"required_deployment_environments":["test1","test2"]}},{"type":"required_signatures"},{"type":"pull_request","parameters":{"allowed_merge_methods":["squash","rebase"],"dismiss_stale_reviews_on_push":true,"require_code_owner_review":true,"require_last_push_approval":true,"required_approving_review_count":2,"required_review_thread_resolution":true}},{"type":"required_status_checks","parameters":{"do_not_enforce_on_create":true,"required_status_checks":[{"context":"test1","integration_id":1},{"context":"test2","integration_id":2}],"strict_required_status_checks_policy":true}},{"type":"non_fast_forward"},{"type":"commit_message_pattern","parameters":{"name":"cmp","negate":false,"operator":"starts_with","pattern":"test"}},{"type":"commit_author_email_pattern","parameters":{"name":"caep","negate":false,"operator":"starts_with","pattern":"test"}},{"type":"committer_email_pattern","parameters":{"name":"cep","negate":false,"operator":"starts_with","pattern":"test"}},{"type":"branch_name_pattern","parameters":{"name":"bp","negate":false,"operator":"starts_with","pattern":"test"}},{"type":"tag_name_pattern","parameters":{"name":"tp","negate":false,"operator":"starts_with","pattern":"test"}},{"type":"file_path_restriction","parameters":{"restricted_file_paths":["test1","test2"]}},{"type":"max_file_path_length","parameters":{"max_file_path_length":512}},{"type":"file_extension_restriction","parameters":{"restricted_file_extensions":[".exe",".pkg"]}},{"type":"max_file_size","parameters":{"max_file_size":1024}},{"type":"workflows","parameters":{"do_not_enforce_on_create":true,"workflows":[{"path":".github/workflows/test1.yaml","ref":"main","repository_id":1,"sha":"aaaa"},{"path":".github/workflows/test2.yaml","ref":"main","repository_id":2,"sha":"bbbb"}]}},{"type":"code_scanning","parameters":{"code_scanning_tools":[{"alerts_threshold":"all","security_alerts_threshold":"all","tool":"test"},{"alerts_threshold":"none","security_alerts_threshold":"none","tool":"test"}]}}]`, 238 }, 239 } 240 241 t.Run("MarshalJSON", func(t *testing.T) { 242 t.Parallel() 243 244 for _, test := range tests { 245 t.Run(test.name, func(t *testing.T) { 246 t.Parallel() 247 248 got, err := json.Marshal(test.rules) 249 if err != nil { 250 t.Errorf("Unable to marshal JSON for %#v", test.rules) 251 } 252 253 if diff := cmp.Diff(test.json, string(got)); diff != "" { 254 t.Errorf( 255 "json.Marshal returned:\n%s\nwant:\n%s\ndiff:\n%v", 256 got, 257 test.json, 258 diff, 259 ) 260 } 261 }) 262 } 263 }) 264 265 t.Run("UnmarshalJSON", func(t *testing.T) { 266 t.Parallel() 267 268 for _, test := range tests { 269 t.Run(test.name, func(t *testing.T) { 270 t.Parallel() 271 272 got := &RepositoryRulesetRules{} 273 err := json.Unmarshal([]byte(test.json), got) 274 if err != nil { 275 t.Errorf("Unable to unmarshal JSON %v: %v", test.json, err) 276 } 277 278 if diff := cmp.Diff(test.rules, got); diff != "" { 279 t.Errorf( 280 "json.Unmarshal returned:\n%#v\nwant:\n%#v\ndiff:\n%v", 281 got, 282 test.rules, 283 diff, 284 ) 285 } 286 }) 287 } 288 }) 289 } 290 291 func TestBranchRules(t *testing.T) { 292 t.Parallel() 293 tests := []struct { 294 name string 295 rules *BranchRules 296 json string 297 }{ 298 {"empty", &BranchRules{}, `[]`}, 299 { 300 "single_rule_type_single_rule_empty_params", 301 &BranchRules{ 302 Creation: []*BranchRuleMetadata{ 303 { 304 RulesetSourceType: RulesetSourceTypeRepository, 305 RulesetSource: "test/test", 306 RulesetID: 1, 307 }, 308 }, 309 }, 310 `[{"type":"creation","ruleset_source_type":"Repository","ruleset_source":"test/test","ruleset_id":1}]`, 311 }, 312 { 313 "single_rule_type_single_rule_with_params", 314 &BranchRules{ 315 Update: []*UpdateBranchRule{ 316 { 317 BranchRuleMetadata: BranchRuleMetadata{ 318 RulesetSourceType: RulesetSourceTypeRepository, 319 RulesetSource: "test/test", 320 RulesetID: 1, 321 }, 322 Parameters: UpdateRuleParameters{UpdateAllowsFetchAndMerge: true}, 323 }, 324 }, 325 }, 326 `[{"type":"update","ruleset_source_type":"Repository","ruleset_source":"test/test","ruleset_id":1,"parameters":{"update_allows_fetch_and_merge":true}}]`, 327 }, 328 { 329 "all_rule_types_with_all_parameters", 330 &BranchRules{ 331 Creation: []*BranchRuleMetadata{ 332 { 333 RulesetSourceType: RulesetSourceTypeRepository, 334 RulesetSource: "test/test", 335 RulesetID: 1, 336 }, 337 }, 338 Update: []*UpdateBranchRule{ 339 { 340 BranchRuleMetadata: BranchRuleMetadata{ 341 RulesetSourceType: RulesetSourceTypeRepository, 342 RulesetSource: "test/test", 343 RulesetID: 1, 344 }, 345 Parameters: UpdateRuleParameters{UpdateAllowsFetchAndMerge: true}, 346 }, 347 }, 348 Deletion: []*BranchRuleMetadata{ 349 { 350 RulesetSourceType: RulesetSourceTypeRepository, 351 RulesetSource: "test/test", 352 RulesetID: 1, 353 }, 354 }, 355 RequiredLinearHistory: []*BranchRuleMetadata{ 356 { 357 RulesetSourceType: RulesetSourceTypeRepository, 358 RulesetSource: "test/test", 359 RulesetID: 1, 360 }, 361 }, 362 MergeQueue: []*MergeQueueBranchRule{ 363 { 364 BranchRuleMetadata: BranchRuleMetadata{ 365 RulesetSourceType: RulesetSourceTypeRepository, 366 RulesetSource: "test/test", 367 RulesetID: 1, 368 }, 369 Parameters: MergeQueueRuleParameters{ 370 CheckResponseTimeoutMinutes: 5, 371 GroupingStrategy: MergeGroupingStrategyAllGreen, 372 MaxEntriesToBuild: 10, 373 MaxEntriesToMerge: 20, 374 MergeMethod: MergeMethodSquash, 375 MinEntriesToMerge: 1, 376 MinEntriesToMergeWaitMinutes: 15, 377 }, 378 }, 379 }, 380 RequiredDeployments: []*RequiredDeploymentsBranchRule{ 381 { 382 BranchRuleMetadata: BranchRuleMetadata{ 383 RulesetSourceType: RulesetSourceTypeRepository, 384 RulesetSource: "test/test", 385 RulesetID: 1, 386 }, 387 Parameters: RequiredDeploymentsRuleParameters{ 388 RequiredDeploymentEnvironments: []string{"test1", "test2"}, 389 }, 390 }, 391 }, 392 RequiredSignatures: []*BranchRuleMetadata{ 393 { 394 RulesetSourceType: RulesetSourceTypeRepository, 395 RulesetSource: "test/test", 396 RulesetID: 1, 397 }, 398 }, 399 PullRequest: []*PullRequestBranchRule{ 400 { 401 BranchRuleMetadata: BranchRuleMetadata{ 402 RulesetSourceType: RulesetSourceTypeRepository, 403 RulesetSource: "test/test", 404 RulesetID: 1, 405 }, 406 Parameters: PullRequestRuleParameters{ 407 AllowedMergeMethods: []MergeMethod{ 408 MergeMethodSquash, 409 MergeMethodRebase, 410 }, 411 DismissStaleReviewsOnPush: true, 412 RequireCodeOwnerReview: true, 413 RequireLastPushApproval: true, 414 RequiredApprovingReviewCount: 2, 415 RequiredReviewThreadResolution: true, 416 }, 417 }, 418 }, 419 RequiredStatusChecks: []*RequiredStatusChecksBranchRule{ 420 { 421 BranchRuleMetadata: BranchRuleMetadata{ 422 RulesetSourceType: RulesetSourceTypeRepository, 423 RulesetSource: "test/test", 424 RulesetID: 1, 425 }, 426 Parameters: RequiredStatusChecksRuleParameters{ 427 DoNotEnforceOnCreate: Ptr(true), 428 RequiredStatusChecks: []*RuleStatusCheck{ 429 {Context: "test1", IntegrationID: Ptr(int64(1))}, 430 {Context: "test2", IntegrationID: Ptr(int64(2))}, 431 }, 432 StrictRequiredStatusChecksPolicy: true, 433 }, 434 }, 435 }, 436 NonFastForward: []*BranchRuleMetadata{ 437 { 438 RulesetSourceType: RulesetSourceTypeRepository, 439 RulesetSource: "test/test", 440 RulesetID: 1, 441 }, 442 }, 443 CommitMessagePattern: []*PatternBranchRule{ 444 { 445 BranchRuleMetadata: BranchRuleMetadata{ 446 RulesetSourceType: RulesetSourceTypeRepository, 447 RulesetSource: "test/test", 448 RulesetID: 1, 449 }, 450 Parameters: PatternRuleParameters{ 451 Name: Ptr("cmp"), 452 Negate: Ptr(false), 453 Operator: PatternRuleOperatorStartsWith, 454 Pattern: "test", 455 }, 456 }, 457 }, 458 CommitAuthorEmailPattern: []*PatternBranchRule{ 459 { 460 BranchRuleMetadata: BranchRuleMetadata{ 461 RulesetSourceType: RulesetSourceTypeRepository, 462 RulesetSource: "test/test", 463 RulesetID: 1, 464 }, 465 Parameters: PatternRuleParameters{ 466 Name: Ptr("caep"), 467 Negate: Ptr(false), 468 Operator: PatternRuleOperatorStartsWith, 469 Pattern: "test", 470 }, 471 }, 472 }, 473 CommitterEmailPattern: []*PatternBranchRule{ 474 { 475 BranchRuleMetadata: BranchRuleMetadata{ 476 RulesetSourceType: RulesetSourceTypeRepository, 477 RulesetSource: "test/test", 478 RulesetID: 1, 479 }, 480 Parameters: PatternRuleParameters{ 481 Name: Ptr("cep"), 482 Negate: Ptr(false), 483 Operator: PatternRuleOperatorStartsWith, 484 Pattern: "test", 485 }, 486 }, 487 }, 488 BranchNamePattern: []*PatternBranchRule{ 489 { 490 BranchRuleMetadata: BranchRuleMetadata{ 491 RulesetSourceType: RulesetSourceTypeRepository, 492 RulesetSource: "test/test", 493 RulesetID: 1, 494 }, 495 Parameters: PatternRuleParameters{ 496 Name: Ptr("bp"), 497 Negate: Ptr(false), 498 Operator: PatternRuleOperatorStartsWith, 499 Pattern: "test", 500 }, 501 }, 502 }, 503 TagNamePattern: []*PatternBranchRule{ 504 { 505 BranchRuleMetadata: BranchRuleMetadata{ 506 RulesetSourceType: RulesetSourceTypeRepository, 507 RulesetSource: "test/test", 508 RulesetID: 1, 509 }, 510 Parameters: PatternRuleParameters{ 511 Name: Ptr("tp"), 512 Negate: Ptr(false), 513 Operator: PatternRuleOperatorStartsWith, 514 Pattern: "test", 515 }, 516 }, 517 }, 518 FilePathRestriction: []*FilePathRestrictionBranchRule{ 519 { 520 BranchRuleMetadata: BranchRuleMetadata{ 521 RulesetSourceType: RulesetSourceTypeRepository, 522 RulesetSource: "test/test", 523 RulesetID: 1, 524 }, 525 Parameters: FilePathRestrictionRuleParameters{ 526 RestrictedFilePaths: []string{"test1", "test2"}, 527 }, 528 }, 529 }, 530 MaxFilePathLength: []*MaxFilePathLengthBranchRule{ 531 { 532 BranchRuleMetadata: BranchRuleMetadata{ 533 RulesetSourceType: RulesetSourceTypeRepository, 534 RulesetSource: "test/test", 535 RulesetID: 1, 536 }, 537 Parameters: MaxFilePathLengthRuleParameters{MaxFilePathLength: 512}, 538 }, 539 }, 540 FileExtensionRestriction: []*FileExtensionRestrictionBranchRule{ 541 { 542 BranchRuleMetadata: BranchRuleMetadata{ 543 RulesetSourceType: RulesetSourceTypeRepository, 544 RulesetSource: "test/test", 545 RulesetID: 1, 546 }, 547 Parameters: FileExtensionRestrictionRuleParameters{ 548 RestrictedFileExtensions: []string{".exe", ".pkg"}, 549 }, 550 }, 551 }, 552 MaxFileSize: []*MaxFileSizeBranchRule{ 553 { 554 BranchRuleMetadata: BranchRuleMetadata{ 555 RulesetSourceType: RulesetSourceTypeRepository, 556 RulesetSource: "test/test", 557 RulesetID: 1, 558 }, 559 Parameters: MaxFileSizeRuleParameters{MaxFileSize: 1024}, 560 }, 561 }, 562 Workflows: []*WorkflowsBranchRule{ 563 { 564 BranchRuleMetadata: BranchRuleMetadata{ 565 RulesetSourceType: RulesetSourceTypeRepository, 566 RulesetSource: "test/test", 567 RulesetID: 1, 568 }, 569 Parameters: WorkflowsRuleParameters{ 570 DoNotEnforceOnCreate: Ptr(true), 571 Workflows: []*RuleWorkflow{ 572 { 573 Path: ".github/workflows/test1.yaml", 574 Ref: Ptr("main"), 575 RepositoryID: Ptr(int64(1)), 576 SHA: Ptr("aaaa"), 577 }, 578 { 579 Path: ".github/workflows/test2.yaml", 580 Ref: Ptr("main"), 581 RepositoryID: Ptr(int64(2)), 582 SHA: Ptr("bbbb"), 583 }, 584 }, 585 }, 586 }, 587 }, 588 CodeScanning: []*CodeScanningBranchRule{ 589 { 590 BranchRuleMetadata: BranchRuleMetadata{ 591 RulesetSourceType: RulesetSourceTypeRepository, 592 RulesetSource: "test/test", 593 RulesetID: 1, 594 }, 595 Parameters: CodeScanningRuleParameters{ 596 CodeScanningTools: []*RuleCodeScanningTool{ 597 { 598 AlertsThreshold: CodeScanningAlertsThresholdAll, 599 SecurityAlertsThreshold: CodeScanningSecurityAlertsThresholdAll, 600 Tool: "test", 601 }, 602 { 603 AlertsThreshold: CodeScanningAlertsThresholdNone, 604 SecurityAlertsThreshold: CodeScanningSecurityAlertsThresholdNone, 605 Tool: "test", 606 }, 607 }, 608 }, 609 }, 610 }, 611 }, 612 `[{"type":"creation","ruleset_source_type":"Repository","ruleset_source":"test/test","ruleset_id":1},{"type":"update","ruleset_source_type":"Repository","ruleset_source":"test/test","ruleset_id":1,"parameters":{"update_allows_fetch_and_merge":true}},{"type":"deletion","ruleset_source_type":"Repository","ruleset_source":"test/test","ruleset_id":1},{"type":"required_linear_history","ruleset_source_type":"Repository","ruleset_source":"test/test","ruleset_id":1},{"type":"merge_queue","ruleset_source_type":"Repository","ruleset_source":"test/test","ruleset_id":1,"parameters":{"check_response_timeout_minutes":5,"grouping_strategy":"ALLGREEN","max_entries_to_build":10,"max_entries_to_merge":20,"merge_method":"squash","min_entries_to_merge":1,"min_entries_to_merge_wait_minutes":15}},{"type":"required_deployments","ruleset_source_type":"Repository","ruleset_source":"test/test","ruleset_id":1,"parameters":{"required_deployment_environments":["test1","test2"]}},{"type":"required_signatures","ruleset_source_type":"Repository","ruleset_source":"test/test","ruleset_id":1},{"type":"pull_request","ruleset_source_type":"Repository","ruleset_source":"test/test","ruleset_id":1,"parameters":{"allowed_merge_methods":["squash","rebase"],"dismiss_stale_reviews_on_push":true,"require_code_owner_review":true,"require_last_push_approval":true,"required_approving_review_count":2,"required_review_thread_resolution":true}},{"type":"required_status_checks","ruleset_source_type":"Repository","ruleset_source":"test/test","ruleset_id":1,"parameters":{"do_not_enforce_on_create":true,"required_status_checks":[{"context":"test1","integration_id":1},{"context":"test2","integration_id":2}],"strict_required_status_checks_policy":true}},{"type":"non_fast_forward","ruleset_source_type":"Repository","ruleset_source":"test/test","ruleset_id":1},{"type":"commit_message_pattern","ruleset_source_type":"Repository","ruleset_source":"test/test","ruleset_id":1,"parameters":{"name":"cmp","negate":false,"operator":"starts_with","pattern":"test"}},{"type":"commit_author_email_pattern","ruleset_source_type":"Repository","ruleset_source":"test/test","ruleset_id":1,"parameters":{"name":"caep","negate":false,"operator":"starts_with","pattern":"test"}},{"type":"committer_email_pattern","ruleset_source_type":"Repository","ruleset_source":"test/test","ruleset_id":1,"parameters":{"name":"cep","negate":false,"operator":"starts_with","pattern":"test"}},{"type":"branch_name_pattern","ruleset_source_type":"Repository","ruleset_source":"test/test","ruleset_id":1,"parameters":{"name":"bp","negate":false,"operator":"starts_with","pattern":"test"}},{"type":"tag_name_pattern","ruleset_source_type":"Repository","ruleset_source":"test/test","ruleset_id":1,"parameters":{"name":"tp","negate":false,"operator":"starts_with","pattern":"test"}},{"type":"file_path_restriction","ruleset_source_type":"Repository","ruleset_source":"test/test","ruleset_id":1,"parameters":{"restricted_file_paths":["test1","test2"]}},{"type":"max_file_path_length","ruleset_source_type":"Repository","ruleset_source":"test/test","ruleset_id":1,"parameters":{"max_file_path_length":512}},{"type":"file_extension_restriction","ruleset_source_type":"Repository","ruleset_source":"test/test","ruleset_id":1,"parameters":{"restricted_file_extensions":[".exe",".pkg"]}},{"type":"max_file_size","ruleset_source_type":"Repository","ruleset_source":"test/test","ruleset_id":1,"parameters":{"max_file_size":1024}},{"type":"workflows","ruleset_source_type":"Repository","ruleset_source":"test/test","ruleset_id":1,"parameters":{"do_not_enforce_on_create":true,"workflows":[{"path":".github/workflows/test1.yaml","ref":"main","repository_id":1,"sha":"aaaa"},{"path":".github/workflows/test2.yaml","ref":"main","repository_id":2,"sha":"bbbb"}]}},{"type":"code_scanning","ruleset_source_type":"Repository","ruleset_source":"test/test","ruleset_id":1,"parameters":{"code_scanning_tools":[{"alerts_threshold":"all","security_alerts_threshold":"all","tool":"test"},{"alerts_threshold":"none","security_alerts_threshold":"none","tool":"test"}]}}]`, 613 }, 614 } 615 616 t.Run("UnmarshalJSON", func(t *testing.T) { 617 t.Parallel() 618 619 for _, test := range tests { 620 t.Run(test.name, func(t *testing.T) { 621 t.Parallel() 622 623 got := &BranchRules{} 624 err := json.Unmarshal([]byte(test.json), got) 625 if err != nil { 626 t.Errorf("Unable to unmarshal JSON %v: %v", test.json, err) 627 } 628 629 if diff := cmp.Diff(test.rules, got); diff != "" { 630 t.Errorf( 631 "json.Unmarshal returned:\n%#v\nwant:\n%#v\ndiff:\n%v", 632 got, 633 test.rules, 634 diff, 635 ) 636 } 637 }) 638 } 639 }) 640 } 641 642 func TestRepositoryRule(t *testing.T) { 643 t.Parallel() 644 tests := []struct { 645 name string 646 rule *RepositoryRule 647 json string 648 }{ 649 { 650 "empty", 651 &RepositoryRule{}, 652 `{}`, 653 }, 654 { 655 "creation", 656 &RepositoryRule{Type: RulesetRuleTypeCreation, Parameters: nil}, 657 `{"type":"creation"}`, 658 }, 659 { 660 "update", 661 &RepositoryRule{Type: RulesetRuleTypeUpdate, Parameters: &UpdateRuleParameters{}}, 662 `{"type":"update"}`, 663 }, 664 { 665 "update_params_empty", 666 &RepositoryRule{Type: RulesetRuleTypeUpdate, Parameters: &UpdateRuleParameters{}}, 667 `{"type":"update","parameters":{}}`, 668 }, 669 { 670 "update_params_set", 671 &RepositoryRule{ 672 Type: RulesetRuleTypeUpdate, 673 Parameters: &UpdateRuleParameters{UpdateAllowsFetchAndMerge: true}, 674 }, 675 `{"type":"update","parameters":{"update_allows_fetch_and_merge":true}}`, 676 }, 677 { 678 "deletion", 679 &RepositoryRule{Type: RulesetRuleTypeDeletion, Parameters: nil}, 680 `{"type":"deletion"}`, 681 }, 682 { 683 "required_linear_history", 684 &RepositoryRule{Type: RulesetRuleTypeRequiredLinearHistory, Parameters: nil}, 685 `{"type":"required_linear_history"}`, 686 }, 687 { 688 "merge_queue", 689 &RepositoryRule{ 690 Type: RulesetRuleTypeMergeQueue, 691 Parameters: &MergeQueueRuleParameters{ 692 CheckResponseTimeoutMinutes: 5, 693 GroupingStrategy: MergeGroupingStrategyAllGreen, 694 MaxEntriesToBuild: 10, 695 MaxEntriesToMerge: 20, 696 MergeMethod: MergeMethodSquash, 697 MinEntriesToMerge: 1, 698 MinEntriesToMergeWaitMinutes: 15, 699 }, 700 }, 701 `{"type":"merge_queue","parameters":{"check_response_timeout_minutes":5,"grouping_strategy":"ALLGREEN","max_entries_to_build":10,"max_entries_to_merge":20,"merge_method":"squash","min_entries_to_merge":1,"min_entries_to_merge_wait_minutes":15}}`, 702 }, 703 { 704 "required_deployments", 705 &RepositoryRule{ 706 Type: RulesetRuleTypeRequiredDeployments, 707 Parameters: &RequiredDeploymentsRuleParameters{ 708 RequiredDeploymentEnvironments: []string{"test1", "test2"}, 709 }, 710 }, 711 `{"type":"required_deployments","parameters":{"required_deployment_environments":["test1","test2"]}}`, 712 }, 713 { 714 "required_signatures", 715 &RepositoryRule{Type: RulesetRuleTypeRequiredSignatures, Parameters: nil}, 716 `{"type":"required_signatures"}`, 717 }, 718 { 719 "pull_request", 720 &RepositoryRule{ 721 Type: RulesetRuleTypePullRequest, 722 Parameters: &PullRequestRuleParameters{ 723 AllowedMergeMethods: []MergeMethod{ 724 MergeMethodSquash, 725 MergeMethodRebase, 726 }, 727 DismissStaleReviewsOnPush: true, 728 RequireCodeOwnerReview: true, 729 RequireLastPushApproval: true, 730 RequiredApprovingReviewCount: 2, 731 RequiredReviewThreadResolution: true, 732 }, 733 }, 734 `{"type":"pull_request","parameters":{"allowed_merge_methods":["squash","rebase"],"dismiss_stale_reviews_on_push":true,"require_code_owner_review":true,"require_last_push_approval":true,"required_approving_review_count":2,"required_review_thread_resolution":true}}`, 735 }, 736 { 737 "required_status_checks", 738 &RepositoryRule{ 739 Type: RulesetRuleTypeRequiredStatusChecks, 740 Parameters: &RequiredStatusChecksRuleParameters{ 741 RequiredStatusChecks: []*RuleStatusCheck{ 742 {Context: "test1"}, 743 {Context: "test2"}, 744 }, 745 StrictRequiredStatusChecksPolicy: true, 746 }, 747 }, 748 `{"type":"required_status_checks","parameters":{"required_status_checks":[{"context":"test1"},{"context":"test2"}],"strict_required_status_checks_policy":true}}`, 749 }, 750 { 751 "non_fast_forward", 752 &RepositoryRule{Type: RulesetRuleTypeNonFastForward, Parameters: nil}, 753 `{"type":"non_fast_forward"}`, 754 }, 755 { 756 "commit_message_pattern", 757 &RepositoryRule{ 758 Type: RulesetRuleTypeCommitMessagePattern, 759 Parameters: &PatternRuleParameters{ 760 Name: Ptr("test"), 761 Negate: Ptr(false), 762 Operator: PatternRuleOperatorStartsWith, 763 Pattern: "test", 764 }, 765 }, 766 `{"type":"commit_message_pattern","parameters":{"name":"test","negate":false,"operator":"starts_with","pattern":"test"}}`, 767 }, 768 { 769 "commit_author_email_pattern", 770 &RepositoryRule{ 771 Type: RulesetRuleTypeCommitAuthorEmailPattern, 772 Parameters: &PatternRuleParameters{ 773 Name: Ptr("test"), 774 Negate: Ptr(false), 775 Operator: PatternRuleOperatorStartsWith, 776 Pattern: "test", 777 }, 778 }, 779 `{"type":"commit_author_email_pattern","parameters":{"name":"test","negate":false,"operator":"starts_with","pattern":"test"}}`, 780 }, 781 { 782 "committer_email_pattern", 783 &RepositoryRule{ 784 Type: RulesetRuleTypeCommitterEmailPattern, 785 Parameters: &PatternRuleParameters{ 786 Name: Ptr("test"), 787 Negate: Ptr(false), 788 Operator: PatternRuleOperatorStartsWith, 789 Pattern: "test", 790 }, 791 }, 792 `{"type":"committer_email_pattern","parameters":{"name":"test","negate":false,"operator":"starts_with","pattern":"test"}}`, 793 }, 794 { 795 "branch_name_pattern", 796 &RepositoryRule{ 797 Type: RulesetRuleTypeBranchNamePattern, 798 Parameters: &PatternRuleParameters{ 799 Name: Ptr("test"), 800 Negate: Ptr(false), 801 Operator: PatternRuleOperatorStartsWith, 802 Pattern: "test", 803 }, 804 }, 805 `{"type":"branch_name_pattern","parameters":{"name":"test","negate":false,"operator":"starts_with","pattern":"test"}}`, 806 }, 807 { 808 "tag_name_pattern", 809 &RepositoryRule{ 810 Type: RulesetRuleTypeTagNamePattern, 811 Parameters: &PatternRuleParameters{ 812 Name: Ptr("test"), 813 Negate: Ptr(false), 814 Operator: PatternRuleOperatorStartsWith, 815 Pattern: "test", 816 }, 817 }, 818 `{"type":"tag_name_pattern","parameters":{"name":"test","negate":false,"operator":"starts_with","pattern":"test"}}`, 819 }, 820 { 821 "file_path_restriction", 822 &RepositoryRule{ 823 Type: RulesetRuleTypeFilePathRestriction, 824 Parameters: &FilePathRestrictionRuleParameters{ 825 RestrictedFilePaths: []string{"test1", "test2"}, 826 }, 827 }, 828 `{"type":"file_path_restriction","parameters":{"restricted_file_paths":["test1","test2"]}}`, 829 }, 830 { 831 "max_file_path_length", 832 &RepositoryRule{ 833 Type: RulesetRuleTypeMaxFilePathLength, 834 Parameters: &MaxFilePathLengthRuleParameters{MaxFilePathLength: 512}, 835 }, 836 `{"type":"max_file_path_length","parameters":{"max_file_path_length":512}}`, 837 }, 838 { 839 "file_extension_restriction", 840 &RepositoryRule{ 841 Type: RulesetRuleTypeFileExtensionRestriction, 842 Parameters: &FileExtensionRestrictionRuleParameters{ 843 RestrictedFileExtensions: []string{".exe", ".pkg"}, 844 }, 845 }, 846 `{"type":"file_extension_restriction","parameters":{"restricted_file_extensions":[".exe",".pkg"]}}`, 847 }, 848 { 849 "max_file_size", 850 &RepositoryRule{ 851 Type: RulesetRuleTypeMaxFileSize, 852 Parameters: &MaxFileSizeRuleParameters{MaxFileSize: 1024}, 853 }, 854 `{"type":"max_file_size","parameters":{"max_file_size":1024}}`, 855 }, 856 { 857 "workflows", 858 &RepositoryRule{ 859 Type: RulesetRuleTypeWorkflows, 860 Parameters: &WorkflowsRuleParameters{ 861 Workflows: []*RuleWorkflow{ 862 {Path: ".github/workflows/test1.yaml"}, 863 {Path: ".github/workflows/test2.yaml"}, 864 }, 865 }, 866 }, 867 `{"type":"workflows","parameters":{"workflows":[{"path":".github/workflows/test1.yaml"},{"path":".github/workflows/test2.yaml"}]}}`, 868 }, 869 { 870 "code_scanning", 871 &RepositoryRule{ 872 Type: RulesetRuleTypeCodeScanning, 873 Parameters: &CodeScanningRuleParameters{ 874 CodeScanningTools: []*RuleCodeScanningTool{ 875 { 876 AlertsThreshold: CodeScanningAlertsThresholdAll, 877 SecurityAlertsThreshold: CodeScanningSecurityAlertsThresholdAll, 878 Tool: "test", 879 }, 880 { 881 AlertsThreshold: CodeScanningAlertsThresholdNone, 882 SecurityAlertsThreshold: CodeScanningSecurityAlertsThresholdNone, 883 Tool: "test", 884 }, 885 }, 886 }, 887 }, 888 `{"type":"code_scanning","parameters":{"code_scanning_tools":[{"alerts_threshold":"all","security_alerts_threshold":"all","tool":"test"},{"alerts_threshold":"none","security_alerts_threshold":"none","tool":"test"}]}}`, 889 }, 890 } 891 892 t.Run("UnmarshalJSON", func(t *testing.T) { 893 t.Parallel() 894 895 for _, test := range tests { 896 t.Run(test.name, func(t *testing.T) { 897 t.Parallel() 898 899 got := &RepositoryRule{} 900 err := json.Unmarshal([]byte(test.json), got) 901 if err != nil { 902 t.Errorf("Unable to unmarshal JSON %v: %v", test.json, err) 903 } 904 905 if diff := cmp.Diff(test.rule, got); diff != "" { 906 t.Errorf( 907 "json.Unmarshal returned:\n%#v\nwant:\n%#v\ndiff:\n%v", 908 got, 909 test.rule, 910 diff, 911 ) 912 } 913 }) 914 } 915 }) 916 }