Skip to content

Implement rulesets #2795

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 39 commits into from
Jun 17, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
958a8a0
Add repository ruleset and related structs
liaodaniel May 31, 2023
1e2554c
Add GetAllOrganizationRepositoryRulesets
liaodaniel May 31, 2023
6a93946
Extend ruleset struct with conditions
liaodaniel May 31, 2023
5b15d81
Create all the different rules
liaodaniel May 31, 2023
dc199b5
Spilt out ruleset conditions in different types
liaodaniel May 31, 2023
90d803f
Add missing requiredStatusChecks struct
liaodaniel Jun 1, 2023
8b3f493
Add CreateOrganizationRepositoryRuleset
liaodaniel Jun 1, 2023
f2b462f
Fix unhandled rulesetRule type message
liaodaniel Jun 1, 2023
113d39f
Add comments on the rule creations
liaodaniel Jun 1, 2023
93e2a90
Add GetOrganizationRepositoryRuleset
liaodaniel Jun 1, 2023
3208f5c
Add copyright metadata
liaodaniel Jun 1, 2023
f58936c
Add UpdateOrganizationRepositoryRuleset
liaodaniel Jun 1, 2023
879e3e0
Add DeleteOrganizationRepositoryRuleset
liaodaniel Jun 1, 2023
d89d75a
Add comment on ruleset
liaodaniel Jun 1, 2023
51f34d4
Fix linting
liaodaniel Jun 1, 2023
8d47d85
Add tests for Rule_UnmarshalJSON
liaodaniel Jun 1, 2023
5439e29
Fix newline linting
liaodaniel Jun 1, 2023
3f1a6b4
Rename RuleSetRule to RepositoryRule
liaodaniel Jun 1, 2023
90c2a8d
Add GetRulesForBranch
liaodaniel Jun 1, 2023
0e828ee
Add GetAllRulesets
liaodaniel Jun 2, 2023
5589fc1
Add CreateRuleset
liaodaniel Jun 2, 2023
8c128a6
Add GetRuleset
liaodaniel Jun 2, 2023
7696f52
Add UpdateRuleset
liaodaniel Jun 2, 2023
9db0040
Fix http method for UpdateOrganizationRepositoryRuleset
liaodaniel Jun 2, 2023
fc0b2f1
Always return response when deleting rulesets
liaodaniel Jun 2, 2023
5a90752
Update comments
liaodaniel Jun 2, 2023
5492131
Small renaming and tidy up for consistency
liaodaniel Jun 2, 2023
fdbe041
Merge branch 'master' into add_org_ruleset
liaodaniel Jun 2, 2023
b814d7f
Add includesParent query to GetAllRulesets
liaodaniel Jun 2, 2023
c390b09
Further tidy up comments
liaodaniel Jun 2, 2023
6ab01f8
Fix the test for RepositoryRule UnmarshalJSON
liaodaniel Jun 2, 2023
a7d82e3
Make fields in RulesetRepositoryConditionParameters optional
liaodaniel Jun 2, 2023
fe12731
Fix line break and spelling
liaodaniel Jun 2, 2023
b584269
Rename some vars
liaodaniel Jun 4, 2023
ac74284
Simplify Ruleset struct to use list of pointers
liaodaniel Jun 4, 2023
b4eb612
Make BypassActor fields optional
liaodaniel Jun 5, 2023
ad0beca
Add testing for RepositoryRule UnmarshalJSON
liaodaniel Jun 5, 2023
5618f6f
Switch parameters to *json.RawMessage type
liaodaniel Jun 7, 2023
221c3ee
Merge branch 'master' into add_ruleset
liaodaniel Jun 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Further tidy up comments
Signed-off-by: Daniel Liao <[email protected]>
  • Loading branch information
liaodaniel committed Jun 2, 2023
commit c390b09c1ab6724df8053057f99d7ad0d6733492
10 changes: 5 additions & 5 deletions github/orgs_rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"fmt"
)

// GetAllOrganizationRulesets gets all the repository rulesets for the specified organization.
// GetAllOrganizationRulesets gets all the rulesets for the specified organization.
//
// GitHub API docs: https://docs.github.com/en/rest/orgs/rules#get-all-organization-repository-rulesets
func (s *OrganizationsService) GetAllOrganizationRulesets(ctx context.Context, org string) ([]*Ruleset, *Response, error) {
Expand All @@ -30,7 +30,7 @@ func (s *OrganizationsService) GetAllOrganizationRulesets(ctx context.Context, o
return rulesets, resp, nil
}

// CreateOrganizationRuleset creates a repository ruleset for the specified organization.
// CreateOrganizationRuleset creates a ruleset for the specified organization.
//
// GitHub API docs: https://docs.github.com/en/rest/orgs/rules#create-an-organization-repository-ruleset
func (s *OrganizationsService) CreateOrganizationRuleset(ctx context.Context, org string, rs *Ruleset) (*Ruleset, *Response, error) {
Expand All @@ -50,7 +50,7 @@ func (s *OrganizationsService) CreateOrganizationRuleset(ctx context.Context, or
return ruleset, resp, nil
}

// GetOrganizationRuleset gets a repository ruleset from the specified organization.
// GetOrganizationRuleset gets a ruleset from the specified organization.
//
// GitHub API docs: https://docs.github.com/en/rest/orgs/rules#get-an-organization-repository-ruleset
func (s *OrganizationsService) GetOrganizationRuleset(ctx context.Context, org string, rulesetID int64) (*Ruleset, *Response, error) {
Expand All @@ -70,7 +70,7 @@ func (s *OrganizationsService) GetOrganizationRuleset(ctx context.Context, org s
return rulesets, resp, nil
}

// UpdateOrganizationRuleset updates a repository ruleset from the specified organization.
// UpdateOrganizationRuleset updates a ruleset from the specified organization.
//
// GitHub API docs: https://docs.github.com/en/rest/orgs/rules#update-an-organization-repository-ruleset
func (s *OrganizationsService) UpdateOrganizationRuleset(ctx context.Context, org string, rulesetID int64, rs *Ruleset) (*Ruleset, *Response, error) {
Expand All @@ -90,7 +90,7 @@ func (s *OrganizationsService) UpdateOrganizationRuleset(ctx context.Context, or
return rulesets, resp, nil
}

// DeleteOrganizationRuleset deletes a repository ruleset from the specified organization.
// DeleteOrganizationRuleset deletes a ruleset from the specified organization.
//
// GitHub API docs: https://docs.github.com/en/rest/orgs/rules#delete-an-organization-repository-ruleset
func (s *OrganizationsService) DeleteOrganizationRuleset(ctx context.Context, org string, rulesetID int64) (*Response, error) {
Expand Down
47 changes: 25 additions & 22 deletions github/repos_rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"fmt"
)

// BypassActor represents the bypass actors from a repository ruleset.
// BypassActor represents the bypass actors from a ruleset.
type BypassActor struct {
ActorID int64 `json:"actor_id,omitempty"`
// Possible values for ActorType are: Team, Integration
Expand Down Expand Up @@ -47,7 +47,7 @@ type RulesetConditions struct {
RepositoryName *RulesetRepositoryConditionParameters `json:"repository_name,omitempty"`
}

// RulePatternParameters represents the rule pattern parameter.
// RulePatternParameters represents the rule pattern parameters.
type RulePatternParameters struct {
Name *string `json:"name,omitempty"`
// If Negate is true, the rule will fail if the pattern matches.
Expand Down Expand Up @@ -88,7 +88,7 @@ type RequiredStatusChecksRuleParameters struct {
StrictRequiredStatusChecksPolicy bool `json:"strict_required_status_checks_policy"`
}

// RepositoryRule represents a GitHub Rule within a Ruleset.
// RepositoryRule represents a GitHub Rule.
type RepositoryRule struct {
Type string `json:"type"`
Parameters interface{} `json:"parameters,omitempty"`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of interface{}, I'm wondering if this would be better to have a *json.RawMessage here like we do in other places in this repo?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can I get some guidance on how this might be done? I took a look at some of the other examples and they seem to suggest to allow users to pass in *json.RawMessage types as the parameters? I am on the fence with this one as I feel like you lose out on all the typed constructs when you switch over to this it in this particular case?

# Example of creating a pull request rule
func NewPullRequestRule(params *json.RawMessage) (rule *RepositoryRule) {
	return &RepositoryRule{
		Type:       "pull_request",
		Parameters: params,
	}
}

pullRequestParams := json.RawMessage(`{
	"dismiss_stale_reviews_on_push": true,
	"require_code_owner_review": true,
	"require_last_push_approval": true,
	"required_approving_review_count": 1,
	"required_review_thread_resolution": true
}`)

rule := NewPullRequestRule(&pullRequestParams),

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I'm OOO today and will take a look tomorrow.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, you don't have to give up strong typing with json.RawMessage... you can always marshal other strongly-typed structs into the raw message. It is just another way to handle variadic sub-messages within a JSON blob.
So I'm not sure you lose any functionality with json.RawMessage over the use of any... I think it is just a cleaner way of implementing the interface... but maybe I'm not understanding your question.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, thank you. Think I may have interpreted what you meant incorrectly previously.

Was this what you had in mind? See 5618f6f

Expand Down Expand Up @@ -147,51 +147,51 @@ func (r *RepositoryRule) UnmarshalJSON(data []byte) error {
return nil
}

// NewCreationRule creates a rule as part of a GitHub ruleset to only allow users with bypass permission to create matching refs.
// NewCreationRule creates a rule to only allow users with bypass permission to create matching refs.
func NewCreationRule() (rule RepositoryRule) {
return RepositoryRule{
Type: "creation",
}
}

// NewUpdateRule creates a rule as part of a GitHub ruleset to only allow users with bypass permission to update matching refs.
// NewUpdateRule creates a rule to only allow users with bypass permission to update matching refs.
func NewUpdateRule(params *UpdateAllowsFetchAndMergeRuleParameters) (rule RepositoryRule) {
return RepositoryRule{
Type: "update",
Parameters: params,
}
}

// NewDeletionRule creates a rule as part of a GitHub ruleset to only allow users with bypass permissions to delete matching refs.
// NewDeletionRule creates a rule to only allow users with bypass permissions to delete matching refs.
func NewDeletionRule() (rule RepositoryRule) {
return RepositoryRule{
Type: "deletion",
}
}

// NewRequiredLinearHistoryRule creates a rule as part of a GitHub ruleset to prevent merge commits from being pushed to matching branches.
// NewRequiredLinearHistoryRule creates a rule to prevent merge commits from being pushed to matching branches.
func NewRequiredLinearHistoryRule() (rule RepositoryRule) {
return RepositoryRule{
Type: "required_linear_history",
}
}

// NewRequiredDeploymentsRule creates a rule as part of a GitHub ruleset to require environments to be successfully deployed before they can be merged into the matching branches.
// NewRequiredDeploymentsRule creates a rule to require environments to be successfully deployed before they can be merged into the matching branches.
func NewRequiredDeploymentsRule(params *RequiredDeploymentEnvironmentsRuleParameters) (rule RepositoryRule) {
return RepositoryRule{
Type: "required_deployments",
Parameters: params,
}
}

// NewRequiredSignaturesRule creates a rule as part of a GitHub ruleset to require commits pushed to matching branches to have verified signatures.
// NewRequiredSignaturesRule creates a rule a to require commits pushed to matching branches to have verified signatures.
func NewRequiredSignaturesRule() (rule RepositoryRule) {
return RepositoryRule{
Type: "required_signatures",
}
}

// NewPullRequestRule creates a rule as part of a GitHub ruleset to require all commits be made to a non-target branch and submitted via a pull request before they can be merged.
// NewPullRequestRule creates a rule to require all commits be made to a non-target branch and submitted via a pull request before they can be merged.
func NewPullRequestRule(params *PullRequestRuleParameters) (
rule RepositoryRule) {
return RepositoryRule{
Expand All @@ -200,52 +200,54 @@ func NewPullRequestRule(params *PullRequestRuleParameters) (
}
}

// NewRequiredStatusChecksRule creates a rule as part of a GitHub ruleset to require which status checks must pass before branches can be merged into a branch rule.
// NewRequiredStatusChecksRule creates a rule to require which status checks must pass before branches can be merged into a branch rule.
func NewRequiredStatusChecksRule(params *RequiredStatusChecksRuleParameters) (rule RepositoryRule) {
return RepositoryRule{
Type: "required_status_checks",
Parameters: params,
}
}

// NewNonFastForwardRule creates a rule as part of a GitHub ruleset to prevent users with push access from force pushing to matching branches.
// NewNonFastForwardRule creates a rule as part to prevent users with push access from force pushing to matching branches.
func NewNonFastForwardRule() (rule RepositoryRule) {
return RepositoryRule{
Type: "non_fast_forward",
}
}

// NewCommitMessagePatternRule creates a rule as part of a GitHub ruleset to restrict commit message patterns being pushed to matching branches.
// NewCommitMessagePatternRule creates a rule to restrict commit message patterns being pushed to matching branches.
func NewCommitMessagePatternRule(pattern *RulePatternParameters) (rule RepositoryRule) {
return RepositoryRule{
Type: "commit_message_pattern",
Parameters: pattern,
}
}

// NewCommitAuthorEmailPatternRule creates a rule as part of a GitHub ruleset to restrict commits with author email patterns being merged into matching branches.
// NewCommitAuthorEmailPatternRule creates a rule to restrict commits with author email patterns being merged into matching branches.
func NewCommitAuthorEmailPatternRule(pattern *RulePatternParameters) (rule RepositoryRule) {
return RepositoryRule{
Type: "commit_author_email_pattern",
Parameters: pattern,
}
}

// NewCommitterEmailPatternRule creates a rule as part of a GitHub ruleset to restrict commits with committer email patterns being merged into matching branches.
// NewCommitterEmailPatternRule creates a rule to restrict commits with committer email patterns being merged into matching branches.
func NewCommitterEmailPatternRule(pattern *RulePatternParameters) (rule RepositoryRule) {
return RepositoryRule{
Type: "committer_email_pattern",
Parameters: pattern,
}
}

// NewBranchNamePatternRule creates a rule to restrict branch patterns from being merged into matching branches.
func NewBranchNamePatternRule(pattern *RulePatternParameters) (rule RepositoryRule) {
return RepositoryRule{
Type: "branch_name_pattern",
Parameters: pattern,
}
}

// NewTagNamePatternRule creates a rule to restrict tag patterns contained in non-target branches from being merged into matching branches.
func NewTagNamePatternRule(pattern *RulePatternParameters) (rule RepositoryRule) {
return RepositoryRule{
Type: "tag_name_pattern",
Expand Down Expand Up @@ -273,7 +275,7 @@ type Ruleset struct {
Rules *[]RepositoryRule `json:"rules,omitempty"`
}

// GetRulesForBranch gets all the repository rules that apply to the specified branch.
// GetRulesForBranch gets all the rules that apply to the specified branch.
//
// GitHub API docs: https://docs.github.com/en/rest/repos/rules#get-rules-for-a-branch
func (s *RepositoriesService) GetRulesForBranch(ctx context.Context, owner, repo, branch string) ([]*RepositoryRule, *Response, error) {
Expand All @@ -293,11 +295,12 @@ func (s *RepositoriesService) GetRulesForBranch(ctx context.Context, owner, repo
return rules, resp, nil
}

// GetAllRepositoryRulesets gets all the repository rules that apply to the specified repository.
// GetAllRulesets gets all the rules that apply to the specified repository.
// If includesParents is true, rulesets configured at the organisation level that apply to the repository will be returned.
//
// GitHub API docs: https://docs.github.com/en/rest/repos/rules#get-all-repository-rulesets
func (s *RepositoriesService) GetAllRulesets(ctx context.Context, owner, repo string, includesParent bool) ([]*Ruleset, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/rulesets?includes_parents=%v", owner, repo, includesParent)
func (s *RepositoriesService) GetAllRulesets(ctx context.Context, owner, repo string, includesParents bool) ([]*Ruleset, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/rulesets?includes_parents=%v", owner, repo, includesParents)

req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
Expand Down Expand Up @@ -334,11 +337,11 @@ func (s *RepositoriesService) CreateRuleset(ctx context.Context, owner, repo str
}

// GetRuleset gets a ruleset for the specified repository.
// If includesParent is true, rulesets configured at organisation level that apply to the repository can be retrieved.
// If includesParents is true, rulesets configured at the organisation level that apply to the repository will be returned.
//
// GitHub API docs: https://docs.github.com/en/rest/repos/rules#get-a-repository-ruleset
func (s *RepositoriesService) GetRuleset(ctx context.Context, owner, repo string, rulesetID int64, includesParent bool) (*Ruleset, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/rulesets/%v?includes_parents=%v", owner, repo, rulesetID, includesParent)
func (s *RepositoriesService) GetRuleset(ctx context.Context, owner, repo string, rulesetID int64, includesParents bool) (*Ruleset, *Response, error) {
u := fmt.Sprintf("repos/%v/%v/rulesets/%v?includes_parents=%v", owner, repo, rulesetID, includesParents)

req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
Expand Down