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