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 GetPullRequest by ID #92

Merged
merged 20 commits into from
Jul 24, 2023
Merged
Show file tree
Hide file tree
Changes from 13 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
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Currently supported providers are: [GitHub](#github), [Bitbucket Server](#bitbuc
- [Get Commit Status](#get-commit-status)
- [Create Pull Request](#create-pull-request)
- [List Open Pull Requests](#list-open-pull-requests)
- [Get Pull Request](#get-pull-request)
EyalDelarea marked this conversation as resolved.
Show resolved Hide resolved
- [Add Pull Request Comment](#add-pull-request-comment)
- [List Pull Request Comments](#list-pull-request-comments)
- [Get Latest Commit](#get-latest-commit)
Expand Down Expand Up @@ -345,6 +346,21 @@ repository := "jfrog-cli"
openPullRequests, err := client.ListOpenPullRequests(ctx, owner, repository)
```

#### Get Pull Request
EyalDelarea marked this conversation as resolved.
Show resolved Hide resolved

```go
// Go context
ctx := context.Background()
// Organization or username
owner := "jfrog"
// VCS repository
repository := "jfrog-cli"
// Pull Request ID
pullRequestId := 1

openPullRequests, err := client.GetPullReequest(ctx, owner, repository, pullRequestId)
```

##### Add Pull Request Comment

```go
Expand Down
50 changes: 36 additions & 14 deletions vcsclient/azurerepos.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,24 +249,29 @@ func (client *AzureReposClient) ListOpenPullRequests(ctx context.Context, _, rep
}
var pullRequestsInfo []PullRequestInfo
for _, pullRequest := range *pullRequests {
// Trim the branches prefix and get the actual branches name
shortSourceName := (*pullRequest.SourceRefName)[strings.LastIndex(*pullRequest.SourceRefName, "/")+1:]
shortTargetName := (*pullRequest.TargetRefName)[strings.LastIndex(*pullRequest.TargetRefName, "/")+1:]
pullRequestsInfo = append(pullRequestsInfo, PullRequestInfo{
ID: int64(*pullRequest.PullRequestId),
Source: BranchInfo{
Name: shortSourceName,
Repository: repository,
},
Target: BranchInfo{
Name: shortTargetName,
Repository: repository,
},
})
pullRequestDetails := parsePullRequestDetails(pullRequest, repository)
pullRequestsInfo = append(pullRequestsInfo, pullRequestDetails)
}
return pullRequestsInfo, nil
}

func (client *AzureReposClient) GetPullRequest(ctx context.Context, owner, repository string, pullRequestId int) (pullRequestInfo PullRequestInfo, err error) {
azureReposGitClient, err := client.buildAzureReposClient(ctx)
if err != nil {
return
}
client.logger.Debug(fetchingPullRequestById, repository)
pullRequest, err := azureReposGitClient.GetPullRequestById(ctx, git.GetPullRequestByIdArgs{
PullRequestId: &pullRequestId,
Project: &client.vcsInfo.Project,
})
if err != nil {
return
}
pullRequestInfo = parsePullRequestDetails(*pullRequest, repository)
return
}

// GetLatestCommit on Azure Repos
func (client *AzureReposClient) GetLatestCommit(ctx context.Context, _, repository, branch string) (CommitInfo, error) {
azureReposGitClient, err := client.buildAzureReposClient(ctx)
Expand Down Expand Up @@ -518,6 +523,23 @@ func (client *AzureReposClient) GetModifiedFiles(ctx context.Context, _, reposit
return fileNamesList, nil
}

func parsePullRequestDetails(pullRequest git.GitPullRequest, repository string) PullRequestInfo {
// Trim the branches prefix and get the actual branches name
shortSourceName := (*pullRequest.SourceRefName)[strings.LastIndex(*pullRequest.SourceRefName, "/")+1:]
shortTargetName := (*pullRequest.TargetRefName)[strings.LastIndex(*pullRequest.TargetRefName, "/")+1:]
return PullRequestInfo{
ID: int64(*pullRequest.PullRequestId),
Source: BranchInfo{
Name: shortSourceName,
Repository: repository,
},
Target: BranchInfo{
Name: shortTargetName,
Repository: repository,
},
}
}

// mapStatusToString maps commit status enum to string, specific for azure.
func mapStatusToString(status CommitStatus) string {
conversionMap := map[CommitStatus]string{
Expand Down
25 changes: 25 additions & 0 deletions vcsclient/azurerepos_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,31 @@ func TestAzureRepos_TestListOpenPullRequests(t *testing.T) {
assert.Error(t, err)
}

func TestAzureReposClient_GetPullRequest(t *testing.T) {
pullRequestId := 1
repoName := "repoName"
sourceName := "source"
targetName := "master"
res := git.GitPullRequest{
SourceRefName: &sourceName,
TargetRefName: &targetName,
PullRequestId: &pullRequestId,
}
jsonRes, err := json.Marshal(res)
assert.NoError(t, err)
ctx := context.Background()
client, cleanUp := createServerAndClient(t, vcsutils.AzureRepos, true, jsonRes, fmt.Sprintf("getPullRequests/%d", pullRequestId), createAzureReposHandler)
defer cleanUp()
pullRequestsInfo, err := client.GetPullRequest(ctx, "", repoName, pullRequestId)
assert.NoError(t, err)
assert.True(t, reflect.DeepEqual(pullRequestsInfo, PullRequestInfo{ID: 1, Source: BranchInfo{Name: sourceName, Repository: repoName}, Target: BranchInfo{Name: targetName, Repository: repoName}}))

badClient, cleanUp := createBadAzureReposClient(t, []byte{})
defer cleanUp()
_, err = badClient.GetPullRequest(ctx, "", repo1, pullRequestId)
assert.Error(t, err)
}

func TestListPullRequestComments(t *testing.T) {
type ListPullRequestCommentsResponse struct {
Value []git.GitPullRequestCommentThread
Expand Down
36 changes: 36 additions & 0 deletions vcsclient/bitbucketcloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"net/http"
"net/url"
"sort"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -320,6 +321,41 @@ func (client *BitbucketCloudClient) ListOpenPullRequests(ctx context.Context, ow
return mapBitbucketCloudPullRequestToPullRequestInfo(&parsedPullRequests), nil
}

func (client *BitbucketCloudClient) GetPullRequest(ctx context.Context, owner, repository string, pullRequestId int) (pullRequestInfo PullRequestInfo, err error) {
err = validateParametersNotBlank(map[string]string{"owner": owner, "repository": repository})
if err != nil {
return
}
bitbucketClient := client.buildBitbucketCloudClient(ctx)
client.logger.Debug(fetchingPullRequestById, repository)
prIdStr := strconv.Itoa(pullRequestId)
options := &bitbucket.PullRequestsOptions{
Owner: owner,
RepoSlug: repository,
ID: prIdStr,
}
pullRequestRaw, err := bitbucketClient.Repositories.PullRequests.Get(options)
if err != nil {
return
}
pullRequestDetails, err := vcsutils.RemapFields[pullRequestsDetails](pullRequestRaw, "json")
if err != nil {
return
}
pullRequestInfo = PullRequestInfo{
ID: pullRequestDetails.ID,
Source: BranchInfo{
Name: pullRequestDetails.Source.Name.Str,
Repository: pullRequestDetails.Source.Repository.Name,
},
Target: BranchInfo{
Name: pullRequestDetails.Target.Name.Str,
Repository: pullRequestDetails.Target.Repository.Name,
},
}
return
}

// AddPullRequestComment on Bitbucket cloud
func (client *BitbucketCloudClient) AddPullRequestComment(ctx context.Context, owner, repository, content string, pullRequestID int) error {
err := validateParametersNotBlank(map[string]string{"owner": owner, "repository": repository, "content": content})
Expand Down
36 changes: 36 additions & 0 deletions vcsclient/bitbucketcloud_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,42 @@ func TestBitbucketCloud_ListOpenPullRequests(t *testing.T) {
}, result[0]))
}

func TestBitbucketCloudClient_GetPullRequest(t *testing.T) {
pullRequestId := 1
repoName := "froggit"
ctx := context.Background()

// Successful Response
response, err := os.ReadFile(filepath.Join("testdata", "bitbucketcloud", "get_pull_request_response.json"))
assert.NoError(t, err)
client, cleanUp := createServerAndClient(t, vcsutils.BitbucketCloud, true, response,
fmt.Sprintf("/repositories/%s/%s/pullrequests/%d", owner, repoName, pullRequestId), createBitbucketCloudHandler)
defer cleanUp()
result, err := client.GetPullRequest(ctx, owner, repoName, pullRequestId)
assert.NoError(t, err)
assert.True(t, reflect.DeepEqual(PullRequestInfo{
ID: int64(pullRequestId),
Source: BranchInfo{Name: "pr", Repository: "workspace/froggit"},
Target: BranchInfo{Name: "main", Repository: "workspace/froggit"},
}, result))

// Bad Response
badClient, badClientCleanUp := createServerAndClient(t, vcsutils.BitbucketCloud, true, "{",
fmt.Sprintf("/repositories/%s/%s/pullrequests/%d", owner, repoName, pullRequestId), createBitbucketCloudHandler)
defer badClientCleanUp()
_, err = badClient.GetPullRequest(ctx, owner, repoName, pullRequestId)
assert.Error(t, err)

// Bad Fields
badRepoName := ""
badParseClient, badParseClientCleanUp := createServerAndClient(t, vcsutils.BitbucketCloud, true, response,
fmt.Sprintf("/repositories/%s/%s/pullrequests/%d", owner, badRepoName, pullRequestId), createBitbucketCloudHandler)
defer badParseClientCleanUp()
_, err = badParseClient.GetPullRequest(ctx, owner, badRepoName, pullRequestId)
assert.Error(t, err)

}

func TestBitbucketCloud_AddPullRequestComment(t *testing.T) {
ctx := context.Background()
client, cleanUp := createServerAndClient(t, vcsutils.BitbucketCloud, true, nil, "/repositories/jfrog/repo-1/pullrequests/1/comments", createBitbucketCloudHandler)
Expand Down
23 changes: 23 additions & 0 deletions vcsclient/bitbucketserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,29 @@ func (client *BitbucketServerClient) ListOpenPullRequests(ctx context.Context, o
return results, nil
}

// GetPullRequestInfoById on bitbucket server
func (client *BitbucketServerClient) GetPullRequest(ctx context.Context, owner, repository string, pullRequestId int) (pullRequestInfo PullRequestInfo, err error) {
client.logger.Debug("fetching pull request by ID in ", repository)
bitbucketClient, err := client.buildBitbucketClient(ctx)
if err != nil {
return
}
apiResponse, err := bitbucketClient.GetPullRequest(owner, repository, pullRequestId)
if err != nil {
return
}
pullRequest, err := bitbucketv1.GetPullRequestResponse(apiResponse)
if err != nil {
return
}
pullRequestInfo = PullRequestInfo{
ID: int64(pullRequest.ID),
Source: BranchInfo{Name: pullRequest.FromRef.ID, Repository: pullRequest.ToRef.Repository.Slug},
Target: BranchInfo{Name: pullRequest.ToRef.ID, Repository: pullRequest.ToRef.Repository.Slug},
}
return
}

// AddPullRequestComment on Bitbucket server
func (client *BitbucketServerClient) AddPullRequestComment(ctx context.Context, owner, repository, content string, pullRequestID int) error {
err := validateParametersNotBlank(map[string]string{"owner": owner, "repository": repository, "content": content})
Expand Down
30 changes: 30 additions & 0 deletions vcsclient/bitbucketserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,36 @@ func TestBitbucketServer_ListOpenPullRequests(t *testing.T) {
}, result[0]))
}

func TestBitbucketServerClient_GetPullRequest(t *testing.T) {
ctx := context.Background()
response, err := os.ReadFile(filepath.Join("testdata", "bitbucketserver", "get_pull_request_response.json"))
assert.NoError(t, err)
pullRequestId := 6

// Successful
client, cleanUp := createServerAndClient(t, vcsutils.BitbucketServer, true, response,
fmt.Sprintf("/rest/api/1.0/projects/%s/repos/%s/pull-requests/%d", owner, repo1, pullRequestId), createBitbucketServerHandler)
defer cleanUp()
result, err := client.GetPullRequest(ctx, owner, repo1, pullRequestId)
require.NoError(t, err)
assert.True(t, reflect.DeepEqual(PullRequestInfo{
ID: int64(pullRequestId),
Source: BranchInfo{Name: "refs/heads/new_vul_2", Repository: "repoName"},
Target: BranchInfo{Name: "refs/heads/master", Repository: "repoName"},
}, result))

// Bad response
badClient, badClientCleanUp := createServerAndClient(t, vcsutils.BitbucketServer, true, "{",
fmt.Sprintf("/rest/api/1.0/projects/%s/repos/%s/pull-requests/%d", owner, repo1, pullRequestId), createBitbucketServerHandler)
defer badClientCleanUp()
_, err2 := badClient.GetPullRequest(ctx, owner, repo1, pullRequestId)
require.Error(t, err2)

// Bad Client
_, err = createBadBitbucketServerClient(t).GetPullRequest(ctx, owner, repo1, pullRequestId)
assert.Error(t, err)
}

func TestBitbucketServer_ListPullRequestComments(t *testing.T) {
ctx := context.Background()
response, err := os.ReadFile(filepath.Join("testdata", "bitbucketserver", "pull_request_comments_list_response.json"))
Expand Down
42 changes: 42 additions & 0 deletions vcsclient/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package vcsclient
import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/jfrog/gofrog/datastructures"
"io"
Expand Down Expand Up @@ -288,6 +289,47 @@ func (client *GitHubClient) ListOpenPullRequests(ctx context.Context, owner, rep
return mapGitHubPullRequestToPullRequestInfoList(pullRequests)
}

func (client *GitHubClient) GetPullRequest(ctx context.Context, owner, repository string, pullRequestId int) (PullRequestInfo, error) {
ghClient, err := client.buildGithubClient(ctx)
if err != nil {
return PullRequestInfo{}, err
}
client.logger.Debug(fetchingPullRequestById, repository)
pullRequest, _, err := ghClient.PullRequests.Get(ctx, owner, repository, pullRequestId)
EyalDelarea marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return PullRequestInfo{}, err
}

sourceBranch, err1 := extractBranchFromLabel(*pullRequest.Head.Label)
targetBranch, err2 := extractBranchFromLabel(*pullRequest.Base.Label)
err = errors.Join(err1, err2)
if err != nil {
return PullRequestInfo{}, err
}

prInfo := PullRequestInfo{
ID: int64(pullRequestId),
Source: BranchInfo{
Name: sourceBranch,
Repository: *pullRequest.Head.Repo.Name,
},
Target: BranchInfo{
Name: targetBranch,
Repository: *pullRequest.Base.Repo.Name,
},
}
return prInfo, nil
}

// Extracts branch name from the following expected label format repo:branch
func extractBranchFromLabel(label string) (string, error) {
split := strings.Split(label, ":")
if len(split) <= 1 {
return "", fmt.Errorf("bad label format %s", label)
}
return split[1], nil
}

// AddPullRequestComment on GitHub
func (client *GitHubClient) AddPullRequestComment(ctx context.Context, owner, repository, content string, pullRequestID int) error {
err := validateParametersNotBlank(map[string]string{"owner": owner, "repository": repository, "content": content})
Expand Down
41 changes: 41 additions & 0 deletions vcsclient/github_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,47 @@ func TestGitHubClient_ListOpenPullRequests(t *testing.T) {
assert.Error(t, err)
}

func TestGitHubClient_GetPullRequest(t *testing.T) {
ctx := context.Background()
pullRequestId := 1
repoName := "Hello-World"

// Successful response
response, err := os.ReadFile(filepath.Join("testdata", "github", "pull_request_info_response.json"))
assert.NoError(t, err)
client, cleanUp := createServerAndClient(t, vcsutils.GitHub, false, response,
fmt.Sprintf("/repos/%s/%s/pulls/%d", owner, repoName, pullRequestId), createGitHubHandler)
defer cleanUp()
result, err := client.GetPullRequest(ctx, owner, repoName, pullRequestId)
assert.NoError(t, err)
assert.True(t, reflect.DeepEqual(PullRequestInfo{
ID: int64(pullRequestId),
Source: BranchInfo{Name: "new-topic", Repository: "Hello-World"},
Target: BranchInfo{Name: "master", Repository: "Hello-World"},
}, result))

// Bad Labels
badLabels, err := os.ReadFile(filepath.Join("testdata", "github", "pull_request_info_response_bad_labels.json"))
assert.NoError(t, err)
badLabelsClient, badLabelClientCleanUp := createServerAndClient(t, vcsutils.GitHub, false, badLabels,
fmt.Sprintf("/repos/%s/%s/pulls/%d", owner, repoName, pullRequestId), createGitHubHandler)
defer badLabelClientCleanUp()
_, err = badLabelsClient.GetPullRequest(ctx, owner, repoName, pullRequestId)
assert.Error(t, err)

// Bad client
_, err = createBadGitHubClient(t).GetPullRequest(ctx, owner, repoName, pullRequestId)
assert.Error(t, err)

// Bad Response
badResponseClient, badResponseCleanUp := createServerAndClient(t, vcsutils.GitHub, false, "{",
fmt.Sprintf("/repos/%s/%s/pulls/%d", owner, repoName, pullRequestId), createGitHubHandler)
defer badResponseCleanUp()
_, err = badResponseClient.GetPullRequest(ctx, owner, repoName, pullRequestId)
assert.Error(t, err)

}

func TestGitHubClient_ListPullRequestComments(t *testing.T) {
ctx := context.Background()
response, err := os.ReadFile(filepath.Join("testdata", "github", "pull_request_comments_list_response.json"))
Expand Down
Loading