@@ -10,9 +10,8 @@ import (
10
10
"context"
11
11
"errors"
12
12
"fmt"
13
+ "io"
13
14
"strings"
14
-
15
- "github.com/ProtonMail/go-crypto/openpgp"
16
15
)
17
16
18
17
// SignatureVerification represents GPG signature verification.
@@ -23,6 +22,25 @@ type SignatureVerification struct {
23
22
Payload * string `json:"payload,omitempty"`
24
23
}
25
24
25
+ // MessageSigner is used by GitService.CreateCommit to sign a commit.
26
+ //
27
+ // To create a MessageSigner that signs a commit with a [golang.org/x/crypto/openpgp.Entity],
28
+ // or [github.com/ProtonMail/go-crypto/openpgp.Entity], use:
29
+ //
30
+ // commit.Signer = github.MessageSignerFunc(func(w io.Writer, r io.Reader) error {
31
+ // return openpgp.ArmoredDetachSign(w, openpgpEntity, r, nil)
32
+ // })
33
+ type MessageSigner interface {
34
+ Sign (w io.Writer , r io.Reader ) error
35
+ }
36
+
37
+ // MessageSignerFunc is a single function implementation of MessageSigner.
38
+ type MessageSignerFunc func (w io.Writer , r io.Reader ) error
39
+
40
+ func (f MessageSignerFunc ) Sign (w io.Writer , r io.Reader ) error {
41
+ return f (w , r )
42
+ }
43
+
26
44
// Commit represents a GitHub commit.
27
45
type Commit struct {
28
46
SHA * string `json:"sha,omitempty"`
@@ -41,11 +59,6 @@ type Commit struct {
41
59
// is only populated for requests that fetch GitHub data like
42
60
// Pulls.ListCommits, Repositories.ListCommits, etc.
43
61
CommentCount * int `json:"comment_count,omitempty"`
44
-
45
- // SigningKey denotes a key to sign the commit with. If not nil this key will
46
- // be used to sign the commit. The private key must be present and already
47
- // decrypted. Ignored if Verification.Signature is defined.
48
- SigningKey * openpgp.Entity `json:"-"`
49
62
}
50
63
51
64
func (c Commit ) String () string {
@@ -96,6 +109,12 @@ type createCommit struct {
96
109
Signature * string `json:"signature,omitempty"`
97
110
}
98
111
112
+ type CreateCommitOptions struct {
113
+ // CreateCommit will sign the commit with this signer. See MessageSigner doc for more details.
114
+ // Ignored on commits where Verification.Signature is defined.
115
+ Signer MessageSigner
116
+ }
117
+
99
118
// CreateCommit creates a new commit in a repository.
100
119
// commit must not be nil.
101
120
//
@@ -104,10 +123,13 @@ type createCommit struct {
104
123
// the authenticated user’s information and the current date.
105
124
//
106
125
// GitHub API docs: https://docs.github.com/en/rest/git/commits#create-a-commit
107
- func (s * GitService ) CreateCommit (ctx context.Context , owner string , repo string , commit * Commit ) (* Commit , * Response , error ) {
126
+ func (s * GitService ) CreateCommit (ctx context.Context , owner string , repo string , commit * Commit , opts * CreateCommitOptions ) (* Commit , * Response , error ) {
108
127
if commit == nil {
109
128
return nil , nil , fmt .Errorf ("commit must be provided" )
110
129
}
130
+ if opts == nil {
131
+ opts = & CreateCommitOptions {}
132
+ }
111
133
112
134
u := fmt .Sprintf ("repos/%v/%v/git/commits" , owner , repo )
113
135
@@ -125,16 +147,16 @@ func (s *GitService) CreateCommit(ctx context.Context, owner string, repo string
125
147
if commit .Tree != nil {
126
148
body .Tree = commit .Tree .SHA
127
149
}
128
- if commit .SigningKey != nil {
129
- signature , err := createSignature (commit .SigningKey , body )
150
+ switch {
151
+ case commit .Verification != nil :
152
+ body .Signature = commit .Verification .Signature
153
+ case opts .Signer != nil :
154
+ signature , err := createSignature (opts .Signer , body )
130
155
if err != nil {
131
156
return nil , nil , err
132
157
}
133
158
body .Signature = & signature
134
159
}
135
- if commit .Verification != nil {
136
- body .Signature = commit .Verification .Signature
137
- }
138
160
139
161
req , err := s .client .NewRequest ("POST" , u , body )
140
162
if err != nil {
@@ -150,8 +172,8 @@ func (s *GitService) CreateCommit(ctx context.Context, owner string, repo string
150
172
return c , resp , nil
151
173
}
152
174
153
- func createSignature (signingKey * openpgp. Entity , commit * createCommit ) (string , error ) {
154
- if signingKey == nil || commit == nil {
175
+ func createSignature (signer MessageSigner , commit * createCommit ) (string , error ) {
176
+ if signer == nil {
155
177
return "" , errors .New ("createSignature: invalid parameters" )
156
178
}
157
179
@@ -160,9 +182,9 @@ func createSignature(signingKey *openpgp.Entity, commit *createCommit) (string,
160
182
return "" , err
161
183
}
162
184
163
- writer := new ( bytes.Buffer )
164
- reader := bytes . NewReader ([] byte (message ))
165
- if err := openpgp . ArmoredDetachSign ( writer , signingKey , reader , nil ); err != nil {
185
+ var writer bytes.Buffer
186
+ err = signer . Sign ( & writer , strings . NewReader (message ))
187
+ if err != nil {
166
188
return "" , err
167
189
}
168
190
0 commit comments