diff --git a/github/repos_rules.go b/github/repos_rules.go index 50e75cdba1..d09bb71d10 100644 --- a/github/repos_rules.go +++ b/github/repos_rules.go @@ -85,6 +85,21 @@ type RuleFileParameters struct { RestrictedFilePaths *[]string `json:"restricted_file_paths"` } +// RuleMaxFilePathLengthParameters represents the max_file_path_length rule parameters. +type RuleMaxFilePathLengthParameters struct { + MaxFilePathLength int `json:"max_file_path_length"` +} + +// RuleFileExtensionRestrictionParameters represents the file_extension_restriction rule parameters. +type RuleFileExtensionRestrictionParameters struct { + RestrictedFileExtensions []string `json:"restricted_file_extensions"` +} + +// RuleMaxFileSizeParameters represents the max_file_size rule parameters. +type RuleMaxFileSizeParameters struct { + MaxFileSize int64 `json:"max_file_size"` +} + // UpdateAllowsFetchAndMergeRuleParameters represents the update rule parameters. type UpdateAllowsFetchAndMergeRuleParameters struct { UpdateAllowsFetchAndMerge bool `json:"update_allows_fetch_and_merge"` @@ -255,6 +270,33 @@ func (r *RepositoryRule) UnmarshalJSON(data []byte) error { bytes, _ := json.Marshal(params) rawParams := json.RawMessage(bytes) + r.Parameters = &rawParams + case "max_file_path_length": + params := RuleMaxFilePathLengthParameters{} + if err := json.Unmarshal(*RepositoryRule.Parameters, ¶ms); err != nil { + return err + } + bytes, _ := json.Marshal(params) + rawParams := json.RawMessage(bytes) + + r.Parameters = &rawParams + case "file_extension_restriction": + params := RuleFileExtensionRestrictionParameters{} + if err := json.Unmarshal(*RepositoryRule.Parameters, ¶ms); err != nil { + return err + } + bytes, _ := json.Marshal(params) + rawParams := json.RawMessage(bytes) + + r.Parameters = &rawParams + case "max_file_size": + params := RuleMaxFileSizeParameters{} + if err := json.Unmarshal(*RepositoryRule.Parameters, ¶ms); err != nil { + return err + } + bytes, _ := json.Marshal(params) + rawParams := json.RawMessage(bytes) + r.Parameters = &rawParams default: r.Type = "" @@ -454,6 +496,42 @@ func NewFilePathRestrictionRule(params *RuleFileParameters) (rule *RepositoryRul } } +// NewMaxFilePathLengthRule creates a rule to restrict file paths longer than the limit from being pushed. +func NewMaxFilePathLengthRule(params *RuleMaxFilePathLengthParameters) (rule *RepositoryRule) { + bytes, _ := json.Marshal(params) + + rawParams := json.RawMessage(bytes) + + return &RepositoryRule{ + Type: "max_file_path_length", + Parameters: &rawParams, + } +} + +// NewFileExtensionRestrictionRule creates a rule to restrict file extensions from being pushed to a commit. +func NewFileExtensionRestrictionRule(params *RuleFileExtensionRestrictionParameters) (rule *RepositoryRule) { + bytes, _ := json.Marshal(params) + + rawParams := json.RawMessage(bytes) + + return &RepositoryRule{ + Type: "file_extension_restriction", + Parameters: &rawParams, + } +} + +// NewMaxFileSizeRule creates a rule to restrict file sizes from being pushed to a commit. +func NewMaxFileSizeRule(params *RuleMaxFileSizeParameters) (rule *RepositoryRule) { + bytes, _ := json.Marshal(params) + + rawParams := json.RawMessage(bytes) + + return &RepositoryRule{ + Type: "max_file_size", + Parameters: &rawParams, + } +} + // Ruleset represents a GitHub ruleset object. type Ruleset struct { ID *int64 `json:"id,omitempty"` diff --git a/github/repos_rules_test.go b/github/repos_rules_test.go index 8e123ed0f8..6daf753432 100644 --- a/github/repos_rules_test.go +++ b/github/repos_rules_test.go @@ -312,6 +312,48 @@ func TestRepositoryRule_UnmarshalJSON(t *testing.T) { }, wantErr: true, }, + "Valid max_file_path_length params": { + data: `{"type":"max_file_path_length","parameters":{"max_file_path_length": 255}}`, + want: NewMaxFilePathLengthRule(&RuleMaxFilePathLengthParameters{ + MaxFilePathLength: 255, + }), + }, + "Invalid max_file_path_length params": { + data: `{"type":"max_file_path_length","parameters":{"max_file_path_length": "255"}}`, + want: &RepositoryRule{ + Type: "max_file_path_length", + Parameters: nil, + }, + wantErr: true, + }, + "Valid file_extension_restriction params": { + data: `{"type":"file_extension_restriction","parameters":{"restricted_file_extensions":[".exe"]}}`, + want: NewFileExtensionRestrictionRule(&RuleFileExtensionRestrictionParameters{ + RestrictedFileExtensions: []string{".exe"}, + }), + }, + "Invalid file_extension_restriction params": { + data: `{"type":"file_extension_restriction","parameters":{"restricted_file_extensions":true}}`, + want: &RepositoryRule{ + Type: "file_extension_restriction", + Parameters: nil, + }, + wantErr: true, + }, + "Valid max_file_size params": { + data: `{"type":"max_file_size","parameters":{"max_file_size": 1024}}`, + want: NewMaxFileSizeRule(&RuleMaxFileSizeParameters{ + MaxFileSize: 1024, + }), + }, + "Invalid max_file_size params": { + data: `{"type":"max_file_size","parameters":{"max_file_size": "1024"}}`, + want: &RepositoryRule{ + Type: "max_file_size", + Parameters: nil, + }, + wantErr: true, + }, } for name, tc := range tests { @@ -539,6 +581,94 @@ func TestRepositoriesService_CreateRuleset(t *testing.T) { }) } +func TestRepositoriesService_CreateRulesetWithPushRules(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/repos/o/repo/rulesets", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "POST") + fmt.Fprint(w, `{ + "id": 42, + "name": "ruleset", + "source_type": "Repository", + "source": "o/repo", + "enforcement": "enabled", + "target": "push", + "rules": [ + { + "type": "file_path_restriction", + "parameters": { + "restricted_file_paths": ["/a/file"] + } + }, + { + "type": "max_file_path_length", + "parameters": { + "max_file_path_length": 255 + } + }, + { + "type": "file_extension_restriction", + "parameters": { + "restricted_file_extensions": [".exe"] + } + }, + { + "type": "max_file_size", + "parameters": { + "max_file_size": 1024 + } + } + ] + }`) + }) + + ctx := context.Background() + ruleSet, _, err := client.Repositories.CreateRuleset(ctx, "o", "repo", &Ruleset{ + Name: "ruleset", + Enforcement: "enabled", + }) + if err != nil { + t.Errorf("Repositories.CreateRuleset returned error: %v", err) + } + + want := &Ruleset{ + ID: Int64(42), + Name: "ruleset", + SourceType: String("Repository"), + Source: "o/repo", + Target: String("push"), + Enforcement: "enabled", + Rules: []*RepositoryRule{ + NewFilePathRestrictionRule(&RuleFileParameters{ + RestrictedFilePaths: &[]string{"/a/file"}, + }), + NewMaxFilePathLengthRule(&RuleMaxFilePathLengthParameters{ + MaxFilePathLength: 255, + }), + NewFileExtensionRestrictionRule(&RuleFileExtensionRestrictionParameters{ + RestrictedFileExtensions: []string{".exe"}, + }), + NewMaxFileSizeRule(&RuleMaxFileSizeParameters{ + MaxFileSize: 1024, + }), + }, + } + if !cmp.Equal(ruleSet, want) { + t.Errorf("Repositories.CreateRuleset returned %+v, want %+v", ruleSet, want) + } + + const methodName = "CreateRuleset" + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.CreateRuleset(ctx, "o", "repo", &Ruleset{}) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + func TestRepositoriesService_GetRuleset(t *testing.T) { client, mux, _, teardown := setup() defer teardown()