Skip to content

Commit ab35a47

Browse files
authored
Implement file deletion for CreateTree (#1372)
1 parent 4b2f230 commit ab35a47

File tree

2 files changed

+55
-28
lines changed

2 files changed

+55
-28
lines changed

github/git_trees.go

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,20 @@ func (t TreeEntry) String() string {
4444
return Stringify(t)
4545
}
4646

47+
// treeEntryWithFileDelete is used internally to delete a file whose
48+
// Content and SHA fields are empty. It does this by removing the "omitempty"
49+
// tag modifier on the SHA field which causes the GitHub API to receive
50+
// {"sha":null} and thereby delete the file.
51+
type treeEntryWithFileDelete struct {
52+
SHA *string `json:"sha"`
53+
Path *string `json:"path,omitempty"`
54+
Mode *string `json:"mode,omitempty"`
55+
Type *string `json:"type,omitempty"`
56+
Size *int `json:"size,omitempty"`
57+
Content *string `json:"content,omitempty"`
58+
URL *string `json:"url,omitempty"`
59+
}
60+
4761
func (t *TreeEntry) MarshalJSON() ([]byte, error) {
4862
if t.SHA == nil && t.Content == nil {
4963
return json.Marshal(struct {
@@ -102,8 +116,8 @@ func (s *GitService) GetTree(ctx context.Context, owner string, repo string, sha
102116

103117
// createTree represents the body of a CreateTree request.
104118
type createTree struct {
105-
BaseTree string `json:"base_tree,omitempty"`
106-
Entries []TreeEntry `json:"tree"`
119+
BaseTree string `json:"base_tree,omitempty"`
120+
Entries []interface{} `json:"tree"`
107121
}
108122

109123
// CreateTree creates a new tree in a repository. If both a tree and a nested
@@ -114,9 +128,24 @@ type createTree struct {
114128
func (s *GitService) CreateTree(ctx context.Context, owner string, repo string, baseTree string, entries []TreeEntry) (*Tree, *Response, error) {
115129
u := fmt.Sprintf("repos/%v/%v/git/trees", owner, repo)
116130

131+
newEntries := make([]interface{}, 0, len(entries))
132+
for _, entry := range entries {
133+
if entry.Content == nil && entry.SHA == nil {
134+
newEntries = append(newEntries, treeEntryWithFileDelete{
135+
Path: entry.Path,
136+
Mode: entry.Mode,
137+
Type: entry.Type,
138+
Size: entry.Size,
139+
URL: entry.URL,
140+
})
141+
continue
142+
}
143+
newEntries = append(newEntries, entry)
144+
}
145+
117146
body := &createTree{
118147
BaseTree: baseTree,
119-
Entries: entries,
148+
Entries: newEntries,
120149
}
121150
req, err := s.client.NewRequest("POST", u, body)
122151
if err != nil {

github/git_trees_test.go

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66
package github
77

88
import (
9+
"bytes"
910
"context"
10-
"encoding/json"
1111
"fmt"
12+
"io/ioutil"
1213
"net/http"
1314
"reflect"
1415
"testing"
@@ -68,17 +69,16 @@ func TestGitService_CreateTree(t *testing.T) {
6869
}
6970

7071
mux.HandleFunc("/repos/o/r/git/trees", func(w http.ResponseWriter, r *http.Request) {
71-
v := new(createTree)
72-
json.NewDecoder(r.Body).Decode(v)
72+
got, err := ioutil.ReadAll(r.Body)
73+
if err != nil {
74+
t.Fatalf("unable to read body: %v", err)
75+
}
7376

7477
testMethod(t, r, "POST")
7578

76-
want := &createTree{
77-
BaseTree: "b",
78-
Entries: input,
79-
}
80-
if !reflect.DeepEqual(v, want) {
81-
t.Errorf("Git.CreateTree request body: %+v, want %+v", v, want)
79+
want := []byte(`{"base_tree":"b","tree":[{"sha":"7c258a9869f33c1e1e1f74fbb32f07c86cb5a75b","path":"file.rb","mode":"100644","type":"blob"}]}` + "\n")
80+
if !bytes.Equal(got, want) {
81+
t.Errorf("Git.CreateTree request body: %s, want %s", got, want)
8282
}
8383

8484
fmt.Fprint(w, `{
@@ -132,17 +132,16 @@ func TestGitService_CreateTree_Content(t *testing.T) {
132132
}
133133

134134
mux.HandleFunc("/repos/o/r/git/trees", func(w http.ResponseWriter, r *http.Request) {
135-
v := new(createTree)
136-
json.NewDecoder(r.Body).Decode(v)
135+
got, err := ioutil.ReadAll(r.Body)
136+
if err != nil {
137+
t.Fatalf("unable to read body: %v", err)
138+
}
137139

138140
testMethod(t, r, "POST")
139141

140-
want := &createTree{
141-
BaseTree: "b",
142-
Entries: input,
143-
}
144-
if !reflect.DeepEqual(v, want) {
145-
t.Errorf("Git.CreateTree request body: %+v, want %+v", v, want)
142+
want := []byte(`{"base_tree":"b","tree":[{"path":"content.md","mode":"100644","content":"file content"}]}` + "\n")
143+
if !bytes.Equal(got, want) {
144+
t.Errorf("Git.CreateTree request body: %s, want %s", got, want)
146145
}
147146

148147
fmt.Fprint(w, `{
@@ -198,17 +197,16 @@ func TestGitService_CreateTree_Delete(t *testing.T) {
198197
}
199198

200199
mux.HandleFunc("/repos/o/r/git/trees", func(w http.ResponseWriter, r *http.Request) {
201-
v := new(createTree)
202-
json.NewDecoder(r.Body).Decode(v)
200+
got, err := ioutil.ReadAll(r.Body)
201+
if err != nil {
202+
t.Fatalf("unable to read body: %v", err)
203+
}
203204

204205
testMethod(t, r, "POST")
205206

206-
want := &createTree{
207-
BaseTree: "b",
208-
Entries: input,
209-
}
210-
if !reflect.DeepEqual(v, want) {
211-
t.Errorf("Git.CreateTree request body: %+v, want %+v", v, want)
207+
want := []byte(`{"base_tree":"b","tree":[{"sha":null,"path":"content.md","mode":"100644"}]}` + "\n")
208+
if !bytes.Equal(got, want) {
209+
t.Errorf("Git.CreateTree request body: %s, want %s", got, want)
212210
}
213211

214212
fmt.Fprint(w, `{

0 commit comments

Comments
 (0)