Browse Source

add support for git signing API methods

Fixes #334.

Change-Id: I9b10ae5e7679f5196778d9eb3ded6168d7facfc3
Glenn Lewis 10 years ago
parent
commit
a6edb1171a
10 changed files with 281 additions and 14 deletions
  1. +3
    -0
      github/authorizations.go
  2. +20
    -8
      github/git_commits.go
  3. +1
    -0
      github/git_commits_test.go
  4. +10
    -6
      github/git_tags.go
  5. +1
    -0
      github/git_tags_test.go
  6. +3
    -0
      github/github.go
  7. +3
    -0
      github/repos_commits.go
  8. +1
    -0
      github/repos_commits_test.go
  9. +129
    -0
      github/users_gpg_keys.go
  10. +110
    -0
      github/users_gpg_keys_test.go

+ 3
- 0
github/authorizations.go View File

@ -35,6 +35,9 @@ const (
ScopeReadPublicKey Scope = "read:public_key"
ScopeWritePublicKey Scope = "write:public_key"
ScopeAdminPublicKey Scope = "admin:public_key"
ScopeReadGPGKey Scope = "read:gpg_key"
ScopeWriteGPGKey Scope = "write:gpg_key"
ScopeAdminGPGKey Scope = "admin:gpg_key"
)
// AuthorizationsService handles communication with the authorization related


+ 20
- 8
github/git_commits.go View File

@ -10,16 +10,25 @@ import (
"time"
)
// SignatureVerification represents GPG signature verification.
type SignatureVerification struct {
Verified *bool `json:"verified,omitempty"`
Reason *string `json:"reason,omitempty"`
Signature *string `json:"signature,omitempty"`
Payload *string `json:"payload,omitempty"`
}
// Commit represents a GitHub commit.
type Commit struct {
SHA *string `json:"sha,omitempty"`
Author *CommitAuthor `json:"author,omitempty"`
Committer *CommitAuthor `json:"committer,omitempty"`
Message *string `json:"message,omitempty"`
Tree *Tree `json:"tree,omitempty"`
Parents []Commit `json:"parents,omitempty"`
Stats *CommitStats `json:"stats,omitempty"`
URL *string `json:"url,omitempty"`
SHA *string `json:"sha,omitempty"`
Author *CommitAuthor `json:"author,omitempty"`
Committer *CommitAuthor `json:"committer,omitempty"`
Message *string `json:"message,omitempty"`
Tree *Tree `json:"tree,omitempty"`
Parents []Commit `json:"parents,omitempty"`
Stats *CommitStats `json:"stats,omitempty"`
URL *string `json:"url,omitempty"`
Verification *SignatureVerification `json:"verification,omitempty"`
// CommentCount is the number of GitHub comments on the commit. This
// is only populated for requests that fetch GitHub data like
@ -56,6 +65,9 @@ func (s *GitService) GetCommit(owner string, repo string, sha string) (*Commit,
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGitSigningPreview)
c := new(Commit)
resp, err := s.client.Do(req, c)
if err != nil {


+ 1
- 0
github/git_commits_test.go View File

@ -19,6 +19,7 @@ func TestGitService_GetCommit(t *testing.T) {
mux.HandleFunc("/repos/o/r/git/commits/s", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeGitSigningPreview)
fmt.Fprint(w, `{"sha":"s","message":"m","author":{"name":"n"}}`)
})


+ 10
- 6
github/git_tags.go View File

@ -11,12 +11,13 @@ import (
// Tag represents a tag object.
type Tag struct {
Tag *string `json:"tag,omitempty"`
SHA *string `json:"sha,omitempty"`
URL *string `json:"url,omitempty"`
Message *string `json:"message,omitempty"`
Tagger *CommitAuthor `json:"tagger,omitempty"`
Object *GitObject `json:"object,omitempty"`
Tag *string `json:"tag,omitempty"`
SHA *string `json:"sha,omitempty"`
URL *string `json:"url,omitempty"`
Message *string `json:"message,omitempty"`
Tagger *CommitAuthor `json:"tagger,omitempty"`
Object *GitObject `json:"object,omitempty"`
Verification *SignatureVerification `json:"verification,omitempty"`
}
// createTagRequest represents the body of a CreateTag request. This is mostly
@ -40,6 +41,9 @@ func (s *GitService) GetTag(owner string, repo string, sha string) (*Tag, *Respo
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGitSigningPreview)
tag := new(Tag)
resp, err := s.client.Do(req, tag)
return tag, resp, err


+ 1
- 0
github/git_tags_test.go View File

@ -19,6 +19,7 @@ func TestGitService_GetTag(t *testing.T) {
mux.HandleFunc("/repos/o/r/git/tags/s", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeGitSigningPreview)
fmt.Fprint(w, `{"tag": "t"}`)
})


+ 3
- 0
github/github.go View File

@ -72,6 +72,9 @@ const (
// https://developer.github.com/changes/2016-04-01-squash-api-preview/
mediaTypeSquashPreview = "application/vnd.github.polaris-preview+json"
// https://developer.github.com/changes/2016-04-04-git-signing-api-preview/
mediaTypeGitSigningPreview = "application/vnd.github.cryptographer-preview+json"
)
// A Client manages communication with the GitHub API.


+ 3
- 0
github/repos_commits.go View File

@ -138,6 +138,9 @@ func (s *RepositoriesService) GetCommit(owner, repo, sha string) (*RepositoryCom
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGitSigningPreview)
commit := new(RepositoryCommit)
resp, err := s.client.Do(req, commit)
if err != nil {


+ 1
- 0
github/repos_commits_test.go View File

@ -55,6 +55,7 @@ func TestRepositoriesService_GetCommit(t *testing.T) {
mux.HandleFunc("/repos/o/r/commits/s", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeGitSigningPreview)
fmt.Fprintf(w, `{
"sha": "s",
"commit": { "message": "m" },


+ 129
- 0
github/users_gpg_keys.go View File

@ -0,0 +1,129 @@
// Copyright 2016 The go-github AUTHORS. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package github
import (
"fmt"
"time"
)
// GPGKey represents a GitHub user's public GPG key used to verify GPG signed commits and tags.
//
// https://developer.github.com/changes/2016-04-04-git-signing-api-preview/
type GPGKey struct {
ID *int `json:"id,omitempty"`
PrimaryKeyID *int `json:"primary_key_id,omitempty"`
KeyID *string `json:"key_id,omitempty"`
PublicKey *string `json:"public_key,omitempty"`
Emails []GPGEmail `json:"emails,omitempty"`
Subkeys []GPGKey `json:"subkeys,omitempty"`
CanSign *bool `json:"can_sign,omitempty"`
CanEncryptComms *bool `json:"can_encrypt_comms,omitempty"`
CanEncryptStorage *bool `json:"can_encrypt_storage,omitempty"`
CanCertify *bool `json:"can_certify,omitempty"`
CreatedAt *time.Time `json:"created_at,omitempty"`
ExpiresAt *time.Time `json:"expires_at,omitempty"`
}
// String stringifies a GPGKey.
func (k GPGKey) String() string {
return Stringify(k)
}
// GPGEmail represents an email address associated to a GPG key.
type GPGEmail struct {
Email *string `json:"email,omitempty"`
Verified *bool `json:"verified,omitempty"`
}
// ListGPGKeys lists the current user's GPG keys. It requires authentication
// via Basic Auth or via OAuth with at least read:gpg_key scope.
//
// GitHub API docs: https://developer.github.com/v3/users/gpg_keys/#list-your-gpg-keys
func (s *UsersService) ListGPGKeys() ([]GPGKey, *Response, error) {
req, err := s.client.NewRequest("GET", "user/gpg_keys", nil)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGitSigningPreview)
var keys []GPGKey
resp, err := s.client.Do(req, &keys)
if err != nil {
return nil, resp, err
}
return keys, resp, err
}
// GetGPGKey gets extended details for a single GPG key. It requires authentication
// via Basic Auth or via OAuth with at least read:gpg_key scope.
//
// GitHub API docs: https://developer.github.com/v3/users/gpg_keys/#get-a-single-gpg-key
func (s *UsersService) GetGPGKey(id int) (*GPGKey, *Response, error) {
u := fmt.Sprintf("user/gpg_keys/%v", id)
req, err := s.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGitSigningPreview)
key := &GPGKey{}
resp, err := s.client.Do(req, key)
if err != nil {
return nil, resp, err
}
return key, resp, err
}
// CreateGPGKey creates a GPG key. It requires authenticatation via Basic Auth
// or OAuth with at least write:gpg_key scope.
//
// GitHub API docs: https://developer.github.com/v3/users/gpg_keys/#create-a-gpg-key
func (s *UsersService) CreateGPGKey(armoredPublicKey string) (*GPGKey, *Response, error) {
gpgKey := &struct {
ArmoredPublicKey *string `json:"armored_public_key,omitempty"`
}{
ArmoredPublicKey: String(armoredPublicKey),
}
req, err := s.client.NewRequest("POST", "user/gpg_keys", gpgKey)
if err != nil {
return nil, nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGitSigningPreview)
key := &GPGKey{}
resp, err := s.client.Do(req, key)
if err != nil {
return nil, resp, err
}
return key, resp, err
}
// DeleteGPGKey deletes a GPG key. It requires authentication via Basic Auth or
// via OAuth with at least admin:gpg_key scope.
//
// GitHub API docs: https://developer.github.com/v3/users/gpg_keys/#delete-a-gpg-key
func (s *UsersService) DeleteGPGKey(id int) (*Response, error) {
u := fmt.Sprintf("user/gpg_keys/%v", id)
req, err := s.client.NewRequest("DELETE", u, nil)
if err != nil {
return nil, err
}
// TODO: remove custom Accept header when this API fully launches.
req.Header.Set("Accept", mediaTypeGitSigningPreview)
return s.client.Do(req, nil)
}

+ 110
- 0
github/users_gpg_keys_test.go View File

@ -0,0 +1,110 @@
// Copyright 2016 The go-github AUTHORS. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package github
import (
"encoding/json"
"fmt"
"net/http"
"reflect"
"testing"
)
func TestUsersService_ListGPGKeys(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/user/gpg_keys", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeGitSigningPreview)
fmt.Fprint(w, `[{"id":1,"primary_key_id":2}]`)
})
keys, _, err := client.Users.ListGPGKeys()
if err != nil {
t.Errorf("Users.ListGPGKeys returned error: %v", err)
}
want := []GPGKey{{ID: Int(1), PrimaryKeyID: Int(2)}}
if !reflect.DeepEqual(keys, want) {
t.Errorf("Users.ListGPGKeys = %+v, want %+v", keys, want)
}
}
func TestUsersService_GetGPGKey(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/user/gpg_keys/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
testHeader(t, r, "Accept", mediaTypeGitSigningPreview)
fmt.Fprint(w, `{"id":1}`)
})
key, _, err := client.Users.GetGPGKey(1)
if err != nil {
t.Errorf("Users.GetGPGKey returned error: %v", err)
}
want := &GPGKey{ID: Int(1)}
if !reflect.DeepEqual(key, want) {
t.Errorf("Users.GetGPGKey = %+v, want %+v", key, want)
}
}
func TestUsersService_CreateGPGKey(t *testing.T) {
setup()
defer teardown()
input := `
-----BEGIN PGP PUBLIC KEY BLOCK-----
Comment: GPGTools - https://gpgtools.org
mQINBFcEd9kBEACo54TDbGhKlXKWMvJgecEUKPPcv7XdnpKdGb3LRw5MvFwT0V0f
...
=tqfb
-----END PGP PUBLIC KEY BLOCK-----`
mux.HandleFunc("/user/gpg_keys", func(w http.ResponseWriter, r *http.Request) {
var gpgKey struct {
ArmoredPublicKey *string `json:"armored_public_key,omitempty"`
}
json.NewDecoder(r.Body).Decode(&gpgKey)
testMethod(t, r, "POST")
testHeader(t, r, "Accept", mediaTypeGitSigningPreview)
if gpgKey.ArmoredPublicKey == nil || *gpgKey.ArmoredPublicKey != input {
t.Errorf("gpgKey = %+v, want %q", gpgKey, input)
}
fmt.Fprint(w, `{"id":1}`)
})
gpgKey, _, err := client.Users.CreateGPGKey(input)
if err != nil {
t.Errorf("Users.GetGPGKey returned error: %v", err)
}
want := &GPGKey{ID: Int(1)}
if !reflect.DeepEqual(gpgKey, want) {
t.Errorf("Users.GetGPGKey = %+v, want %+v", gpgKey, want)
}
}
func TestUsersService_DeleteGPGKey(t *testing.T) {
setup()
defer teardown()
mux.HandleFunc("/user/gpg_keys/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
testHeader(t, r, "Accept", mediaTypeGitSigningPreview)
})
_, err := client.Users.DeleteGPGKey(1)
if err != nil {
t.Errorf("Users.DeleteGPGKey returned error: %v", err)
}
}

Loading…
Cancel
Save