-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
adds commits service to the stash client
CommitsService permits retrieving commits and listing them for a given repository. Signed-off-by: Soule BA <[email protected]>
- Loading branch information
Showing
3 changed files
with
274 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
/* | ||
Copyright 2021 The Flux authors | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package stash | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
"net/http" | ||
"net/url" | ||
) | ||
|
||
const ( | ||
commitsURI = "commits" | ||
) | ||
|
||
// Commits interface defines the methods that can be used to | ||
// retrieve commits of a repository. | ||
type Commits interface { | ||
List(ctx context.Context, projectKey, repositorySlug string, opts *PagingOptions) (*CommitList, error) | ||
Get(ctx context.Context, projectKey, repositorySlug, commitID string) (*CommitObject, error) | ||
} | ||
|
||
// CommitsService is a client for communicating with stash commits endpoint | ||
// bitbucket-server API docs: https://docs.atlassian.com/bitbucket-server/rest/5.16.0/bitbucket-rest.html | ||
type CommitsService service | ||
|
||
// CommitObject represents a commit in stash | ||
type CommitObject struct { | ||
// Session is the session object for the branch. | ||
Session `json:"sessionInfo,omitempty"` | ||
// Author is the author of the commit. | ||
Author User `json:"author,omitempty"` | ||
// AuthorTimestamp is the timestamp of the author of the commit. | ||
AuthorTimestamp int64 `json:"authorTimestamp,omitempty"` | ||
// Committer is the committer of the commit. | ||
Committer User `json:"committer,omitempty"` | ||
// CommitterTimestamp is the timestamp of the committer of the commit. | ||
CommitterTimestamp int64 `json:"committerTimestamp,omitempty"` | ||
// DisplayID is the display ID of the commit. | ||
DisplayID string `json:"displayId,omitempty"` | ||
// ID is the ID of the commit i.e the SHA1. | ||
ID string `json:"id,omitempty"` | ||
// Message is the message of the commit. | ||
Message string `json:"message,omitempty"` | ||
// Parents is the list of parents of the commit. | ||
Parents []*Parent `json:"parents,omitempty"` | ||
} | ||
|
||
// Parent represents a parent of a commit. | ||
type Parent struct { | ||
// DisplayID is the display ID of the commit. | ||
DisplayID string `json:"displayId,omitempty"` | ||
// ID is the ID of the commit i.e the SHA1. | ||
ID string `json:"id,omitempty"` | ||
} | ||
|
||
// CommitList represents a list of commits in stash | ||
type CommitList struct { | ||
// Paging is the paging information. | ||
Paging | ||
// Commits is the list of commits. | ||
Commits []*CommitObject `json:"values,omitempty"` | ||
} | ||
|
||
// GetCommits returns the list of commits | ||
func (c *CommitList) GetCommits() []*CommitObject { | ||
return c.Commits | ||
} | ||
|
||
// List returns the list of commits. | ||
// Paging is optional and is enabled by providing a PagingOptions struct. | ||
// A pointer to a CommitList struct is returned to retrieve the next page of results. | ||
// List uses the endpoint "GET /rest/api/1.0/projects/{projectKey}/repos/{repositorySlug}/commits". | ||
// https://docs.atlassian.com/bitbucket-server/rest/5.16.0/bitbucket-rest.html | ||
func (s *CommitsService) List(ctx context.Context, projectKey, repositorySlug string, opts *PagingOptions) (*CommitList, error) { | ||
query := addPaging(&url.Values{}, opts) | ||
req, err := s.Client.NewRequest(ctx, http.MethodGet, newURI(projectsURI, projectKey, RepositoriesURI, repositorySlug, commitsURI), *query, nil, nil) | ||
if err != nil { | ||
return nil, fmt.Errorf("list commits request creation failed: %w", err) | ||
} | ||
res, resp, err := s.Client.Do(req) | ||
if err != nil { | ||
return nil, fmt.Errorf("list commits failed: %w", err) | ||
} | ||
|
||
// As nothing is done with the response body, it is safe to close here | ||
// to avoid leaking connections | ||
defer resp.Body.Close() | ||
if resp != nil && resp.StatusCode == http.StatusNotFound { | ||
return nil, ErrNotFound | ||
} | ||
|
||
c := &CommitList{} | ||
if err := json.Unmarshal(res, c); err != nil { | ||
return nil, fmt.Errorf("list commits for repository failed, unable to unmarshall repository json: %w", err) | ||
} | ||
|
||
for _, commit := range c.GetCommits() { | ||
commit.Session.set(resp) | ||
} | ||
return c, nil | ||
} | ||
|
||
// Get retrieves a stash commit given it's ID i.e a SHA1. | ||
// Get uses the endpoint "GET /rest/api/1.0/projects/{projectKey}/repos/{repositorySlug}/commits/{commitID}". | ||
// https://docs.atlassian.com/bitbucket-server/rest/5.16.0/bitbucket-rest.html | ||
func (s *CommitsService) Get(ctx context.Context, projectKey, repositorySlug, commitID string) (*CommitObject, error) { | ||
req, err := s.Client.NewRequest(ctx, http.MethodGet, newURI(projectsURI, projectKey, RepositoriesURI, repositorySlug, commitsURI, commitID), nil, nil, nil) | ||
if err != nil { | ||
return nil, fmt.Errorf("get commit request creation failed: %w", err) | ||
} | ||
res, resp, err := s.Client.Do(req) | ||
if err != nil { | ||
return nil, fmt.Errorf("get commit failed: %w", err) | ||
} | ||
|
||
// As nothing is done with the response body, it is safe to close here | ||
// to avoid leaking connections | ||
defer resp.Body.Close() | ||
if resp != nil && resp.StatusCode == http.StatusNotFound { | ||
return nil, ErrNotFound | ||
} | ||
|
||
c := &CommitObject{} | ||
if err := json.Unmarshal(res, c); err != nil { | ||
return nil, fmt.Errorf("get commit failed, unable to unmarshall json: %w", err) | ||
} | ||
|
||
c.Session.set(resp) | ||
|
||
return c, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
/* | ||
Copyright 2021 The Flux authors | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package stash | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
"net/http" | ||
"path" | ||
"testing" | ||
|
||
"github.com/google/go-cmp/cmp" | ||
) | ||
|
||
func TestGetCommit(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
commitID string | ||
}{ | ||
{ | ||
name: "test a commit", | ||
commitID: "abcdef0123abcdef4567abcdef8987abcdef6543", | ||
}, | ||
{ | ||
name: "test commit does not exist", | ||
commitID: "*°0#13jbkjfbvsqbùbjùrdfbgzeo'àtu)éuçt&-y", | ||
}, | ||
} | ||
|
||
validCommitID := []string{"abcdef0123abcdef4567abcdef8987abcdef6543"} | ||
|
||
mux, client := setup(t) | ||
|
||
fmt.Println("commit") | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
p := fmt.Sprintf("%s/%s/prj1/%s/repo1/%s/%s", stashURIprefix, projectsURI, RepositoriesURI, commitsURI, tt.commitID) | ||
mux.HandleFunc(p, func(w http.ResponseWriter, r *http.Request) { | ||
for _, substr := range validCommitID { | ||
if path.Base(r.URL.String()) == substr { | ||
w.WriteHeader(http.StatusOK) | ||
c := &CommitObject{ | ||
ID: substr, | ||
DisplayID: substr[:10], | ||
} | ||
|
||
json.NewEncoder(w).Encode(c) | ||
return | ||
} | ||
} | ||
|
||
http.Error(w, "The specified commit does not exist", http.StatusNotFound) | ||
|
||
return | ||
|
||
}) | ||
|
||
ctx := context.Background() | ||
c, err := client.Commits.Get(ctx, "prj1", "repo1", tt.commitID) | ||
if err != nil { | ||
if err != ErrNotFound { | ||
t.Fatalf("Commits.Get returned error: %v", err) | ||
} | ||
return | ||
} | ||
|
||
if c.ID != tt.commitID { | ||
t.Fatalf("Commits.Get returned commit %s, want %s", c.ID, tt.commitID) | ||
} | ||
|
||
}) | ||
} | ||
} | ||
|
||
func TestListCommits(t *testing.T) { | ||
cIDs := []*CommitObject{ | ||
{ID: "abcdef0123abcdef4567abcdef8987abcdef6543"}, | ||
{ID: "aerfdef09893abcdef4567abcdef898abcdef652"}, | ||
{ID: "abcdef3456abcdef4567abcdef8987abcdef6657"}, | ||
{ID: "abcdef9876abcdef4567abcdef8987abcdef4357"}} | ||
|
||
mux, client := setup(t) | ||
|
||
path := fmt.Sprintf("%s/%s/prj1/%s/repo1/%s", stashURIprefix, projectsURI, RepositoriesURI, commitsURI) | ||
mux.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { | ||
w.WriteHeader(http.StatusOK) | ||
b := struct { | ||
Commits []*CommitObject `json:"values"` | ||
}{[]*CommitObject{ | ||
cIDs[0], | ||
cIDs[1], | ||
cIDs[2], | ||
cIDs[3], | ||
}} | ||
json.NewEncoder(w).Encode(b) | ||
return | ||
|
||
}) | ||
ctx := context.Background() | ||
list, err := client.Commits.List(ctx, "prj1", "repo1", nil) | ||
if err != nil { | ||
t.Fatalf("Commits.List returned error: %v", err) | ||
} | ||
|
||
if diff := cmp.Diff(cIDs, list.Commits); diff != "" { | ||
t.Errorf("Commits.List returned diff (want -> got):\n%s", diff) | ||
} | ||
|
||
} |