Skip to content
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

Add label option #135

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,7 @@ echo "gruntwork-io/terragrunt gruntwork-io/terratest" | git-xargs \
| `--no-skip-ci` | By default, git-xargs will prepend \"[skip ci]\" to its commit messages to prevent large git-xargs jobs from creating expensive CI jobs excessively. If you pass the `--no-skip-ci` flag, then git-xargs will not prepend \"[skip ci]\". Default: false, meaning that \"[skip ci]\" will be prepended to commit messages. | Bool | No |
| `--reviewers` | An optional slice of GitHub usernames, separated by commas, to request reviews from after a pull request is successfully opened. Default: empty slice, meaning that no reviewers will be requested. | String | No |
| `--team-reviewers` | An optional slice of GitHub team names, separated by commas, to request reviews from after a pull request is successfully opened. Default: empty slice, meaning that no team reviewers will be requested. IMPORTANT: Please read and understand [the GitHub restrictions](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/requesting-a-pull-request-review) on this functionality before using it! Only certain GitHub organizations / payment plans support this functionality. | String | No |
| `--label` | By default, the PR is opened without any labels. Use this flag multiple times to specify multiple labels that should be attached to the PR upon creation (e.g., --label bug --label enhancement). | String | No |
| `--keep-cloned-repositories` | By default, git-xargs will delete the repositories it clones to your temporary file directory once it has completed processing that repo, to save space on your machine. If you wish to retain the local repositories, pass this flag. | Bool | No |
## Best practices, tips and tricks

Expand Down
6 changes: 6 additions & 0 deletions auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ type githubRepositoriesService interface {
ListByOrg(ctx context.Context, org string, opts *github.RepositoryListByOrgOptions) ([]*github.Repository, *github.Response, error)
}

type githubIssuesService interface {
AddLabelsToIssue(ctx context.Context, owner string, repo string, number int, labels []string) ([]*github.Label, *github.Response, error)
}

// GithubClient is the data structure that is common between production code and test code. In production code,
// go-github satisfies the PullRequests and Repositories service interfaces, whereas in test the concrete
// implementations for these same services are mocks that return a static slice of pointers to GitHub repositories,
Expand All @@ -32,12 +36,14 @@ type githubRepositoriesService interface {
type GithubClient struct {
PullRequests githubPullRequestService
Repositories githubRepositoriesService
Issues githubIssuesService
}

func NewClient(client *github.Client) GithubClient {
return GithubClient{
PullRequests: client.PullRequests,
Repositories: client.Repositories,
Issues: client.Issues,
}
}

Expand Down
1 change: 1 addition & 0 deletions cmd/git-xargs.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ func parseGitXargsConfig(c *cli.Context) (*config.GitXargsConfig, error) {
config.PullRequestDescription = c.String("pull-request-description")
config.Reviewers = c.StringSlice("reviewers")
config.TeamReviewers = c.StringSlice("team-reviewers")
config.PullRequestLabelSlice = c.StringSlice("label")
config.ReposFile = c.String("repos")
config.GithubOrg = c.String("github-org")
config.RepoSlice = c.StringSlice("repo")
Expand Down
5 changes: 5 additions & 0 deletions common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const (
PullRequestDescriptionFlagName = "pull-request-description"
PullRequestReviewersFlagName = "reviewers"
PullRequestTeamReviewersFlagName = "team-reviewers"
PullRequestLabelFlagName = "label"
SecondsToWaitBetweenPrsFlagName = "seconds-between-prs"
DefaultCommitMessage = "git-xargs programmatic commit"
DefaultPullRequestTitle = "git-xargs programmatic pull request"
Expand Down Expand Up @@ -91,6 +92,10 @@ var (
Name: PullRequestTeamReviewersFlagName,
Usage: "A list of GitHub team names to request reviews from",
}
GenericPullRequestLabelFlag = cli.StringSliceFlag{
Name: PullRequestLabelFlagName,
Usage: "A single GitHub label to add to the pull request. Can be invoked multiple times with different labels",
}
GenericSecondsToWaitFlag = cli.IntFlag{
Name: SecondsToWaitBetweenPrsFlagName,
Usage: "The number of seconds to sleep between pull requests in order to respect GitHub API rate limits. Increase this number if you are being rate limited regularly. Defaults to 12 seconds.",
Expand Down
6 changes: 6 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type GitXargsConfig struct {
PullRequestDescription string
Reviewers []string
TeamReviewers []string
PullRequestLabelSlice []string
ReposFile string
GithubOrg string
RepoSlice []string
Expand Down Expand Up @@ -58,6 +59,7 @@ func NewGitXargsConfig() *GitXargsConfig {
PullRequestDescription: common.DefaultPullRequestDescription,
Reviewers: []string{},
TeamReviewers: []string{},
PullRequestLabelSlice: []string{},
ReposFile: "",
GithubOrg: "",
RepoSlice: []string{},
Expand Down Expand Up @@ -91,3 +93,7 @@ func NewGitXargsTestConfig() *GitXargsConfig {
func (c *GitXargsConfig) HasReviewers() bool {
return len(c.Reviewers) > 0 || len(c.TeamReviewers) > 0
}

func (c *GitXargsConfig) HasLabels() bool {
return len(c.PullRequestLabelSlice) > 0
}
1 change: 1 addition & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ func setupApp() *cli.App {
common.GenericPullRequestDescriptionFlag,
common.GenericPullRequestReviewersFlag,
common.GenericPullRequestTeamReviewersFlag,
common.GenericPullRequestLabelFlag,
common.GenericSecondsToWaitFlag,
common.GenericMaxPullRequestRetriesFlag,
common.GenericSecondsToWaitWhenRateLimitedFlag,
Expand Down
13 changes: 13 additions & 0 deletions mocks/mocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,15 @@ func (m mockGithubRepositoriesService) ListByOrg(ctx context.Context, org string
return m.Repositories, m.Response, nil
}

type mockGithubIssuesService struct {
Issue *github.Issue
Response *github.Response
}

func (m mockGithubIssuesService) AddLabelsToIssue(ctx context.Context, owner string, repo string, number int, labels []string) ([]*github.Label, *github.Response, error) {
return []*github.Label{}, m.Response, nil
}

// ConfigureMockGithubClient returns a valid GithubClient configured for testing purposes, complete with the mocked services
func ConfigureMockGithubClient() auth.GithubClient {
// Call the same NewClient method that is used by the actual CLI to obtain a GitHub client that calls the
Expand Down Expand Up @@ -126,6 +135,10 @@ func ConfigureMockGithubClient() auth.GithubClient {
},
Response: &github.Response{},
}
client.Issues = mockGithubIssuesService{
Issue: &github.Issue{},
Response: &github.Response{},
}

return client
}
Expand Down
9 changes: 9 additions & 0 deletions repository/repo-operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,15 @@ func openPullRequest(config *config.GitXargsConfig, pr types.OpenPrRequest) erro

}

// if the user supplied label information on the pull request, initiate a separate request to add label(s)
if config.HasLabels() {
_, _, labelRequestErr := config.GithubClient.Issues.AddLabelsToIssue(context.Background(), *pr.Repo.GetOwner().Login, pr.Repo.GetName(), githubPR.GetNumber(), config.PullRequestLabelSlice)
if labelRequestErr != nil {
config.Stats.TrackSingle(stats.AddLabelsToIssueErr, pr.Repo)
}

}

if config.Draft {
config.Stats.TrackDraftPullRequest(pr.Repo.GetName(), githubPR.GetHTMLURL())
} else {
Expand Down
3 changes: 3 additions & 0 deletions stats/stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ const (
PRFailedAfterMaximumRetriesErr types.Event = "pr-failed-after-maximum-retries"
// RequestReviewersErr denotes a repo whose follow up request to add reviewers to the opened pull request failed
RequestReviewersErr types.Event = "request-reviewers-error"
// AddLabelsToIssueErr denotes a repo whose follow up request to add labels to the opened pull request failed
AddLabelsToIssueErr types.Event = "add-labels-to-issue-error"
)

var allEvents = []types.AnnotatedEvent{
Expand Down Expand Up @@ -112,6 +114,7 @@ var allEvents = []types.AnnotatedEvent{
{Event: PRFailedDueToRateLimitsErr, Description: "Repos whose initial Pull Request failed to be created due to GitHub rate limits"},
{Event: PRFailedAfterMaximumRetriesErr, Description: "Repos whose Pull Request failed to be created after the maximum number of retries"},
{Event: RequestReviewersErr, Description: "Repos whose request to add reviewers to the opened pull request failed"},
{Event: AddLabelsToIssueErr, Description: "Repos whose request to add labels to the opened pull request failed"},
}

// RunStats will be a stats-tracker class that keeps score of which repos were touched, which were considered for update, which had branches made, PRs made, which were missing workflows or contexts, or had out of date workflows syntax values, etc
Expand Down