github.com/google/go-github/v66@v66.0.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  	t.Parallel()
    19  	tests := map[string]struct {
    20  		data    string
    21  		want    *RepositoryRule
    22  		wantErr bool
    23  	}{
    24  		"Invalid JSON": {
    25  			data: `{`,
    26  			want: &RepositoryRule{
    27  				Type:       "",
    28  				Parameters: nil,
    29  			},
    30  			wantErr: true,
    31  		},
    32  		"With Metadata": {
    33  			data: `{
    34                      "type": "creation",
    35  					"ruleset_source_type": "Repository",
    36  					"ruleset_source": "google",
    37  					"ruleset_id": 1984
    38             		   }`,
    39  			want: &RepositoryRule{
    40  				RulesetSource:     "google",
    41  				RulesetSourceType: "Repository",
    42  				RulesetID:         1984,
    43  				Type:              "creation",
    44  			},
    45  		},
    46  		"Valid creation": {
    47  			data: `{"type":"creation"}`,
    48  			want: NewCreationRule(),
    49  		},
    50  		"Valid deletion": {
    51  			data: `{"type":"deletion"}`,
    52  			want: &RepositoryRule{
    53  				Type:       "deletion",
    54  				Parameters: nil,
    55  			},
    56  		},
    57  		"Valid required_linear_history": {
    58  			data: `{"type":"required_linear_history"}`,
    59  			want: &RepositoryRule{
    60  				Type:       "required_linear_history",
    61  				Parameters: nil,
    62  			},
    63  		},
    64  		"Valid required_signatures": {
    65  			data: `{"type":"required_signatures"}`,
    66  			want: &RepositoryRule{
    67  				Type:       "required_signatures",
    68  				Parameters: nil,
    69  			},
    70  		},
    71  		"Valid merge_queue": {
    72  			data: `{"type":"merge_queue"}`,
    73  			want: &RepositoryRule{
    74  				Type:       "merge_queue",
    75  				Parameters: nil,
    76  			},
    77  		},
    78  		"Valid merge_queue with params": {
    79  			data: `{
    80  				"type":"merge_queue",
    81  				"parameters":{
    82  					"check_response_timeout_minutes": 35,
    83  					"grouping_strategy": "HEADGREEN",
    84  					"max_entries_to_build": 8,
    85  					"max_entries_to_merge": 4,
    86  					"merge_method": "SQUASH",
    87  					"min_entries_to_merge": 2,
    88  					"min_entries_to_merge_wait_minutes": 13
    89  				}
    90  			}`,
    91  			want: NewMergeQueueRule(&MergeQueueRuleParameters{
    92  				CheckResponseTimeoutMinutes:  35,
    93  				GroupingStrategy:             "HEADGREEN",
    94  				MaxEntriesToBuild:            8,
    95  				MaxEntriesToMerge:            4,
    96  				MergeMethod:                  "SQUASH",
    97  				MinEntriesToMerge:            2,
    98  				MinEntriesToMergeWaitMinutes: 13,
    99  			}),
   100  		},
   101  		"Invalid merge_queue with params": {
   102  			data: `{
   103  				"type":"merge_queue",
   104  				"parameters":{
   105  					"check_response_timeout_minutes": "35",
   106  					"grouping_strategy": "HEADGREEN",
   107  					"max_entries_to_build": "8",
   108  					"max_entries_to_merge": "4",
   109  					"merge_method": "SQUASH",
   110  					"min_entries_to_merge": "2",
   111  					"min_entries_to_merge_wait_minutes": "13"
   112  				}
   113  			}`,
   114  			want: &RepositoryRule{
   115  				Type:       "merge_queue",
   116  				Parameters: nil,
   117  			},
   118  			wantErr: true,
   119  		},
   120  		"Valid non_fast_forward": {
   121  			data: `{"type":"non_fast_forward"}`,
   122  			want: &RepositoryRule{
   123  				Type:       "non_fast_forward",
   124  				Parameters: nil,
   125  			},
   126  		},
   127  		"Valid update params": {
   128  			data: `{"type":"update","parameters":{"update_allows_fetch_and_merge":true}}`,
   129  			want: NewUpdateRule(&UpdateAllowsFetchAndMergeRuleParameters{UpdateAllowsFetchAndMerge: true}),
   130  		},
   131  		"Invalid update params": {
   132  			data: `{"type":"update","parameters":{"update_allows_fetch_and_merge":"true"}}`,
   133  			want: &RepositoryRule{
   134  				Type:       "update",
   135  				Parameters: nil,
   136  			},
   137  			wantErr: true,
   138  		},
   139  		"Valid required_deployments params": {
   140  			data: `{"type":"required_deployments","parameters":{"required_deployment_environments":["test"]}}`,
   141  			want: NewRequiredDeploymentsRule(&RequiredDeploymentEnvironmentsRuleParameters{
   142  				RequiredDeploymentEnvironments: []string{"test"},
   143  			}),
   144  		},
   145  		"Invalid required_deployments params": {
   146  			data: `{"type":"required_deployments","parameters":{"required_deployment_environments":true}}`,
   147  			want: &RepositoryRule{
   148  				Type:       "required_deployments",
   149  				Parameters: nil,
   150  			},
   151  			wantErr: true,
   152  		},
   153  		"Valid commit_message_pattern params": {
   154  			data: `{"type":"commit_message_pattern","parameters":{"operator":"starts_with","pattern":"github"}}`,
   155  			want: NewCommitMessagePatternRule(&RulePatternParameters{
   156  				Operator: "starts_with",
   157  				Pattern:  "github",
   158  			}),
   159  		},
   160  		"Invalid commit_message_pattern params": {
   161  			data: `{"type":"commit_message_pattern","parameters":{"operator":"starts_with","pattern":1}}`,
   162  			want: &RepositoryRule{
   163  				Type:       "commit_message_pattern",
   164  				Parameters: nil,
   165  			},
   166  			wantErr: true,
   167  		},
   168  		"Valid commit_author_email_pattern params": {
   169  			data: `{"type":"commit_author_email_pattern","parameters":{"operator":"starts_with","pattern":"github"}}`,
   170  			want: NewCommitAuthorEmailPatternRule(&RulePatternParameters{
   171  				Operator: "starts_with",
   172  				Pattern:  "github",
   173  			}),
   174  		},
   175  		"Invalid commit_author_email_pattern params": {
   176  			data: `{"type":"commit_author_email_pattern","parameters":{"operator":"starts_with","pattern":1}}`,
   177  			want: &RepositoryRule{
   178  				Type:       "commit_author_email_pattern",
   179  				Parameters: nil,
   180  			},
   181  			wantErr: true,
   182  		},
   183  		"Valid committer_email_pattern params": {
   184  			data: `{"type":"committer_email_pattern","parameters":{"operator":"starts_with","pattern":"github"}}`,
   185  			want: NewCommitterEmailPatternRule(&RulePatternParameters{
   186  				Operator: "starts_with",
   187  				Pattern:  "github",
   188  			}),
   189  		},
   190  		"Invalid committer_email_pattern params": {
   191  			data: `{"type":"committer_email_pattern","parameters":{"operator":"starts_with","pattern":1}}`,
   192  			want: &RepositoryRule{
   193  				Type:       "committer_email_pattern",
   194  				Parameters: nil,
   195  			},
   196  			wantErr: true,
   197  		},
   198  		"Valid branch_name_pattern params": {
   199  			data: `{"type":"branch_name_pattern","parameters":{"operator":"starts_with","pattern":"github"}}`,
   200  			want: NewBranchNamePatternRule(&RulePatternParameters{
   201  				Operator: "starts_with",
   202  				Pattern:  "github",
   203  			}),
   204  		},
   205  		"Invalid branch_name_pattern params": {
   206  			data: `{"type":"branch_name_pattern","parameters":{"operator":"starts_with","pattern":1}}`,
   207  			want: &RepositoryRule{
   208  				Type:       "branch_name_pattern",
   209  				Parameters: nil,
   210  			},
   211  			wantErr: true,
   212  		},
   213  		"Valid tag_name_pattern params": {
   214  			data: `{"type":"tag_name_pattern","parameters":{"operator":"starts_with","pattern":"github"}}`,
   215  			want: NewTagNamePatternRule(&RulePatternParameters{
   216  				Operator: "starts_with",
   217  				Pattern:  "github",
   218  			}),
   219  		},
   220  		"Invalid tag_name_pattern params": {
   221  			data: `{"type":"tag_name_pattern","parameters":{"operator":"starts_with","pattern":1}}`,
   222  			want: &RepositoryRule{
   223  				Type:       "tag_name_pattern",
   224  				Parameters: nil,
   225  			},
   226  			wantErr: true,
   227  		},
   228  		"Valid file_path_restriction params": {
   229  			data: `{"type":"file_path_restriction","parameters":{"restricted_file_paths":["/a/file"]}}`,
   230  			want: NewFilePathRestrictionRule(&RuleFileParameters{
   231  				RestrictedFilePaths: &[]string{"/a/file"},
   232  			}),
   233  		},
   234  		"Invalid file_path_restriction params": {
   235  			data: `{"type":"file_path_restriction","parameters":{"restricted_file_paths":true}}`,
   236  			want: &RepositoryRule{
   237  				Type:       "file_path_restriction",
   238  				Parameters: nil,
   239  			},
   240  			wantErr: true,
   241  		},
   242  		"Valid pull_request params": {
   243  			data: `{
   244  				"type":"pull_request",
   245  				"parameters":{
   246  					"dismiss_stale_reviews_on_push": true,
   247  					"require_code_owner_review": true,
   248  					"require_last_push_approval": true,
   249  					"required_approving_review_count": 1,
   250  					"required_review_thread_resolution":true
   251  				}
   252  			}`,
   253  			want: NewPullRequestRule(&PullRequestRuleParameters{
   254  				DismissStaleReviewsOnPush:      true,
   255  				RequireCodeOwnerReview:         true,
   256  				RequireLastPushApproval:        true,
   257  				RequiredApprovingReviewCount:   1,
   258  				RequiredReviewThreadResolution: true,
   259  			}),
   260  		},
   261  		"Invalid pull_request params": {
   262  			data: `{"type":"pull_request","parameters": {"dismiss_stale_reviews_on_push":"true"}}`,
   263  			want: &RepositoryRule{
   264  				Type:       "pull_request",
   265  				Parameters: nil,
   266  			},
   267  			wantErr: true,
   268  		},
   269  		"Valid required_status_checks params": {
   270  			data: `{"type":"required_status_checks","parameters":{"required_status_checks":[{"context":"test","integration_id":1}],"strict_required_status_checks_policy":true,"do_not_enforce_on_create":true}}`,
   271  			want: NewRequiredStatusChecksRule(&RequiredStatusChecksRuleParameters{
   272  				DoNotEnforceOnCreate: true,
   273  				RequiredStatusChecks: []RuleRequiredStatusChecks{
   274  					{
   275  						Context:       "test",
   276  						IntegrationID: Int64(1),
   277  					},
   278  				},
   279  				StrictRequiredStatusChecksPolicy: true,
   280  			}),
   281  		},
   282  		"Invalid required_status_checks params": {
   283  			data: `{"type":"required_status_checks",
   284  			"parameters": {
   285  				"required_status_checks": [
   286  				  {
   287  					"context": 1
   288  				  }
   289  				]
   290  			  }}`,
   291  			want: &RepositoryRule{
   292  				Type:       "required_status_checks",
   293  				Parameters: nil,
   294  			},
   295  			wantErr: true,
   296  		},
   297  		"Required workflows params": {
   298  			data: `{"type":"workflows","parameters":{"workflows":[{"path": ".github/workflows/test.yml", "repository_id": 1}]}}`,
   299  			want: NewRequiredWorkflowsRule(&RequiredWorkflowsRuleParameters{
   300  				RequiredWorkflows: []*RuleRequiredWorkflow{
   301  					{
   302  						Path:         ".github/workflows/test.yml",
   303  						RepositoryID: Int64(1),
   304  					},
   305  				},
   306  			}),
   307  		},
   308  		"Invalid type": {
   309  			data: `{"type":"unknown"}`,
   310  			want: &RepositoryRule{
   311  				Type:       "",
   312  				Parameters: nil,
   313  			},
   314  			wantErr: true,
   315  		},
   316  		"Valid max_file_path_length params": {
   317  			data: `{"type":"max_file_path_length","parameters":{"max_file_path_length": 255}}`,
   318  			want: NewMaxFilePathLengthRule(&RuleMaxFilePathLengthParameters{
   319  				MaxFilePathLength: 255,
   320  			}),
   321  		},
   322  		"Invalid max_file_path_length params": {
   323  			data: `{"type":"max_file_path_length","parameters":{"max_file_path_length": "255"}}`,
   324  			want: &RepositoryRule{
   325  				Type:       "max_file_path_length",
   326  				Parameters: nil,
   327  			},
   328  			wantErr: true,
   329  		},
   330  		"Valid file_extension_restriction params": {
   331  			data: `{"type":"file_extension_restriction","parameters":{"restricted_file_extensions":[".exe"]}}`,
   332  			want: NewFileExtensionRestrictionRule(&RuleFileExtensionRestrictionParameters{
   333  				RestrictedFileExtensions: []string{".exe"},
   334  			}),
   335  		},
   336  		"Invalid file_extension_restriction params": {
   337  			data: `{"type":"file_extension_restriction","parameters":{"restricted_file_extensions":true}}`,
   338  			want: &RepositoryRule{
   339  				Type:       "file_extension_restriction",
   340  				Parameters: nil,
   341  			},
   342  			wantErr: true,
   343  		},
   344  		"Valid max_file_size params": {
   345  			data: `{"type":"max_file_size","parameters":{"max_file_size": 1024}}`,
   346  			want: NewMaxFileSizeRule(&RuleMaxFileSizeParameters{
   347  				MaxFileSize: 1024,
   348  			}),
   349  		},
   350  		"Invalid max_file_size params": {
   351  			data: `{"type":"max_file_size","parameters":{"max_file_size": "1024"}}`,
   352  			want: &RepositoryRule{
   353  				Type:       "max_file_size",
   354  				Parameters: nil,
   355  			},
   356  			wantErr: true,
   357  		},
   358  	}
   359  
   360  	for name, tc := range tests {
   361  		tc := tc
   362  		rule := &RepositoryRule{}
   363  
   364  		t.Run(name, func(t *testing.T) {
   365  			t.Parallel()
   366  			err := rule.UnmarshalJSON([]byte(tc.data))
   367  			if err == nil && tc.wantErr {
   368  				t.Errorf("RepositoryRule.UnmarshalJSON returned nil instead of an error")
   369  			}
   370  			if err != nil && !tc.wantErr {
   371  				t.Errorf("RepositoryRule.UnmarshalJSON returned an unexpected error: %+v", err)
   372  			}
   373  			if !cmp.Equal(tc.want, rule) {
   374  				t.Errorf("RepositoryRule.UnmarshalJSON expected rule %+v, got %+v", tc.want, rule)
   375  			}
   376  		})
   377  	}
   378  }
   379  
   380  func TestRepositoriesService_GetRulesForBranch(t *testing.T) {
   381  	t.Parallel()
   382  	client, mux, _ := setup(t)
   383  
   384  	mux.HandleFunc("/repos/o/repo/rules/branches/branch", func(w http.ResponseWriter, r *http.Request) {
   385  		testMethod(t, r, "GET")
   386  		fmt.Fprint(w, `[
   387  			{
   388  			  "ruleset_id": 42069,
   389  			  "ruleset_source_type": "Repository",
   390  			  "ruleset_source": "google",
   391  			  "type": "creation"
   392  			},
   393  			{
   394  			  "ruleset_id": 42069,
   395  			  "ruleset_source_type": "Organization",
   396  			  "ruleset_source": "google",
   397  			  "type": "update",
   398  			  "parameters": {
   399  			    "update_allows_fetch_and_merge": true
   400  			  }
   401  			}
   402  		]`)
   403  	})
   404  
   405  	ctx := context.Background()
   406  	rules, _, err := client.Repositories.GetRulesForBranch(ctx, "o", "repo", "branch")
   407  	if err != nil {
   408  		t.Errorf("Repositories.GetRulesForBranch returned error: %v", err)
   409  	}
   410  
   411  	creationRule := NewCreationRule()
   412  	creationRule.RulesetID = 42069
   413  	creationRule.RulesetSource = "google"
   414  	creationRule.RulesetSourceType = "Repository"
   415  	updateRule := NewUpdateRule(&UpdateAllowsFetchAndMergeRuleParameters{
   416  		UpdateAllowsFetchAndMerge: true,
   417  	})
   418  	updateRule.RulesetID = 42069
   419  	updateRule.RulesetSource = "google"
   420  	updateRule.RulesetSourceType = "Organization"
   421  
   422  	want := []*RepositoryRule{
   423  		creationRule,
   424  		updateRule,
   425  	}
   426  	if !cmp.Equal(rules, want) {
   427  		t.Errorf("Repositories.GetRulesForBranch returned %+v, want %+v", rules, want)
   428  	}
   429  
   430  	const methodName = "GetRulesForBranch"
   431  
   432  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   433  		got, resp, err := client.Repositories.GetRulesForBranch(ctx, "o", "repo", "branch")
   434  		if got != nil {
   435  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   436  		}
   437  		return resp, err
   438  	})
   439  }
   440  
   441  func TestRepositoriesService_GetRulesForBranchEmptyUpdateRule(t *testing.T) {
   442  	t.Parallel()
   443  	client, mux, _ := setup(t)
   444  
   445  	mux.HandleFunc("/repos/o/repo/rules/branches/branch", func(w http.ResponseWriter, r *http.Request) {
   446  		testMethod(t, r, "GET")
   447  		fmt.Fprint(w, `[
   448  			{
   449  			  "type": "update"
   450  			}
   451  		]`)
   452  	})
   453  
   454  	ctx := context.Background()
   455  	rules, _, err := client.Repositories.GetRulesForBranch(ctx, "o", "repo", "branch")
   456  	if err != nil {
   457  		t.Errorf("Repositories.GetRulesForBranch returned error: %v", err)
   458  	}
   459  
   460  	updateRule := NewUpdateRule(nil)
   461  
   462  	want := []*RepositoryRule{
   463  		updateRule,
   464  	}
   465  	if !cmp.Equal(rules, want) {
   466  		t.Errorf("Repositories.GetRulesForBranch returned %+v, want %+v", Stringify(rules), Stringify(want))
   467  	}
   468  
   469  	const methodName = "GetRulesForBranch"
   470  
   471  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   472  		got, resp, err := client.Repositories.GetRulesForBranch(ctx, "o", "repo", "branch")
   473  		if got != nil {
   474  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   475  		}
   476  		return resp, err
   477  	})
   478  }
   479  
   480  func TestRepositoriesService_GetAllRulesets(t *testing.T) {
   481  	t.Parallel()
   482  	client, mux, _ := setup(t)
   483  
   484  	mux.HandleFunc("/repos/o/repo/rulesets", func(w http.ResponseWriter, r *http.Request) {
   485  		testMethod(t, r, "GET")
   486  		fmt.Fprint(w, `[
   487  			{
   488  			  "id": 42,
   489  			  "name": "ruleset",
   490  			  "source_type": "Repository",
   491  			  "source": "o/repo",
   492  			  "enforcement": "enabled"
   493  			},
   494  			{
   495  			  "id": 314,
   496  			  "name": "Another ruleset",
   497  			  "source_type": "Repository",
   498  			  "source": "o/repo",
   499  			  "enforcement": "enabled"
   500  			}
   501  		]`)
   502  	})
   503  
   504  	ctx := context.Background()
   505  	ruleSet, _, err := client.Repositories.GetAllRulesets(ctx, "o", "repo", false)
   506  	if err != nil {
   507  		t.Errorf("Repositories.GetAllRulesets returned error: %v", err)
   508  	}
   509  
   510  	want := []*Ruleset{
   511  		{
   512  			ID:          Int64(42),
   513  			Name:        "ruleset",
   514  			SourceType:  String("Repository"),
   515  			Source:      "o/repo",
   516  			Enforcement: "enabled",
   517  		},
   518  		{
   519  			ID:          Int64(314),
   520  			Name:        "Another ruleset",
   521  			SourceType:  String("Repository"),
   522  			Source:      "o/repo",
   523  			Enforcement: "enabled",
   524  		},
   525  	}
   526  	if !cmp.Equal(ruleSet, want) {
   527  		t.Errorf("Repositories.GetAllRulesets returned %+v, want %+v", ruleSet, want)
   528  	}
   529  
   530  	const methodName = "GetAllRulesets"
   531  
   532  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   533  		got, resp, err := client.Repositories.GetAllRulesets(ctx, "o", "repo", false)
   534  		if got != nil {
   535  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   536  		}
   537  		return resp, err
   538  	})
   539  }
   540  
   541  func TestRepositoriesService_CreateRuleset(t *testing.T) {
   542  	t.Parallel()
   543  	client, mux, _ := setup(t)
   544  
   545  	mux.HandleFunc("/repos/o/repo/rulesets", func(w http.ResponseWriter, r *http.Request) {
   546  		testMethod(t, r, "POST")
   547  		fmt.Fprint(w, `{
   548  			"id": 42,
   549  			"name": "ruleset",
   550  			"source_type": "Repository",
   551  			"source": "o/repo",
   552  			"enforcement": "enabled"
   553  		}`)
   554  	})
   555  
   556  	ctx := context.Background()
   557  	ruleSet, _, err := client.Repositories.CreateRuleset(ctx, "o", "repo", &Ruleset{
   558  		Name:        "ruleset",
   559  		Enforcement: "enabled",
   560  	})
   561  	if err != nil {
   562  		t.Errorf("Repositories.CreateRuleset returned error: %v", err)
   563  	}
   564  
   565  	want := &Ruleset{
   566  		ID:          Int64(42),
   567  		Name:        "ruleset",
   568  		SourceType:  String("Repository"),
   569  		Source:      "o/repo",
   570  		Enforcement: "enabled",
   571  	}
   572  	if !cmp.Equal(ruleSet, want) {
   573  		t.Errorf("Repositories.CreateRuleset returned %+v, want %+v", ruleSet, want)
   574  	}
   575  
   576  	const methodName = "CreateRuleset"
   577  
   578  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   579  		got, resp, err := client.Repositories.CreateRuleset(ctx, "o", "repo", &Ruleset{})
   580  		if got != nil {
   581  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   582  		}
   583  		return resp, err
   584  	})
   585  }
   586  
   587  func TestRepositoriesService_CreateRulesetWithPushRules(t *testing.T) {
   588  	t.Parallel()
   589  	client, mux, _ := setup(t)
   590  
   591  	mux.HandleFunc("/repos/o/repo/rulesets", func(w http.ResponseWriter, r *http.Request) {
   592  		testMethod(t, r, "POST")
   593  		fmt.Fprint(w, `{
   594  			"id": 42,
   595  			"name": "ruleset",
   596  			"source_type": "Repository",
   597  			"source": "o/repo",
   598  			"enforcement": "enabled",
   599  			"target": "push",
   600  			"rules": [
   601  				{
   602  					"type": "file_path_restriction",
   603  					"parameters": {
   604  						"restricted_file_paths": ["/a/file"]
   605  					}
   606  				},
   607  				{
   608  					"type": "max_file_path_length",
   609  					"parameters": {
   610  						"max_file_path_length": 255
   611  					}
   612  				},
   613  				{
   614  					"type": "file_extension_restriction",
   615  					"parameters": {
   616  						"restricted_file_extensions": [".exe"]
   617  					}
   618  				},
   619  				{
   620  					"type": "max_file_size",
   621  					"parameters": {
   622  						"max_file_size": 1024
   623  					}
   624  				}
   625  			]
   626  		}`)
   627  	})
   628  
   629  	ctx := context.Background()
   630  	ruleSet, _, err := client.Repositories.CreateRuleset(ctx, "o", "repo", &Ruleset{
   631  		Name:        "ruleset",
   632  		Enforcement: "enabled",
   633  	})
   634  	if err != nil {
   635  		t.Errorf("Repositories.CreateRuleset returned error: %v", err)
   636  	}
   637  
   638  	want := &Ruleset{
   639  		ID:          Int64(42),
   640  		Name:        "ruleset",
   641  		SourceType:  String("Repository"),
   642  		Source:      "o/repo",
   643  		Target:      String("push"),
   644  		Enforcement: "enabled",
   645  		Rules: []*RepositoryRule{
   646  			NewFilePathRestrictionRule(&RuleFileParameters{
   647  				RestrictedFilePaths: &[]string{"/a/file"},
   648  			}),
   649  			NewMaxFilePathLengthRule(&RuleMaxFilePathLengthParameters{
   650  				MaxFilePathLength: 255,
   651  			}),
   652  			NewFileExtensionRestrictionRule(&RuleFileExtensionRestrictionParameters{
   653  				RestrictedFileExtensions: []string{".exe"},
   654  			}),
   655  			NewMaxFileSizeRule(&RuleMaxFileSizeParameters{
   656  				MaxFileSize: 1024,
   657  			}),
   658  		},
   659  	}
   660  	if !cmp.Equal(ruleSet, want) {
   661  		t.Errorf("Repositories.CreateRuleset returned %+v, want %+v", ruleSet, want)
   662  	}
   663  
   664  	const methodName = "CreateRuleset"
   665  
   666  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   667  		got, resp, err := client.Repositories.CreateRuleset(ctx, "o", "repo", &Ruleset{})
   668  		if got != nil {
   669  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   670  		}
   671  		return resp, err
   672  	})
   673  }
   674  
   675  func TestRepositoriesService_GetRuleset(t *testing.T) {
   676  	t.Parallel()
   677  	client, mux, _ := setup(t)
   678  
   679  	mux.HandleFunc("/repos/o/repo/rulesets/42", func(w http.ResponseWriter, r *http.Request) {
   680  		testMethod(t, r, "GET")
   681  		fmt.Fprint(w, `{
   682  			"id": 42,
   683  			"name": "ruleset",
   684  			"source_type": "Organization",
   685  			"source": "o",
   686  			"enforcement": "enabled"
   687  		}`)
   688  	})
   689  
   690  	ctx := context.Background()
   691  	ruleSet, _, err := client.Repositories.GetRuleset(ctx, "o", "repo", 42, true)
   692  	if err != nil {
   693  		t.Errorf("Repositories.GetRuleset returned error: %v", err)
   694  	}
   695  
   696  	want := &Ruleset{
   697  		ID:          Int64(42),
   698  		Name:        "ruleset",
   699  		SourceType:  String("Organization"),
   700  		Source:      "o",
   701  		Enforcement: "enabled",
   702  	}
   703  	if !cmp.Equal(ruleSet, want) {
   704  		t.Errorf("Repositories.GetRuleset returned %+v, want %+v", ruleSet, want)
   705  	}
   706  
   707  	const methodName = "GetRuleset"
   708  
   709  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   710  		got, resp, err := client.Repositories.GetRuleset(ctx, "o", "repo", 42, true)
   711  		if got != nil {
   712  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   713  		}
   714  		return resp, err
   715  	})
   716  }
   717  
   718  func TestRepositoriesService_UpdateRulesetNoBypassActor(t *testing.T) {
   719  	t.Parallel()
   720  	client, mux, _ := setup(t)
   721  
   722  	rs := &Ruleset{
   723  		Name:        "ruleset",
   724  		Source:      "o/repo",
   725  		Enforcement: "enabled",
   726  	}
   727  
   728  	mux.HandleFunc("/repos/o/repo/rulesets/42", func(w http.ResponseWriter, r *http.Request) {
   729  		testMethod(t, r, "PUT")
   730  		fmt.Fprint(w, `{
   731  			"id": 42,
   732  			"name": "ruleset",
   733  			"source_type": "Repository",
   734  			"source": "o/repo",
   735  			"enforcement": "enabled"
   736  		}`)
   737  	})
   738  
   739  	ctx := context.Background()
   740  
   741  	ruleSet, _, err := client.Repositories.UpdateRulesetNoBypassActor(ctx, "o", "repo", 42, rs)
   742  
   743  	if err != nil {
   744  		t.Errorf("Repositories.UpdateRulesetNoBypassActor returned error: %v \n", err)
   745  	}
   746  
   747  	want := &Ruleset{
   748  		ID:          Int64(42),
   749  		Name:        "ruleset",
   750  		SourceType:  String("Repository"),
   751  		Source:      "o/repo",
   752  		Enforcement: "enabled",
   753  	}
   754  
   755  	if !cmp.Equal(ruleSet, want) {
   756  		t.Errorf("Repositories.UpdateRulesetNoBypassActor returned %+v, want %+v", ruleSet, want)
   757  	}
   758  
   759  	const methodName = "UpdateRulesetNoBypassActor"
   760  
   761  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   762  		got, resp, err := client.Repositories.UpdateRulesetNoBypassActor(ctx, "o", "repo", 42, nil)
   763  		if got != nil {
   764  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   765  		}
   766  		return resp, err
   767  	})
   768  }
   769  
   770  func TestRepositoriesService_UpdateRuleset(t *testing.T) {
   771  	t.Parallel()
   772  	client, mux, _ := setup(t)
   773  
   774  	mux.HandleFunc("/repos/o/repo/rulesets/42", func(w http.ResponseWriter, r *http.Request) {
   775  		testMethod(t, r, "PUT")
   776  		fmt.Fprint(w, `{
   777  			"id": 42,
   778  			"name": "ruleset",
   779  			"source_type": "Repository",
   780  			"source": "o/repo",
   781  			"enforcement": "enabled"
   782  		}`)
   783  	})
   784  
   785  	ctx := context.Background()
   786  	ruleSet, _, err := client.Repositories.UpdateRuleset(ctx, "o", "repo", 42, &Ruleset{
   787  		Name:        "ruleset",
   788  		Enforcement: "enabled",
   789  	})
   790  	if err != nil {
   791  		t.Errorf("Repositories.UpdateRuleset returned error: %v", err)
   792  	}
   793  
   794  	want := &Ruleset{
   795  		ID:          Int64(42),
   796  		Name:        "ruleset",
   797  		SourceType:  String("Repository"),
   798  		Source:      "o/repo",
   799  		Enforcement: "enabled",
   800  	}
   801  
   802  	if !cmp.Equal(ruleSet, want) {
   803  		t.Errorf("Repositories.UpdateRuleset returned %+v, want %+v", ruleSet, want)
   804  	}
   805  
   806  	const methodName = "UpdateRuleset"
   807  
   808  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   809  		got, resp, err := client.Repositories.UpdateRuleset(ctx, "o", "repo", 42, nil)
   810  		if got != nil {
   811  			t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got)
   812  		}
   813  		return resp, err
   814  	})
   815  }
   816  
   817  func TestRepositoriesService_DeleteRuleset(t *testing.T) {
   818  	t.Parallel()
   819  	client, mux, _ := setup(t)
   820  
   821  	mux.HandleFunc("/repos/o/repo/rulesets/42", func(w http.ResponseWriter, r *http.Request) {
   822  		testMethod(t, r, "DELETE")
   823  	})
   824  
   825  	ctx := context.Background()
   826  	_, err := client.Repositories.DeleteRuleset(ctx, "o", "repo", 42)
   827  	if err != nil {
   828  		t.Errorf("Repositories.DeleteRuleset returned error: %v", err)
   829  	}
   830  
   831  	const methodName = "DeleteRuleset"
   832  
   833  	testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) {
   834  		return client.Repositories.DeleteRuleset(ctx, "o", "repo", 42)
   835  	})
   836  }