feat(repos): add repository deploy key endpoints
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
20e038265f
commit
1f6cfbfd8b
2 changed files with 195 additions and 0 deletions
78
repos.go
78
repos.go
|
|
@ -20,6 +20,26 @@ type RepoService struct {
|
|||
Resource[types.Repository, types.CreateRepoOption, types.EditRepoOption]
|
||||
}
|
||||
|
||||
// RepoKeyListOptions controls filtering for repository key listings.
|
||||
type RepoKeyListOptions struct {
|
||||
KeyID int64
|
||||
Fingerprint string
|
||||
}
|
||||
|
||||
func (o RepoKeyListOptions) queryParams() map[string]string {
|
||||
query := make(map[string]string, 2)
|
||||
if o.KeyID != 0 {
|
||||
query["key_id"] = strconv.FormatInt(o.KeyID, 10)
|
||||
}
|
||||
if o.Fingerprint != "" {
|
||||
query["fingerprint"] = o.Fingerprint
|
||||
}
|
||||
if len(query) == 0 {
|
||||
return nil
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
||||
func newRepoService(c *Client) *RepoService {
|
||||
return &RepoService{
|
||||
Resource: *NewResource[types.Repository, types.CreateRepoOption, types.EditRepoOption](
|
||||
|
|
@ -126,6 +146,44 @@ func (s *RepoService) DeleteTagProtection(ctx context.Context, owner, repo strin
|
|||
return s.client.Delete(ctx, path)
|
||||
}
|
||||
|
||||
// ListKeys returns all deploy keys for a repository.
|
||||
func (s *RepoService) ListKeys(ctx context.Context, owner, repo string, filters ...RepoKeyListOptions) ([]types.DeployKey, error) {
|
||||
path := ResolvePath("/api/v1/repos/{owner}/{repo}/keys", pathParams("owner", owner, "repo", repo))
|
||||
return ListAll[types.DeployKey](ctx, s.client, path, repoKeyQuery(filters...))
|
||||
}
|
||||
|
||||
// IterKeys returns an iterator over all deploy keys for a repository.
|
||||
func (s *RepoService) IterKeys(ctx context.Context, owner, repo string, filters ...RepoKeyListOptions) iter.Seq2[types.DeployKey, error] {
|
||||
path := ResolvePath("/api/v1/repos/{owner}/{repo}/keys", pathParams("owner", owner, "repo", repo))
|
||||
return ListIter[types.DeployKey](ctx, s.client, path, repoKeyQuery(filters...))
|
||||
}
|
||||
|
||||
// GetKey returns a single deploy key by ID.
|
||||
func (s *RepoService) GetKey(ctx context.Context, owner, repo string, id int64) (*types.DeployKey, error) {
|
||||
path := ResolvePath("/api/v1/repos/{owner}/{repo}/keys/{id}", pathParams("owner", owner, "repo", repo, "id", int64String(id)))
|
||||
var out types.DeployKey
|
||||
if err := s.client.Get(ctx, path, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
// CreateKey adds a deploy key to a repository.
|
||||
func (s *RepoService) CreateKey(ctx context.Context, owner, repo string, opts *types.CreateKeyOption) (*types.DeployKey, error) {
|
||||
path := ResolvePath("/api/v1/repos/{owner}/{repo}/keys", pathParams("owner", owner, "repo", repo))
|
||||
var out types.DeployKey
|
||||
if err := s.client.Post(ctx, path, opts, &out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
// DeleteKey removes a deploy key from a repository by ID.
|
||||
func (s *RepoService) DeleteKey(ctx context.Context, owner, repo string, id int64) error {
|
||||
path := ResolvePath("/api/v1/repos/{owner}/{repo}/keys/{id}", pathParams("owner", owner, "repo", repo, "id", int64String(id)))
|
||||
return s.client.Delete(ctx, path)
|
||||
}
|
||||
|
||||
// ListStargazers returns all users who starred a repository.
|
||||
func (s *RepoService) ListStargazers(ctx context.Context, owner, repo string) ([]types.User, error) {
|
||||
path := ResolvePath("/api/v1/repos/{owner}/{repo}/stargazers", pathParams("owner", owner, "repo", repo))
|
||||
|
|
@ -589,3 +647,23 @@ func (s *RepoService) SyncPushMirrors(ctx context.Context, owner, repo string) e
|
|||
path := ResolvePath("/api/v1/repos/{owner}/{repo}/push_mirrors-sync", pathParams("owner", owner, "repo", repo))
|
||||
return s.client.Post(ctx, path, nil, nil)
|
||||
}
|
||||
|
||||
func repoKeyQuery(filters ...RepoKeyListOptions) map[string]string {
|
||||
if len(filters) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
query := make(map[string]string, 2)
|
||||
for _, filter := range filters {
|
||||
if filter.KeyID != 0 {
|
||||
query["key_id"] = strconv.FormatInt(filter.KeyID, 10)
|
||||
}
|
||||
if filter.Fingerprint != "" {
|
||||
query["fingerprint"] = filter.Fingerprint
|
||||
}
|
||||
}
|
||||
if len(query) == 0 {
|
||||
return nil
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
|
|
|||
117
repos_test.go
117
repos_test.go
|
|
@ -628,6 +628,123 @@ func TestRepoService_DeleteTagProtection_Good(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestRepoService_ListKeysWithFilters_Good(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
t.Errorf("expected GET, got %s", r.Method)
|
||||
}
|
||||
if r.URL.Path != "/api/v1/repos/core/go-forge/keys" {
|
||||
t.Errorf("wrong path: %s", r.URL.Path)
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
if got := r.URL.Query().Get("key_id"); got != "7" {
|
||||
t.Errorf("got key_id=%q, want %q", got, "7")
|
||||
}
|
||||
if got := r.URL.Query().Get("fingerprint"); got != "aa:bb:cc" {
|
||||
t.Errorf("got fingerprint=%q, want %q", got, "aa:bb:cc")
|
||||
}
|
||||
if got := r.URL.Query().Get("page"); got != "1" {
|
||||
t.Errorf("got page=%q, want %q", got, "1")
|
||||
}
|
||||
if got := r.URL.Query().Get("limit"); got != "50" {
|
||||
t.Errorf("got limit=%q, want %q", got, "50")
|
||||
}
|
||||
w.Header().Set("X-Total-Count", "1")
|
||||
json.NewEncoder(w).Encode([]types.DeployKey{{ID: 7, Title: "deploy"}})
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
f := NewForge(srv.URL, "tok")
|
||||
keys, err := f.Repos.ListKeys(context.Background(), "core", "go-forge", RepoKeyListOptions{
|
||||
KeyID: 7,
|
||||
Fingerprint: "aa:bb:cc",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(keys) != 1 {
|
||||
t.Fatalf("got %d keys, want 1", len(keys))
|
||||
}
|
||||
if keys[0].ID != 7 || keys[0].Title != "deploy" {
|
||||
t.Fatalf("got %#v", keys[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepoService_GetKey_Good(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
t.Errorf("expected GET, got %s", r.Method)
|
||||
}
|
||||
if r.URL.Path != "/api/v1/repos/core/go-forge/keys/7" {
|
||||
t.Errorf("wrong path: %s", r.URL.Path)
|
||||
}
|
||||
json.NewEncoder(w).Encode(types.DeployKey{ID: 7, Title: "deploy"})
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
f := NewForge(srv.URL, "tok")
|
||||
key, err := f.Repos.GetKey(context.Background(), "core", "go-forge", 7)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if key.ID != 7 || key.Title != "deploy" {
|
||||
t.Fatalf("got %#v", key)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepoService_CreateKey_Good(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
t.Errorf("expected POST, got %s", r.Method)
|
||||
}
|
||||
if r.URL.Path != "/api/v1/repos/core/go-forge/keys" {
|
||||
t.Errorf("wrong path: %s", r.URL.Path)
|
||||
}
|
||||
var opts types.CreateKeyOption
|
||||
if err := json.NewDecoder(r.Body).Decode(&opts); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if opts.Title != "deploy" || opts.Key != "ssh-ed25519 AAAA..." || !opts.ReadOnly {
|
||||
t.Fatalf("got %#v", opts)
|
||||
}
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
json.NewEncoder(w).Encode(types.DeployKey{ID: 9, Title: opts.Title, Key: opts.Key, ReadOnly: opts.ReadOnly})
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
f := NewForge(srv.URL, "tok")
|
||||
key, err := f.Repos.CreateKey(context.Background(), "core", "go-forge", &types.CreateKeyOption{
|
||||
Title: "deploy",
|
||||
Key: "ssh-ed25519 AAAA...",
|
||||
ReadOnly: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if key.ID != 9 || key.Title != "deploy" || !key.ReadOnly {
|
||||
t.Fatalf("got %#v", key)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepoService_DeleteKey_Good(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodDelete {
|
||||
t.Errorf("expected DELETE, got %s", r.Method)
|
||||
}
|
||||
if r.URL.Path != "/api/v1/repos/core/go-forge/keys/7" {
|
||||
t.Errorf("wrong path: %s", r.URL.Path)
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
f := NewForge(srv.URL, "tok")
|
||||
if err := f.Repos.DeleteKey(context.Background(), "core", "go-forge", 7); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepoService_DeleteTag_Bad_NotFound(t *testing.T) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodDelete {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue