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 get commit status #75

Merged
merged 26 commits into from
Mar 27, 2023
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
331c083
Add new interface method and GitHub implementation
EyalDelarea Feb 28, 2023
62324e3
Gitlab implementations
EyalDelarea Mar 1, 2023
8c3cf38
Azure repos implementations
EyalDelarea Mar 2, 2023
5865687
Bitbucket server implementations
EyalDelarea Mar 5, 2023
9535a53
initial bitbucketcloud.go implementation need to fix
EyalDelarea Mar 6, 2023
9746144
Merge branch 'master' of https://github.com/jfrog/froggit-go into imp…
EyalDelarea Mar 6, 2023
1b00d2d
remove hard coded name
EyalDelarea Mar 6, 2023
dd6c0e0
Implement bitbucketcloud
EyalDelarea Mar 6, 2023
b56fdd6
Merge branch 'master' of https://github.com/jfrog/froggit-go into imp…
EyalDelarea Mar 16, 2023
76f2453
handle errors
EyalDelarea Mar 16, 2023
fc8f240
handle errors
EyalDelarea Mar 16, 2023
860fcbb
Merge branch 'implement_get_commit_status' of https://github.com/Eyal…
EyalDelarea Mar 16, 2023
fbcc34f
refactor
EyalDelarea Mar 16, 2023
6bdd81b
Add dummy responses to all VCS providers
EyalDelarea Mar 19, 2023
bdbf594
Add mock tests and add map function for states
EyalDelarea Mar 19, 2023
6a91300
fix unused vars
EyalDelarea Mar 19, 2023
aaf86dc
fix code test coverage
EyalDelarea Mar 19, 2023
a58b9ea
add test coverage #@2
EyalDelarea Mar 19, 2023
8c47740
add lastUpdate time to commit status will fall back to creation time …
EyalDelarea Mar 23, 2023
8d685f2
CR notes
EyalDelarea Mar 23, 2023
80110c5
Merge branch 'master' of https://github.com/jfrog/froggit-go into imp…
EyalDelarea Mar 23, 2023
495ecd3
Add README.md
EyalDelarea Mar 23, 2023
9c2e81b
refactor tests
EyalDelarea Mar 23, 2023
390acdc
add creation time to CommitStatusInfo and remove fallback to be more …
EyalDelarea Mar 23, 2023
edad2af
Refactor CR notes.
EyalDelarea Mar 26, 2023
095fcd5
Refactor CR notes.
EyalDelarea Mar 26, 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
72 changes: 63 additions & 9 deletions vcsclient/azurerepos.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,16 @@ import (
"context"
"errors"
"fmt"
"github.com/jfrog/froggit-go/vcsutils"
"github.com/jfrog/gofrog/datastructures"
"github.com/microsoft/azure-devops-go-api/azuredevops"
"github.com/microsoft/azure-devops-go-api/azuredevops/git"
"github.com/mitchellh/mapstructure"
"io"
"net/http"
"os"
"sort"
"strings"

"github.com/jfrog/gofrog/datastructures"
"github.com/microsoft/azure-devops-go-api/azuredevops"
"github.com/microsoft/azure-devops-go-api/azuredevops/git"
"github.com/mitchellh/mapstructure"

"github.com/jfrog/froggit-go/vcsutils"
)

// Azure Devops API version 6
Expand All @@ -25,6 +23,32 @@ type AzureReposClient struct {
logger Log
}

func (client *AzureReposClient) GetCommitStatus(ctx context.Context, owner, repository, ref string) (status []CommitStatus, err error) {
Copy link
Member

Choose a reason for hiding this comment

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

Let's put this method below SetCommitStatus

azureReposGitClient, err := client.buildAzureReposClient(ctx)
if err != nil {
return nil, err
}
commitStatusArgs := git.GetStatusesArgs{
CommitId: &ref,
RepositoryId: &repository,
Project: &repository,
}
resGitStatus, err := azureReposGitClient.GetStatuses(ctx, commitStatusArgs)
if err != nil {
return nil, err
}
results := make([]CommitStatus, 0)
for _, singleStatus := range *resGitStatus {
results = append(results, CommitStatus{
CommitStatusAsStringToStatus(string(*singleStatus.State)),
*singleStatus.Description,
*singleStatus.TargetUrl,
*singleStatus.CreatedBy.DisplayName,
})
}
return results, err
}

// NewAzureReposClient create a new AzureReposClient
func NewAzureReposClient(vcsInfo VcsInfo, logger Log) (*AzureReposClient, error) {
client := &AzureReposClient{vcsInfo: vcsInfo, logger: logger}
Expand Down Expand Up @@ -358,9 +382,39 @@ func (client *AzureReposClient) DeleteWebhook(ctx context.Context, owner, reposi
return getUnsupportedInAzureError("delete webhook")
}

func CommitStatusToStringStatus(state CommitStatusState) string {
EyalDelarea marked this conversation as resolved.
Show resolved Hide resolved
conversionMap := map[CommitStatusState]string{
0: "success",
1: "fail",
2: "error",
3: "pending",
}
return conversionMap[state]
EyalDelarea marked this conversation as resolved.
Show resolved Hide resolved
}

// SetCommitStatus on Azure Repos
func (client *AzureReposClient) SetCommitStatus(ctx context.Context, commitStatus CommitStatus, owner, repository, ref, title, description, detailsURL string) error {
return getUnsupportedInAzureError("set commit status")
func (client *AzureReposClient) SetCommitStatus(ctx context.Context, commitStatus CommitStatusState, owner, repository, ref, title, description, detailsURL string) error {
azureReposGitClient, err := client.buildAzureReposClient(ctx)
if err != nil {
return err
}
statusState := git.GitStatusState(CommitStatusToStringStatus(commitStatus))
commitStatusArgs := git.CreateCommitStatusArgs{
GitCommitStatusToCreate: &git.GitStatus{
Description: &description,
State: &statusState,
TargetUrl: &detailsURL,
Context: &git.GitStatusContext{
Name: &owner,
Genre: &title,
},
},
CommitId: &ref,
RepositoryId: &repository,
Project: &repository,
}
_, err = azureReposGitClient.CreateCommitStatus(ctx, commitStatusArgs)
return err
}

// DownloadFileFromRepo on Azure Repos
Expand Down
35 changes: 32 additions & 3 deletions vcsclient/azurerepos_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -352,10 +352,12 @@ func TestAzureReposClient_DeleteWebhook(t *testing.T) {

func TestAzureReposClient_SetCommitStatus(t *testing.T) {
ctx := context.Background()
client, cleanUp := createServerAndClient(t, vcsutils.AzureRepos, true, "", "unsupportedTest", createAzureReposHandler)
commitHash := "86d6919952702f9ab03bc95b45687f145a663de0"
expectedUri := "/_apis/ResourceAreas/commitStatus"
client, cleanUp := createServerAndClient(t, vcsutils.AzureRepos, true, nil, expectedUri, createAzureReposHandler)
defer cleanUp()
err := client.SetCommitStatus(ctx, 1, owner, repo1, "", "", "", "")
assert.Error(t, err)
err := client.SetCommitStatus(ctx, 1, owner, repo1, commitHash, "", "", "")
assert.NoError(t, err)
yahavi marked this conversation as resolved.
Show resolved Hide resolved
}

func TestAzureReposClient_GetLabel(t *testing.T) {
Expand Down Expand Up @@ -484,3 +486,30 @@ func createBadAzureReposClient(t *testing.T, response []byte) (VcsClient, func()
createAzureReposHandler)
return client, cleanUp
}

func TestAzureReposClient_GetCommitStatus(t *testing.T) {
Copy link
Member

Choose a reason for hiding this comment

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

Let's put this method inline with the other tests (above the private methods)

ctx := context.Background()

t.Run("full response", func(t *testing.T) {
commitHash := "86d6919952702f9ab03bc95b45687f145a663de0"
expectedUri := "/_apis/ResourceAreas/commitStatus"
response, err := os.ReadFile(filepath.Join("testdata", "azurerepos", "commits_statuses.json"))
assert.NoError(t, err)
client, cleanUp := createServerAndClient(t, vcsutils.AzureRepos, true, response, expectedUri, createAzureReposHandler)
defer cleanUp()
commitStatuses, err := client.GetCommitStatus(ctx, owner, repo1, commitHash)
assert.NoError(t, err)
assert.True(t, len(commitStatuses) == 3)
assert.True(t, commitStatuses[0].State == CommitStatusStateSuccess)
assert.True(t, commitStatuses[1].State == CommitStatusStatePending)
assert.True(t, commitStatuses[2].State == CommitStatusStateFailure)
})
t.Run("empty response", func(t *testing.T) {
commitHash := "86d6919952702f9ab03bc95b45687f145a663de0"
expectedUri := "/_apis/ResourceAreas/commitStatus"
client, cleanUp := createServerAndClient(t, vcsutils.AzureRepos, true, nil, expectedUri, createAzureReposHandler)
defer cleanUp()
_, err := client.GetCommitStatus(ctx, owner, repo1, commitHash)
assert.NoError(t, err)
})
Copy link
Member

Choose a reason for hiding this comment

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

Let's add a negative test:

	t.Run("erroneous client", func(t *testing.T) {
		badClient, badClientCleanup := createBadAzureReposClient(t, []byte{})
		defer badClientCleanup()
		_, err := badClient.GetCommitStatus(ctx, owner, repo1, "")
		assert.Error(t, err)
	})

}
39 changes: 38 additions & 1 deletion vcsclient/bitbucketcloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,43 @@ type BitbucketCloudClient struct {
logger Log
}

// GetCommitStatus for a specific branch, NOTE: currently does not support pagination !
Copy link
Member

Choose a reason for hiding this comment

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

Not only a branch but also a tag, commit hash, etc...
The full documentation is in the vcsclient.go.

Suggested change
// GetCommitStatus for a specific branch, NOTE: currently does not support pagination !
// GetCommitStatus on Bitbucket cloud

About the pagination comment - it looks like it is not supported also on GitHub, GitLab, and Bitbucket cloud (maybe in Azure too). Can we add this comment in the vcsclient.go and in the README?

func (client *BitbucketCloudClient) GetCommitStatus(ctx context.Context, owner, repository, ref string) (status []CommitStatus, err error) {
Copy link
Member

Choose a reason for hiding this comment

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

Let's put this method below SetCommitStatus

bitbucketClient := client.buildBitbucketCloudClient(ctx)
commitOptions := &bitbucket.CommitsOptions{
Owner: owner,
RepoSlug: repository,
Revision: ref,
}
results := make([]CommitStatus, 0)
rawStatuses, err := bitbucketClient.Repositories.Commits.GetCommitStatuses(commitOptions)
if err != nil {
return nil, err
}
statuses := struct {
Statuses []struct {
Title string `mapstructure:"key"`
Url string `mapstructure:"url"`
State string `mapstructure:"state"`
Description string `mapstructure:"description"`
Creator string `mapstructure:"name"`
} `mapstructure:"values"`
}{}
err = mapstructure.Decode(rawStatuses, &statuses)
if err != nil {
return nil, err
}
Copy link
Member

Choose a reason for hiding this comment

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

Optional, you like -

	if err = mapstructure.Decode(rawStatuses, &statuses); err != nil {
		return nil, err
	}

for _, commitStatus := range statuses.Statuses {
results = append(results, CommitStatus{
State: CommitStatusAsStringToStatus(commitStatus.State),
Description: commitStatus.Description,
DetailsUrl: commitStatus.Url,
Creator: commitStatus.Creator,
})
}
return results, err
}

// NewBitbucketCloudClient create a new BitbucketCloudClient
func NewBitbucketCloudClient(vcsInfo VcsInfo, logger Log) (*BitbucketCloudClient, error) {
bitbucketClient := &BitbucketCloudClient{
Expand Down Expand Up @@ -197,7 +234,7 @@ func (client *BitbucketCloudClient) DeleteWebhook(ctx context.Context, owner, re
}

// SetCommitStatus on Bitbucket cloud
func (client *BitbucketCloudClient) SetCommitStatus(ctx context.Context, commitStatus CommitStatus, owner, repository,
func (client *BitbucketCloudClient) SetCommitStatus(ctx context.Context, commitStatus CommitStatusState, owner, repository,
ref, title, description, detailsURL string) error {
bitbucketClient := client.buildBitbucketCloudClient(ctx)
commitOptions := &bitbucket.CommitsOptions{
Expand Down
23 changes: 23 additions & 0 deletions vcsclient/bitbucketcloud_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -508,3 +508,26 @@ func createBitbucketCloudHandler(t *testing.T, expectedURI string, response []by
assert.Equal(t, basicAuthHeader, r.Header.Get("Authorization"))
}
}

func TestBitbucketCloudClient_GetCommitStatus(t *testing.T) {
ctx := context.Background()
t.Run("empty response", func(t *testing.T) {
client, cleanUp := createServerAndClient(t, vcsutils.BitbucketCloud, true, nil, "/repositories/owner/repo/commit/ref/statuses", createBitbucketCloudHandler)
defer cleanUp()
_, err := client.GetCommitStatus(ctx, "owner", "repo", "ref")
assert.NoError(t, err)
})

t.Run("non empty response", func(t *testing.T) {
response, err := os.ReadFile(filepath.Join("testdata", "bitbucketcloud", "commits_statuses.json"))
assert.NoError(t, err)
client, cleanUp := createServerAndClient(t, vcsutils.BitbucketCloud, true, response, "/repositories/owner/repo/commit/ref/statuses", createBitbucketCloudHandler)
defer cleanUp()
commitStatuses, err := client.GetCommitStatus(ctx, "owner", "repo", "ref")
assert.NoError(t, err)
assert.True(t, len(commitStatuses) == 3)
assert.True(t, commitStatuses[0].State == CommitStatusStatePending)
assert.True(t, commitStatuses[1].State == CommitStatusStateSuccess)
assert.True(t, commitStatuses[2].State == CommitStatusStateFailure)
})
}
2 changes: 1 addition & 1 deletion vcsclient/bitbucketcommon.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ var errBitbucketCodeScanningNotSupported = errors.New("code scanning is not supp
var errBitbucketDownloadFileFromRepoNotSupported = errors.New("download file from repo is currently not supported on Bitbucket")
var errBitbucketGetRepoEnvironmentInfoNotSupported = errors.New("get repository environment info is currently not supported on Bitbucket")

func getBitbucketCommitState(commitState CommitStatus) string {
func getBitbucketCommitState(commitState CommitStatusState) string {
switch commitState {
case Pass:
return "SUCCESSFUL"
Expand Down
37 changes: 36 additions & 1 deletion vcsclient/bitbucketserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,41 @@ type BitbucketServerClient struct {
logger Log
}

EyalDelarea marked this conversation as resolved.
Show resolved Hide resolved
func (client *BitbucketServerClient) GetCommitStatus(ctx context.Context, owner, repository, ref string) (status []CommitStatus, err error) {
bitbucketClient, err := client.buildBitbucketClient(ctx)
if err != nil {
return nil, err
}
response, err := bitbucketClient.GetCommitStatus(ref)
if err != nil {
return nil, err
}
statuses := struct {
Statuses []struct {
Title string `mapstructure:"key"`
Url string `mapstructure:"url"`
State string `mapstructure:"state"`
Description string `mapstructure:"description"`
Creator string `mapstructure:"name"`
} `mapstructure:"values"`
}{}
err = mapstructure.Decode(response.Values, &statuses)
if err != nil {
return nil, err
}
results := make([]CommitStatus, 0)
for _, element := range statuses.Statuses {
results = append(results, CommitStatus{
State: CommitStatusAsStringToStatus(element.State),
Description: element.Description,
DetailsUrl: element.Url,
Creator: element.Creator,
})

}
return results, err
}

// NewBitbucketServerClient create a new BitbucketServerClient
func NewBitbucketServerClient(vcsInfo VcsInfo, logger Log) (*BitbucketServerClient, error) {
bitbucketServerClient := &BitbucketServerClient{
Expand Down Expand Up @@ -241,7 +276,7 @@ func (client *BitbucketServerClient) DeleteWebhook(ctx context.Context, owner, r
}

// SetCommitStatus on Bitbucket server
func (client *BitbucketServerClient) SetCommitStatus(ctx context.Context, commitStatus CommitStatus, _, _, ref, title,
func (client *BitbucketServerClient) SetCommitStatus(ctx context.Context, commitStatus CommitStatusState, _, _, ref, title,
description, detailsURL string) error {
bitbucketClient, err := client.buildBitbucketClient(ctx)
if err != nil {
Expand Down
52 changes: 52 additions & 0 deletions vcsclient/bitbucketserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -671,3 +671,55 @@ func createBadBitbucketServerClient(t *testing.T) VcsClient {
require.NoError(t, err)
return client
}

func TestBitbucketServer_TestGetCommitStatus(t *testing.T) {
ctx := context.Background()

t.Run("empty response", func(t *testing.T) {
ref := "9caf1c431fb783b669f0f909bd018b40f2ea3808"
client, cleanUp := createServerAndClient(t, vcsutils.BitbucketServer, false, nil,
fmt.Sprintf("/rest/build-status/1.0/commits/%s", ref), createBitbucketServerHandler)
defer cleanUp()
_, err := client.GetCommitStatus(ctx, owner, repo1, ref)
assert.NoError(t, err)
})

t.Run("full response", func(t *testing.T) {
ref := "9caf1c431fb783b669f0f909bd018b40f2ea3808"
response, err := os.ReadFile(filepath.Join("testdata", "bitbucketserver", "commits_statuses.json"))
assert.NoError(t, err)
client, cleanUp := createServerAndClient(t, vcsutils.BitbucketServer, false, response,
fmt.Sprintf("/rest/build-status/1.0/commits/%s", ref), createBitbucketServerHandler)
defer cleanUp()
commitStatuses, err := client.GetCommitStatus(ctx, owner, repo1, ref)
assert.NoError(t, err)
assert.True(t, len(commitStatuses) == 3)
assert.True(t, commitStatuses[0].State == CommitStatusStatePending)
assert.True(t, commitStatuses[1].State == CommitStatusStateSuccess)
assert.True(t, commitStatuses[2].State == CommitStatusStateFailure)
})

t.Run("failure tests", func(t *testing.T) {
ref := "9caf1c431fb783b669f0f909bd018b40f2ea3808"
response, err := os.ReadFile(filepath.Join("testdata", "github", "commits_statuses_bad_json.json"))
assert.NoError(t, err)
client, cleanUp := createServerAndClient(t, vcsutils.BitbucketServer, false, response,
fmt.Sprintf("/rest/build-status/1.0/commits/%s", ref), createBitbucketServerHandler)
defer cleanUp()
_, err = client.GetCommitStatus(ctx, owner, repo1, ref)
assert.Error(t, err)
_, err = createBadBitbucketServerClient(t).GetCommitStatus(ctx, owner, repo1, ref)
assert.Error(t, err)
})

t.Run("failure tests", func(t *testing.T) {
ref := "9caf1c431fb783b669f0f909bd018b40f2ea3808"
response, err := os.ReadFile(filepath.Join("testdata", "bitbucketserver", "commits_statuses_bad_decode.json"))
assert.NoError(t, err)
client, cleanUp := createServerAndClient(t, vcsutils.BitbucketServer, false, response,
fmt.Sprintf("/rest/build-status/1.0/commits/%s", ref), createBitbucketServerHandler)
defer cleanUp()
_, err = client.GetCommitStatus(ctx, owner, repo1, ref)
assert.Error(t, err)
})
}
26 changes: 24 additions & 2 deletions vcsclient/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,28 @@ type GitHubClient struct {
logger Log
}

// GetCommitStatus gets commit statuses
EyalDelarea marked this conversation as resolved.
Show resolved Hide resolved
func (client *GitHubClient) GetCommitStatus(ctx context.Context, owner, repository, ref string) (status []CommitStatus, err error) {
EyalDelarea marked this conversation as resolved.
Show resolved Hide resolved
ghClient, err := client.buildGithubClient(ctx)
if err != nil {
return nil, err
}
statuses, _, err := ghClient.Repositories.GetCombinedStatus(ctx, owner, repository, ref, nil)
if err != nil {
return nil, err
}
results := make([]CommitStatus, 0)
for _, singleStatus := range statuses.Statuses {
results = append(results, CommitStatus{
State: CommitStatusAsStringToStatus(*singleStatus.State),
Description: singleStatus.GetDescription(),
DetailsUrl: singleStatus.GetTargetURL(),
Creator: singleStatus.GetCreator().GetName(),
})
}
return results, err
}

// NewGitHubClient create a new GitHubClient
func NewGitHubClient(vcsInfo VcsInfo, logger Log) (*GitHubClient, error) {
return &GitHubClient{vcsInfo: vcsInfo, logger: logger}, nil
Expand Down Expand Up @@ -173,7 +195,7 @@ func (client *GitHubClient) DeleteWebhook(ctx context.Context, owner, repository
}

// SetCommitStatus on GitHub
func (client *GitHubClient) SetCommitStatus(ctx context.Context, commitStatus CommitStatus, owner, repository, ref,
func (client *GitHubClient) SetCommitStatus(ctx context.Context, commitStatus CommitStatusState, owner, repository, ref,
title, description, detailsURL string) error {
ghClient, err := client.buildGithubClient(ctx)
if err != nil {
Expand Down Expand Up @@ -659,7 +681,7 @@ func getGitHubRepositoryVisibility(repo *github.Repository) RepositoryVisibility
}
}

func getGitHubCommitState(commitState CommitStatus) string {
func getGitHubCommitState(commitState CommitStatusState) string {
switch commitState {
case Pass:
return "success"
Expand Down
Loading