github.com/google/go-github/v53@v53.2.0/github/repos_rules_test.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 "fmt" 11 "net/http" 12 "testing" 13 14 "github.com/google/go-cmp/cmp" 15 ) 16 17 func TestRepositoryRule_UnmarshalJSON(t *testing.T) { 18 tests := map[string]struct { 19 data string 20 want *RepositoryRule 21 wantErr bool 22 }{ 23 "Invalid JSON": { 24 data: `{`, 25 want: &RepositoryRule{ 26 Type: "", 27 Parameters: nil, 28 }, 29 wantErr: true, 30 }, 31 "Valid creation": { 32 data: `{"type":"creation"}`, 33 want: NewCreationRule(), 34 }, 35 "Valid deletion": { 36 data: `{"type":"deletion"}`, 37 want: &RepositoryRule{ 38 Type: "deletion", 39 Parameters: nil, 40 }, 41 }, 42 "Valid required_linear_history": { 43 data: `{"type":"required_linear_history"}`, 44 want: &RepositoryRule{ 45 Type: "required_linear_history", 46 Parameters: nil, 47 }, 48 }, 49 "Valid required_signatures": { 50 data: `{"type":"required_signatures"}`, 51 want: &RepositoryRule{ 52 Type: "required_signatures", 53 Parameters: nil, 54 }, 55 }, 56 "Valid non_fast_forward": { 57 data: `{"type":"non_fast_forward"}`, 58 want: &RepositoryRule{ 59 Type: "non_fast_forward", 60 Parameters: nil, 61 }, 62 }, 63 "Valid update params": { 64 data: `{"type":"update","parameters":{"update_allows_fetch_and_merge":true}}`, 65 want: NewUpdateRule(&UpdateAllowsFetchAndMergeRuleParameters{UpdateAllowsFetchAndMerge: true}), 66 }, 67 "Invalid update params": { 68 data: `{"type":"update","parameters":{"update_allows_fetch_and_merge":"true"}}`, 69 want: &RepositoryRule{ 70 Type: "update", 71 Parameters: nil, 72 }, 73 wantErr: true, 74 }, 75 "Valid required_deployments params": { 76 data: `{"type":"required_deployments","parameters":{"required_deployment_environments":["test"]}}`, 77 want: NewRequiredDeploymentsRule(&RequiredDeploymentEnvironmentsRuleParameters{ 78 RequiredDeploymentEnvironments: []string{"test"}, 79 }), 80 }, 81 "Invalid required_deployments params": { 82 data: `{"type":"required_deployments","parameters":{"required_deployment_environments":true}}`, 83 want: &RepositoryRule{ 84 Type: "required_deployments", 85 Parameters: nil, 86 }, 87 wantErr: true, 88 }, 89 "Valid commit_message_pattern params": { 90 data: `{"type":"commit_message_pattern","parameters":{"operator":"starts_with","pattern":"github"}}`, 91 want: NewCommitMessagePatternRule(&RulePatternParameters{ 92 Operator: "starts_with", 93 Pattern: "github", 94 }), 95 }, 96 "Invalid commit_message_pattern params": { 97 data: `{"type":"commit_message_pattern","parameters":{"operator":"starts_with","pattern":1}}`, 98 want: &RepositoryRule{ 99 Type: "commit_message_pattern", 100 Parameters: nil, 101 }, 102 wantErr: true, 103 }, 104 "Valid commit_author_email_pattern params": { 105 data: `{"type":"commit_author_email_pattern","parameters":{"operator":"starts_with","pattern":"github"}}`, 106 want: NewCommitAuthorEmailPatternRule(&RulePatternParameters{ 107 Operator: "starts_with", 108 Pattern: "github", 109 }), 110 }, 111 "Invalid commit_author_email_pattern params": { 112 data: `{"type":"commit_author_email_pattern","parameters":{"operator":"starts_with","pattern":1}}`, 113 want: &RepositoryRule{ 114 Type: "commit_author_email_pattern", 115 Parameters: nil, 116 }, 117 wantErr: true, 118 }, 119 "Valid committer_email_pattern params": { 120 data: `{"type":"committer_email_pattern","parameters":{"operator":"starts_with","pattern":"github"}}`, 121 want: NewCommitterEmailPatternRule(&RulePatternParameters{ 122 Operator: "starts_with", 123 Pattern: "github", 124 }), 125 }, 126 "Invalid committer_email_pattern params": { 127 data: `{"type":"committer_email_pattern","parameters":{"operator":"starts_with","pattern":1}}`, 128 want: &RepositoryRule{ 129 Type: "committer_email_pattern", 130 Parameters: nil, 131 }, 132 wantErr: true, 133 }, 134 "Valid branch_name_pattern params": { 135 data: `{"type":"branch_name_pattern","parameters":{"operator":"starts_with","pattern":"github"}}`, 136 want: NewBranchNamePatternRule(&RulePatternParameters{ 137 Operator: "starts_with", 138 Pattern: "github", 139 }), 140 }, 141 "Invalid branch_name_pattern params": { 142 data: `{"type":"branch_name_pattern","parameters":{"operator":"starts_with","pattern":1}}`, 143 want: &RepositoryRule{ 144 Type: "branch_name_pattern", 145 Parameters: nil, 146 }, 147 wantErr: true, 148 }, 149 "Valid tag_name_pattern params": { 150 data: `{"type":"tag_name_pattern","parameters":{"operator":"starts_with","pattern":"github"}}`, 151 want: NewTagNamePatternRule(&RulePatternParameters{ 152 Operator: "starts_with", 153 Pattern: "github", 154 }), 155 }, 156 "Invalid tag_name_pattern params": { 157 data: `{"type":"tag_name_pattern","parameters":{"operator":"starts_with","pattern":1}}`, 158 want: &RepositoryRule{ 159 Type: "tag_name_pattern", 160 Parameters: nil, 161 }, 162 wantErr: true, 163 }, 164 "Valid pull_request params": { 165 data: `{ 166 "type":"pull_request", 167 "parameters":{ 168 "dismiss_stale_reviews_on_push": true, 169 "require_code_owner_review": true, 170 "require_last_push_approval": true, 171 "required_approving_review_count": 1, 172 "required_review_thread_resolution":true 173 } 174 }`, 175 want: NewPullRequestRule(&PullRequestRuleParameters{ 176 DismissStaleReviewsOnPush: true, 177 RequireCodeOwnerReview: true, 178 RequireLastPushApproval: true, 179 RequiredApprovingReviewCount: 1, 180 RequiredReviewThreadResolution: true, 181 }), 182 }, 183 "Invalid pull_request params": { 184 data: `{"type":"pull_request","parameters": {"dismiss_stale_reviews_on_push":"true"}}`, 185 want: &RepositoryRule{ 186 Type: "pull_request", 187 Parameters: nil, 188 }, 189 wantErr: true, 190 }, 191 "Valid required_status_checks params": { 192 data: `{"type":"required_status_checks","parameters":{"required_status_checks":[{"context":"test","integration_id":1}],"strict_required_status_checks_policy":true}}`, 193 want: NewRequiredStatusChecksRule(&RequiredStatusChecksRuleParameters{ 194 RequiredStatusChecks: []RuleRequiredStatusChecks{ 195 { 196 Context: "test", 197 IntegrationID: Int64(1), 198 }, 199 }, 200 StrictRequiredStatusChecksPolicy: true, 201 }), 202 }, 203 "Invalid required_status_checks params": { 204 data: `{"type":"required_status_checks", 205 "parameters": { 206 "required_status_checks": [ 207 { 208 "context": 1 209 } 210 ] 211 }}`, 212 want: &RepositoryRule{ 213 Type: "required_status_checks", 214 Parameters: nil, 215 }, 216 wantErr: true, 217 }, 218 "Invalid type": { 219 data: `{"type":"unknown"}`, 220 want: &RepositoryRule{ 221 Type: "", 222 Parameters: nil, 223 }, 224 wantErr: true, 225 }, 226 } 227 228 for name, tc := range tests { 229 rule := &RepositoryRule{} 230 231 t.Run(name, func(t *testing.T) { 232 err := rule.UnmarshalJSON([]byte(tc.data)) 233 if err == nil && tc.wantErr { 234 t.Errorf("RepositoryRule.UnmarshalJSON returned nil instead of an error") 235 } 236 if err != nil && !tc.wantErr { 237 t.Errorf("RepositoryRule.UnmarshalJSON returned an unexpected error: %+v", err) 238 } 239 if !cmp.Equal(tc.want, rule) { 240 t.Errorf("RepositoryRule.UnmarshalJSON expected rule %+v, got %+v", tc.want, rule) 241 } 242 }) 243 } 244 } 245 246 func TestRepositoriesService_GetRulesForBranch(t *testing.T) { 247 client, mux, _, teardown := setup() 248 defer teardown() 249 250 mux.HandleFunc("/repos/o/repo/rules/branches/branch", func(w http.ResponseWriter, r *http.Request) { 251 testMethod(t, r, "GET") 252 fmt.Fprint(w, `[ 253 { 254 "type": "creation" 255 }, 256 { 257 "type": "update", 258 "parameters": { 259 "update_allows_fetch_and_merge": true 260 } 261 } 262 ]`) 263 }) 264 265 ctx := context.Background() 266 rules, _, err := client.Repositories.GetRulesForBranch(ctx, "o", "repo", "branch") 267 if err != nil { 268 t.Errorf("Repositories.GetRulesForBranch returned error: %v", err) 269 } 270 271 creationRule := NewCreationRule() 272 updateRule := NewUpdateRule(&UpdateAllowsFetchAndMergeRuleParameters{ 273 UpdateAllowsFetchAndMerge: true, 274 }) 275 276 want := []*RepositoryRule{ 277 creationRule, 278 updateRule, 279 } 280 if !cmp.Equal(rules, want) { 281 t.Errorf("Repositories.GetRulesForBranch returned %+v, want %+v", rules, want) 282 } 283 284 const methodName = "GetRulesForBranch" 285 286 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 287 got, resp, err := client.Repositories.GetRulesForBranch(ctx, "o", "repo", "branch") 288 if got != nil { 289 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 290 } 291 return resp, err 292 }) 293 } 294 295 func TestRepositoriesService_GetAllRulesets(t *testing.T) { 296 client, mux, _, teardown := setup() 297 defer teardown() 298 299 mux.HandleFunc("/repos/o/repo/rulesets", func(w http.ResponseWriter, r *http.Request) { 300 testMethod(t, r, "GET") 301 fmt.Fprint(w, `[ 302 { 303 "id": 42, 304 "name": "ruleset", 305 "source_type": "Repository", 306 "source": "o/repo", 307 "enforcement": "enabled" 308 }, 309 { 310 "id": 314, 311 "name": "Another ruleset", 312 "source_type": "Repository", 313 "source": "o/repo", 314 "enforcement": "enabled" 315 } 316 ]`) 317 }) 318 319 ctx := context.Background() 320 ruleSet, _, err := client.Repositories.GetAllRulesets(ctx, "o", "repo", false) 321 if err != nil { 322 t.Errorf("Repositories.GetAllRulesets returned error: %v", err) 323 } 324 325 want := []*Ruleset{ 326 { 327 ID: 42, 328 Name: "ruleset", 329 SourceType: String("Repository"), 330 Source: "o/repo", 331 Enforcement: "enabled", 332 }, 333 { 334 ID: 314, 335 Name: "Another ruleset", 336 SourceType: String("Repository"), 337 Source: "o/repo", 338 Enforcement: "enabled", 339 }, 340 } 341 if !cmp.Equal(ruleSet, want) { 342 t.Errorf("Repositories.GetAllRulesets returned %+v, want %+v", ruleSet, want) 343 } 344 345 const methodName = "GetAllRulesets" 346 347 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 348 got, resp, err := client.Repositories.GetAllRulesets(ctx, "o", "repo", false) 349 if got != nil { 350 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 351 } 352 return resp, err 353 }) 354 } 355 356 func TestRepositoriesService_CreateRuleset(t *testing.T) { 357 client, mux, _, teardown := setup() 358 defer teardown() 359 360 mux.HandleFunc("/repos/o/repo/rulesets", func(w http.ResponseWriter, r *http.Request) { 361 testMethod(t, r, "POST") 362 fmt.Fprint(w, `{ 363 "id": 42, 364 "name": "ruleset", 365 "source_type": "Repository", 366 "source": "o/repo", 367 "enforcement": "enabled" 368 }`) 369 }) 370 371 ctx := context.Background() 372 ruleSet, _, err := client.Repositories.CreateRuleset(ctx, "o", "repo", &Ruleset{ 373 Name: "ruleset", 374 Enforcement: "enabled", 375 }) 376 if err != nil { 377 t.Errorf("Repositories.CreateRuleset returned error: %v", err) 378 } 379 380 want := &Ruleset{ 381 ID: 42, 382 Name: "ruleset", 383 SourceType: String("Repository"), 384 Source: "o/repo", 385 Enforcement: "enabled", 386 } 387 if !cmp.Equal(ruleSet, want) { 388 t.Errorf("Repositories.CreateRuleset returned %+v, want %+v", ruleSet, want) 389 } 390 391 const methodName = "CreateRuleset" 392 393 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 394 got, resp, err := client.Repositories.CreateRuleset(ctx, "o", "repo", &Ruleset{}) 395 if got != nil { 396 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 397 } 398 return resp, err 399 }) 400 } 401 402 func TestRepositoriesService_GetRuleset(t *testing.T) { 403 client, mux, _, teardown := setup() 404 defer teardown() 405 406 mux.HandleFunc("/repos/o/repo/rulesets/42", func(w http.ResponseWriter, r *http.Request) { 407 testMethod(t, r, "GET") 408 fmt.Fprint(w, `{ 409 "id": 42, 410 "name": "ruleset", 411 "source_type": "Organization", 412 "source": "o", 413 "enforcement": "enabled" 414 }`) 415 }) 416 417 ctx := context.Background() 418 ruleSet, _, err := client.Repositories.GetRuleset(ctx, "o", "repo", 42, true) 419 if err != nil { 420 t.Errorf("Repositories.GetRuleset returned error: %v", err) 421 } 422 423 want := &Ruleset{ 424 ID: 42, 425 Name: "ruleset", 426 SourceType: String("Organization"), 427 Source: "o", 428 Enforcement: "enabled", 429 } 430 if !cmp.Equal(ruleSet, want) { 431 t.Errorf("Repositories.GetRuleset returned %+v, want %+v", ruleSet, want) 432 } 433 434 const methodName = "GetRuleset" 435 436 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 437 got, resp, err := client.Repositories.GetRuleset(ctx, "o", "repo", 42, true) 438 if got != nil { 439 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 440 } 441 return resp, err 442 }) 443 } 444 445 func TestRepositoriesService_UpdateRuleset(t *testing.T) { 446 client, mux, _, teardown := setup() 447 defer teardown() 448 449 mux.HandleFunc("/repos/o/repo/rulesets/42", func(w http.ResponseWriter, r *http.Request) { 450 testMethod(t, r, "PUT") 451 fmt.Fprint(w, `{ 452 "id": 42, 453 "name": "ruleset", 454 "source_type": "Repository", 455 "source": "o/repo", 456 "enforcement": "enabled" 457 }`) 458 }) 459 460 ctx := context.Background() 461 ruleSet, _, err := client.Repositories.UpdateRuleset(ctx, "o", "repo", 42, &Ruleset{ 462 Name: "ruleset", 463 Enforcement: "enabled", 464 }) 465 if err != nil { 466 t.Errorf("Repositories.UpdateRuleset returned error: %v", err) 467 } 468 469 want := &Ruleset{ 470 ID: 42, 471 Name: "ruleset", 472 SourceType: String("Repository"), 473 Source: "o/repo", 474 Enforcement: "enabled", 475 } 476 if !cmp.Equal(ruleSet, want) { 477 t.Errorf("Repositories.UpdateRuleset returned %+v, want %+v", ruleSet, want) 478 } 479 480 const methodName = "UpdateRuleset" 481 482 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 483 got, resp, err := client.Repositories.UpdateRuleset(ctx, "o", "repo", 42, nil) 484 if got != nil { 485 t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) 486 } 487 return resp, err 488 }) 489 } 490 491 func TestRepositoriesService_DeleteRuleset(t *testing.T) { 492 client, mux, _, teardown := setup() 493 defer teardown() 494 495 mux.HandleFunc("/repos/o/repo/rulesets/42", func(w http.ResponseWriter, r *http.Request) { 496 testMethod(t, r, "DELETE") 497 }) 498 499 ctx := context.Background() 500 _, err := client.Repositories.DeleteRuleset(ctx, "o", "repo", 42) 501 if err != nil { 502 t.Errorf("Repositories.DeleteRuleset returned error: %v", err) 503 } 504 505 const methodName = "DeleteRuleset" 506 507 testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { 508 return client.Repositories.DeleteRuleset(ctx, "o", "repo", 42) 509 }) 510 }