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  }