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 possibility to add assignees to pull request #196

Merged
Merged
Changes from 2 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
3 changes: 3 additions & 0 deletions cmd/cmd-run.go
Original file line number Diff line number Diff line change
@@ -38,6 +38,7 @@ func RunCmd() *cobra.Command {
cmd.Flags().StringP("pr-body", "b", "", "The body of the commit message. Will default to everything but the first line of the commit message if none is set.")
cmd.Flags().StringP("commit-message", "m", "", "The commit message. Will default to title + body if none is set.")
cmd.Flags().StringSliceP("reviewers", "r", nil, "The username of the reviewers to be added on the pull request.")
cmd.Flags().StringSliceP("assignees", "a", nil, "The username of the assignees to be added on the pull request.")
cmd.Flags().IntP("max-reviewers", "M", 0, "If this value is set, reviewers will be randomized.")
cmd.Flags().IntP("concurrent", "C", 1, "The maximum number of concurrent runs.")
cmd.Flags().BoolP("skip-pr", "", false, "Skip pull request and directly push to the branch.")
@@ -74,6 +75,7 @@ func run(cmd *cobra.Command, args []string) error {
authorName, _ := flag.GetString("author-name")
authorEmail, _ := flag.GetString("author-email")
strOutput, _ := flag.GetString("output")
assignees, _ := flag.GetStringSlice("assignees")

if concurrent < 1 {
return errors.New("concurrent runs can't be less than one")
@@ -168,6 +170,7 @@ func run(cmd *cobra.Command, args []string) error {
SkipPullRequest: skipPullRequest,
CommitAuthor: commitAuthor,
BaseBranch: baseBranchName,
Assignees: assignees,

Concurrent: concurrent,

1 change: 1 addition & 0 deletions internal/git/pullrequest.go
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@ type NewPullRequest struct {
Base string

Reviewers []string // The username of all reviewers
Assignees []string
}

// PullRequestStatus is the status of a pull request, including statuses of the last commit
2 changes: 2 additions & 0 deletions internal/multigitter/run.go
Original file line number Diff line number Diff line change
@@ -50,6 +50,7 @@ type Runner struct {
DryRun bool
CommitAuthor *git.CommitAuthor
BaseBranch string // The base branch of the PR, use default branch if not set
Assignees []string

Concurrent int
SkipPullRequest bool // If set, the script will run directly on the base-branch without creating any PR
@@ -278,6 +279,7 @@ func (r *Runner) runSingleRepo(ctx context.Context, repo git.Repository) (git.Pu
Head: r.FeatureBranch,
Base: baseBranch,
Reviewers: getReviewers(r.Reviewers, r.MaxReviewers),
Assignees: r.Assignees,
})
if err != nil {
return nil, err
48 changes: 32 additions & 16 deletions internal/scm/bitbucketserver/bitbucket_server.go
Original file line number Diff line number Diff line change
@@ -246,26 +246,21 @@ func (b *BitbucketServer) CreatePullRequest(ctx context.Context, repo git.Reposi

client := newClient(ctx, b.config)

var usersWithMetadata []bitbucketv1.UserWithMetadata
for _, reviewer := range newPR.Reviewers {
response, err := client.DefaultApi.GetUser(reviewer)
if err != nil {
return nil, err
}

var userWithLinks bitbucketv1.UserWithLinks
err = mapstructure.Decode(response.Values, &userWithLinks)
if err != nil {
return nil, err
}
reviewers, err := b.getUsersWithLinks(newPR.Reviewers, client)
if err != nil {
return nil, err
}

usersWithMetadata = append(usersWithMetadata, bitbucketv1.UserWithMetadata{User: userWithLinks})
assignees, err := b.getUsersWithLinks(newPR.Assignees, client)
Copy link
Owner

Choose a reason for hiding this comment

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

@ryancurrah Do you have the ability to test out the new --assignees flag in bitbucket server? 🙂

if err != nil {
return nil, err
}

response, err := client.DefaultApi.CreatePullRequest(r.project, r.name, bitbucketv1.PullRequest{
Title: newPR.Title,
Description: newPR.Body,
Reviewers: usersWithMetadata,
Title: newPR.Title,
Description: newPR.Body,
Reviewers: reviewers,
Participants: assignees,
FromRef: bitbucketv1.PullRequestRef{
ID: fmt.Sprintf("refs/heads/%s", newPR.Head),
Repository: bitbucketv1.Repository{
@@ -297,6 +292,27 @@ func (b *BitbucketServer) CreatePullRequest(ctx context.Context, repo git.Reposi
return newPullRequest(pullRequestResp), nil
}

func (b *BitbucketServer) getUsersWithLinks(usernames []string, client *bitbucketv1.APIClient) ([]bitbucketv1.UserWithMetadata, error) {
var usersWithMetadata []bitbucketv1.UserWithMetadata

for _, username := range usernames {
response, err := client.DefaultApi.GetUser(username)
if err != nil {
return nil, err
}

var userWithLinks bitbucketv1.UserWithLinks
err = mapstructure.Decode(response.Values, &userWithLinks)
if err != nil {
return nil, err
}

usersWithMetadata = append(usersWithMetadata, bitbucketv1.UserWithMetadata{User: userWithLinks})
}

return usersWithMetadata, nil
}

// GetPullRequests Gets the latest pull requests from repositories based on the scm configuration
func (b *BitbucketServer) GetPullRequests(ctx context.Context, branchName string) ([]git.PullRequest, error) {
client := newClient(ctx, b.config)
9 changes: 5 additions & 4 deletions internal/scm/gitea/gitea.go
Original file line number Diff line number Diff line change
@@ -207,10 +207,11 @@ func (g *Gitea) CreatePullRequest(ctx context.Context, repo git.Repository, prRe
head := fmt.Sprintf("%s:%s", prR.ownerName, newPR.Head)

pr, _, err := g.giteaClient(ctx).CreatePullRequest(r.ownerName, r.name, gitea.CreatePullRequestOption{
Head: head,
Base: newPR.Base,
Title: newPR.Title,
Body: newPR.Body,
Head: head,
Base: newPR.Base,
Title: newPR.Title,
Body: newPR.Body,
Assignees: newPR.Assignees,
})
if err != nil {
return nil, errors.Wrap(err, "could not create pull request")
12 changes: 12 additions & 0 deletions internal/scm/github/github.go
Original file line number Diff line number Diff line change
@@ -246,6 +246,10 @@ func (g Github) CreatePullRequest(ctx context.Context, repo git.Repository, prRe
return nil, err
}

if err := g.addAssignees(ctx, r, newPR, pr); err != nil {
return nil, err
}

return convertPullRequest(pr), nil
}

@@ -274,6 +278,14 @@ func (g Github) addReviewers(ctx context.Context, repo repository, newPR git.New
return err
}

func (g Github) addAssignees(ctx context.Context, repo repository, newPR git.NewPullRequest, createdPR *github.PullRequest) error {
if len(newPR.Assignees) == 0 {
return nil
}
_, _, err := g.ghClient.Issues.AddAssignees(ctx, repo.ownerName, repo.name, createdPR.GetNumber(), newPR.Assignees)
return err
}

// GetPullRequests gets all pull requests of with a specific branch
func (g Github) GetPullRequests(ctx context.Context, branchName string) ([]git.PullRequest, error) {
// TODO: If this is implemented with the GitHub v4 graphql api, it would be much faster
34 changes: 25 additions & 9 deletions internal/scm/gitlab/gitlab.go
Original file line number Diff line number Diff line change
@@ -206,14 +206,14 @@ func (g *Gitlab) CreatePullRequest(ctx context.Context, repo git.Repository, prR
r := repo.(repository)
prR := prRepo.(repository)

// Convert from usernames to user ids
var assigneeIDs []int
if len(newPR.Reviewers) > 0 {
var err error
assigneeIDs, err = g.getUserIDs(ctx, newPR.Reviewers)
if err != nil {
return nil, err
}
reviewersIDs, err := g.getUserIds(ctx, newPR.Reviewers)
if err != nil {
return nil, err
}

assigneesIDs, err := g.getUserIds(ctx, newPR.Assignees)
if err != nil {
return nil, err
}

removeSourceBranch := true
@@ -223,8 +223,9 @@ func (g *Gitlab) CreatePullRequest(ctx context.Context, repo git.Repository, prR
SourceBranch: &newPR.Head,
TargetBranch: &newPR.Base,
TargetProjectID: &r.pid,
AssigneeIDs: assigneeIDs,
ReviewerIDs: reviewersIDs,
RemoveSourceBranch: &removeSourceBranch,
AssigneeIDs: assigneesIDs,
})
if err != nil {
return nil, err
@@ -241,6 +242,21 @@ func (g *Gitlab) CreatePullRequest(ctx context.Context, repo git.Repository, prR
}, nil
}

func (g *Gitlab) getUserIds(ctx context.Context, usernames []string) ([]int, error) {
// Convert from usernames to user ids
var assigneeIDs []int

if len(usernames) > 0 {
var err error
assigneeIDs, err = g.getUserIDs(ctx, usernames)
if err != nil {
return nil, err
}
}

return assigneeIDs, nil
}

func (g *Gitlab) getUserIDs(ctx context.Context, usernames []string) ([]int, error) {
userIDs := make([]int, len(usernames))
for i := range usernames {
25 changes: 25 additions & 0 deletions tests/table_test.go
Original file line number Diff line number Diff line change
@@ -662,6 +662,31 @@ Repositories with a successful run:
`, runData.out)
},
},

{
name: "assignees",
vcCreate: func(t *testing.T) *vcmock.VersionController {
return &vcmock.VersionController{
Repositories: []vcmock.Repository{
createRepo(t, "owner", "should-change", "i like apples"),
},
}
},
args: []string{
"run",
"--author-name", "Test Author",
"--author-email", "test@example.com",
"-m", "custom message",
"-a", "assignee1,assignee2",
changerBinaryPath,
},
verify: func(t *testing.T, vcMock *vcmock.VersionController, runData runData) {
require.Len(t, vcMock.PullRequests, 1)
require.Len(t, vcMock.PullRequests[0].Assignees, 2)
assert.Contains(t, vcMock.PullRequests[0].Assignees, "assignee1")
assert.Contains(t, vcMock.PullRequests[0].Assignees, "assignee2")
},
},
}

for _, gitBackend := range gitBackends {