Skip to content

Commit 2432deb

Browse files
Add a function to get a commit information from its SHA (#11)
1 parent a93df4c commit 2432deb

15 files changed

+680
-55
lines changed

README.md

+21-4
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ Currently supported providers are: [GitHub](#github), [Bitbucket Server](#bitbuc
2424
- [Delete Webhook](#delete-webhook)
2525
- [Set Commit Status](#set-commit-status)
2626
- [Create Pull Request](#create-pull-request)
27-
- [Latest Commit Hash](#get-latest-commit-hash)
27+
- [Get Latest Commit](#get-latest-commit)
28+
- [Get Commit By SHA](#get-commit-by-sha)
2829
- [Add Public SSH Key](#add-public-ssh-key)
2930
- [Get Repository Info](#get-repository-info)
3031
- [Webhook Parser](#webhook-parser)
@@ -251,7 +252,7 @@ description := "Pull request description"
251252
err := client.CreatePullRequest(ctx, owner, repository, sourceBranch, targetBranch, title, description string)
252253
```
253254

254-
#### Get Latest Commit Hash
255+
#### Get Latest Commit
255256

256257
```go
257258
// Go context
@@ -263,8 +264,24 @@ repository := "jfrog-cli"
263264
// VCS branch
264265
branch := "dev"
265266

266-
// SHA-1 hash of the latest commit
267-
commitHash, err := client.GetLatestCommitHash(ctx, owner, repository, branch)
267+
// Commit information of the latest commit
268+
commitInfo, err := client.GetLatestCommit(ctx, owner, repository, branch)
269+
```
270+
271+
#### Get Commit By SHA
272+
273+
```go
274+
// Go context
275+
ctx := context.Background()
276+
// Organization or username
277+
owner := "jfrog"
278+
// VCS repository
279+
repository := "jfrog-cli"
280+
// SHA-1 hash of the commit
281+
sha := "abcdef0123abcdef4567abcdef8987abcdef6543"
282+
283+
// Commit information of requested commit
284+
commitInfo, err := client.GetCommitBySha(ctx, owner, repository, sha)
268285
```
269286

270287
#### Add Public SSH Key

vcsclient/bitbucketcloud.go

+57-13
Original file line numberDiff line numberDiff line change
@@ -274,19 +274,7 @@ func (client *BitbucketCloudClient) GetLatestCommit(ctx context.Context, owner,
274274
}
275275
if len(parsedCommits.Values) > 0 {
276276
latestCommit := parsedCommits.Values[0]
277-
parents := make([]string, len(latestCommit.Parents))
278-
for i, p := range latestCommit.Parents {
279-
parents[i] = p.Hash
280-
}
281-
return CommitInfo{
282-
Hash: latestCommit.Hash,
283-
AuthorName: latestCommit.Author.User.DisplayName,
284-
CommitterName: "", // not provided
285-
Url: latestCommit.Links.Self.Href,
286-
Timestamp: latestCommit.Date.UTC().Unix(),
287-
Message: latestCommit.Message,
288-
ParentHashes: parents,
289-
}, nil
277+
return mapBitbucketCloudCommitToCommitInfo(latestCommit), nil
290278
}
291279
return CommitInfo{}, nil
292280
}
@@ -327,6 +315,33 @@ func (client *BitbucketCloudClient) GetRepositoryInfo(ctx context.Context, owner
327315
return RepositoryInfo{CloneInfo: info}, nil
328316
}
329317

318+
func (client *BitbucketCloudClient) GetCommitBySha(ctx context.Context, owner, repository, sha string) (CommitInfo, error) {
319+
err := validateParametersNotBlank(map[string]string{
320+
"owner": owner,
321+
"repository": repository,
322+
"sha": sha,
323+
})
324+
if err != nil {
325+
return CommitInfo{}, err
326+
}
327+
328+
bitbucketClient := client.buildBitbucketCloudClient(ctx)
329+
options := &bitbucket.CommitsOptions{
330+
Owner: owner,
331+
RepoSlug: repository,
332+
Revision: sha,
333+
}
334+
commit, err := bitbucketClient.Repositories.Commits.GetCommit(options)
335+
if err != nil {
336+
return CommitInfo{}, err
337+
}
338+
parsedCommit, err := extractCommitDetailsFromResponse(commit)
339+
if err != nil {
340+
return CommitInfo{}, err
341+
}
342+
return mapBitbucketCloudCommitToCommitInfo(parsedCommit), nil
343+
}
344+
330345
func extractCommitFromResponse(commits interface{}) (*commitResponse, error) {
331346
var res commitResponse
332347
b, err := json.Marshal(commits)
@@ -340,6 +355,19 @@ func extractCommitFromResponse(commits interface{}) (*commitResponse, error) {
340355
return &res, nil
341356
}
342357

358+
func extractCommitDetailsFromResponse(commit interface{}) (commitDetails, error) {
359+
var res commitDetails
360+
b, err := json.Marshal(commit)
361+
if err != nil {
362+
return commitDetails{}, err
363+
}
364+
err = json.Unmarshal(b, &res)
365+
if err != nil {
366+
return commitDetails{}, err
367+
}
368+
return res, nil
369+
}
370+
343371
type commitResponse struct {
344372
Values []commitDetails `json:"values"`
345373
}
@@ -412,3 +440,19 @@ func getDownloadLink(repo *bitbucket.Repository, branch string) (string, error)
412440
}
413441
return htmlLink + "/get/" + branch + ".tar.gz", err
414442
}
443+
444+
func mapBitbucketCloudCommitToCommitInfo(parsedCommit commitDetails) CommitInfo {
445+
parents := make([]string, len(parsedCommit.Parents))
446+
for i, p := range parsedCommit.Parents {
447+
parents[i] = p.Hash
448+
}
449+
return CommitInfo{
450+
Hash: parsedCommit.Hash,
451+
AuthorName: parsedCommit.Author.User.DisplayName,
452+
CommitterName: "", // not provided
453+
Url: parsedCommit.Links.Self.Href,
454+
Timestamp: parsedCommit.Date.UTC().Unix(),
455+
Message: parsedCommit.Message,
456+
ParentHashes: parents,
457+
}
458+
}

vcsclient/bitbucketcloud_test.go

+40
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,46 @@ func TestBitbucketCloud_AddSshKeyToRepositoryNotFound(t *testing.T) {
232232
require.EqualError(t, err, "404 Not Found")
233233
}
234234

235+
func TestBitbucketCloud_GetCommitBySha(t *testing.T) {
236+
ctx := context.Background()
237+
sha := "f62ea5359e7af59880b4a5e23e0ce6c1b32b5d3c"
238+
response, err := os.ReadFile(filepath.Join("testdata", "bitbucketcloud", "commit_single_response.json"))
239+
assert.NoError(t, err)
240+
241+
client, cleanUp := createServerAndClient(t, vcsutils.BitbucketCloud, true, response,
242+
fmt.Sprintf("/repositories/%s/%s/commit/%s", owner, repo1, sha), createBitbucketCloudHandler)
243+
defer cleanUp()
244+
245+
result, err := client.GetCommitBySha(ctx, owner, repo1, sha)
246+
247+
require.NoError(t, err)
248+
assert.Equal(t, CommitInfo{
249+
Hash: sha,
250+
AuthorName: "user",
251+
CommitterName: "",
252+
Url: "https://api.bitbucket.org/2.0/repositories/user2/setup-jfrog-cli/commit/f62ea5359e7af59880b4a5e23e0ce6c1b32b5d3c",
253+
Timestamp: 1591030449,
254+
Message: "Update image name\n",
255+
ParentHashes: []string{"f62ea5359e7af59880b4a5e23e0ce6c1b32b5d3c"},
256+
}, result)
257+
}
258+
259+
func TestBitbucketCloud_GetCommitByShaNotFound(t *testing.T) {
260+
ctx := context.Background()
261+
sha := "062ea5359e7af59880b4a5e23e0ce6c1b32b5d3c"
262+
response := []byte(`<!DOCTYPE html><html lang="en"></html>`)
263+
264+
client, cleanUp := createServerAndClientReturningStatus(t, vcsutils.BitbucketCloud, true, response,
265+
fmt.Sprintf("/repositories/%s/%s/commit/%s", owner, repo1, sha),
266+
http.StatusNotFound,
267+
createBitbucketCloudHandler)
268+
defer cleanUp()
269+
270+
result, err := client.GetCommitBySha(ctx, owner, repo1, sha)
271+
require.EqualError(t, err, "404 Not Found")
272+
assert.Empty(t, result)
273+
}
274+
235275
func createBitbucketCloudWithBodyHandler(t *testing.T, expectedUri string, response []byte, expectedRequestBody []byte,
236276
expectedStatusCode int, expectedHttpMethod string) http.HandlerFunc {
237277
return func(writer http.ResponseWriter, request *http.Request) {

vcsclient/bitbucketserver.go

+44-13
Original file line numberDiff line numberDiff line change
@@ -309,19 +309,7 @@ func (client *BitbucketServerClient) GetLatestCommit(ctx context.Context, owner,
309309
}
310310
if len(commits) > 0 {
311311
latestCommit := commits[0]
312-
parents := make([]string, len(latestCommit.Parents))
313-
for i, p := range latestCommit.Parents {
314-
parents[i] = p.ID
315-
}
316-
return CommitInfo{
317-
Hash: latestCommit.ID,
318-
AuthorName: latestCommit.Author.Name,
319-
CommitterName: latestCommit.Committer.Name,
320-
Url: "", // URL not provided
321-
Timestamp: latestCommit.CommitterTimestamp,
322-
Message: latestCommit.Message,
323-
ParentHashes: parents,
324-
}, nil
312+
return mapBitbucketServerCommitToCommitInfo(latestCommit), nil
325313
}
326314
return CommitInfo{}, nil
327315
}
@@ -367,6 +355,33 @@ func (client *BitbucketServerClient) GetRepositoryInfo(ctx context.Context, owne
367355
return RepositoryInfo{CloneInfo: info}, nil
368356
}
369357

358+
func (client BitbucketServerClient) GetCommitBySha(ctx context.Context, owner, repository, sha string) (CommitInfo, error) {
359+
err := validateParametersNotBlank(map[string]string{
360+
"owner": owner,
361+
"repository": repository,
362+
"sha": sha,
363+
})
364+
if err != nil {
365+
return CommitInfo{}, err
366+
}
367+
368+
bitbucketClient, err := client.buildBitbucketClient(ctx)
369+
if err != nil {
370+
return CommitInfo{}, err
371+
}
372+
373+
apiResponse, err := bitbucketClient.GetCommit(owner, repository, sha, nil)
374+
if err != nil {
375+
return CommitInfo{}, err
376+
}
377+
commit := bitbucketv1.Commit{}
378+
err = unmarshalApiResponseValues(apiResponse, &commit)
379+
if err != nil {
380+
return CommitInfo{}, err
381+
}
382+
return mapBitbucketServerCommitToCommitInfo(commit), nil
383+
}
384+
370385
// Get all projects for which the authenticated user has the PROJECT_VIEW permission
371386
func (client *BitbucketServerClient) listProjects(bitbucketClient *bitbucketv1.DefaultApiService) ([]string, error) {
372387
var apiResponse *bitbucketv1.APIResponse
@@ -439,3 +454,19 @@ func getBitbucketServerWebhookEvents(webhookEvents ...vcsutils.WebhookEvent) []s
439454
}
440455
return events
441456
}
457+
458+
func mapBitbucketServerCommitToCommitInfo(commit bitbucketv1.Commit) CommitInfo {
459+
parents := make([]string, len(commit.Parents))
460+
for i, p := range commit.Parents {
461+
parents[i] = p.ID
462+
}
463+
return CommitInfo{
464+
Hash: commit.ID,
465+
AuthorName: commit.Author.Name,
466+
CommitterName: commit.Committer.Name,
467+
Url: "", // URL not provided
468+
Timestamp: commit.CommitterTimestamp,
469+
Message: commit.Message,
470+
ParentHashes: parents,
471+
}
472+
}

vcsclient/bitbucketserver_test.go

+49
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,55 @@ func TestBitbucketServer_GetRepositoryInfo(t *testing.T) {
293293
})
294294
}
295295

296+
func TestBitbucketServer_GetCommitBySha(t *testing.T) {
297+
ctx := context.Background()
298+
sha := "abcdef0123abcdef4567abcdef8987abcdef6543"
299+
response, err := os.ReadFile(filepath.Join("testdata", "bitbucketserver", "commit_single_response.json"))
300+
assert.NoError(t, err)
301+
302+
client, cleanUp := createServerAndClient(t, vcsutils.BitbucketServer, false, response,
303+
fmt.Sprintf("/api/1.0/projects/%s/repos/%s/commits/%s", owner, repo1, sha),
304+
createBitbucketServerHandler)
305+
defer cleanUp()
306+
307+
result, err := client.GetCommitBySha(ctx, owner, repo1, sha)
308+
309+
require.NoError(t, err)
310+
assert.Equal(t, CommitInfo{
311+
Hash: sha,
312+
AuthorName: "charlie",
313+
CommitterName: "mark",
314+
Url: "",
315+
Timestamp: 1636089306104,
316+
Message: "WIP on feature 1",
317+
ParentHashes: []string{"bbcdef0123abcdef4567abcdef8987abcdef6543"},
318+
}, result)
319+
}
320+
321+
func TestBitbucketServer_GetCommitByShaNotFound(t *testing.T) {
322+
ctx := context.Background()
323+
sha := "bbcdef0123abcdef4567abcdef8987abcdef6543"
324+
response := []byte(`{
325+
"errors": [
326+
{
327+
"context": null,
328+
"exceptionName": "com.atlassian.bitbucket.project.NoSuchProjectException",
329+
"message": "Project unknown does not exist."
330+
}
331+
]
332+
}`)
333+
client, cleanUp := createServerAndClientReturningStatus(t, vcsutils.BitbucketServer, false, response,
334+
fmt.Sprintf("/api/1.0/projects/%s/repos/%s/commits/%s", owner, repo1, sha),
335+
http.StatusNotFound, createBitbucketServerHandler)
336+
defer cleanUp()
337+
338+
result, err := client.GetCommitBySha(ctx, owner, repo1, sha)
339+
340+
require.Error(t, err)
341+
assert.Contains(t, err.Error(), "Status: 404 Not Found")
342+
assert.Empty(t, result)
343+
}
344+
296345
func createBitbucketServerHandler(t *testing.T, expectedUri string, response []byte, expectedStatusCode int) http.HandlerFunc {
297346
return func(w http.ResponseWriter, r *http.Request) {
298347
w.WriteHeader(expectedStatusCode)

vcsclient/github.go

+41-14
Original file line numberDiff line numberDiff line change
@@ -240,20 +240,7 @@ func (client *GitHubClient) GetLatestCommit(ctx context.Context, owner, reposito
240240
}
241241
if len(commits) > 0 {
242242
latestCommit := commits[0]
243-
parents := make([]string, len(latestCommit.Parents))
244-
for i, c := range latestCommit.Parents {
245-
parents[i] = c.GetSHA()
246-
}
247-
details := latestCommit.GetCommit()
248-
return CommitInfo{
249-
Hash: latestCommit.GetSHA(),
250-
AuthorName: details.GetAuthor().GetName(),
251-
CommitterName: details.GetCommitter().GetName(),
252-
Url: latestCommit.GetURL(),
253-
Timestamp: details.GetCommitter().GetDate().UTC().Unix(),
254-
Message: details.GetMessage(),
255-
ParentHashes: parents,
256-
}, nil
243+
return mapGitHubCommitToCommitInfo(latestCommit), nil
257244
}
258245
return CommitInfo{}, nil
259246
}
@@ -276,6 +263,29 @@ func (client *GitHubClient) GetRepositoryInfo(ctx context.Context, owner, reposi
276263
return RepositoryInfo{CloneInfo: CloneInfo{HTTP: repo.GetCloneURL(), SSH: repo.GetSSHURL()}}, nil
277264
}
278265

266+
func (client *GitHubClient) GetCommitBySha(ctx context.Context, owner, repository, sha string) (CommitInfo, error) {
267+
err := validateParametersNotBlank(map[string]string{
268+
"owner": owner,
269+
"repository": repository,
270+
"sha": sha,
271+
})
272+
if err != nil {
273+
return CommitInfo{}, err
274+
}
275+
276+
ghClient, err := client.buildGithubClient(ctx)
277+
if err != nil {
278+
return CommitInfo{}, err
279+
}
280+
281+
commit, _, err := ghClient.Repositories.GetCommit(ctx, owner, repository, sha, nil)
282+
if err != nil {
283+
return CommitInfo{}, err
284+
}
285+
286+
return mapGitHubCommitToCommitInfo(commit), nil
287+
}
288+
279289
func createGitHubHook(token, payloadUrl string, webhookEvents ...vcsutils.WebhookEvent) *github.Hook {
280290
return &github.Hook{
281291
Events: getGitHubWebhookEvents(webhookEvents...),
@@ -314,3 +324,20 @@ func getGitHubCommitState(commitState CommitStatus) string {
314324
}
315325
return ""
316326
}
327+
328+
func mapGitHubCommitToCommitInfo(commit *github.RepositoryCommit) CommitInfo {
329+
parents := make([]string, len(commit.Parents))
330+
for i, c := range commit.Parents {
331+
parents[i] = c.GetSHA()
332+
}
333+
details := commit.GetCommit()
334+
return CommitInfo{
335+
Hash: commit.GetSHA(),
336+
AuthorName: details.GetAuthor().GetName(),
337+
CommitterName: details.GetCommitter().GetName(),
338+
Url: commit.GetURL(),
339+
Timestamp: details.GetCommitter().GetDate().UTC().Unix(),
340+
Message: details.GetMessage(),
341+
ParentHashes: parents,
342+
}
343+
}

0 commit comments

Comments
 (0)