github.com/google/go-github/v49@v49.1.0/github/git_trees.go (about) 1 // Copyright 2013 The go-github AUTHORS. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file. 5 6 package github 7 8 import ( 9 "context" 10 "encoding/json" 11 "fmt" 12 ) 13 14 // Tree represents a GitHub tree. 15 type Tree struct { 16 SHA *string `json:"sha,omitempty"` 17 Entries []*TreeEntry `json:"tree,omitempty"` 18 19 // Truncated is true if the number of items in the tree 20 // exceeded GitHub's maximum limit and the Entries were truncated 21 // in the response. Only populated for requests that fetch 22 // trees like Git.GetTree. 23 Truncated *bool `json:"truncated,omitempty"` 24 } 25 26 func (t Tree) String() string { 27 return Stringify(t) 28 } 29 30 // TreeEntry represents the contents of a tree structure. TreeEntry can 31 // represent either a blob, a commit (in the case of a submodule), or another 32 // tree. 33 type TreeEntry struct { 34 SHA *string `json:"sha,omitempty"` 35 Path *string `json:"path,omitempty"` 36 Mode *string `json:"mode,omitempty"` 37 Type *string `json:"type,omitempty"` 38 Size *int `json:"size,omitempty"` 39 Content *string `json:"content,omitempty"` 40 URL *string `json:"url,omitempty"` 41 } 42 43 func (t TreeEntry) String() string { 44 return Stringify(t) 45 } 46 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 61 func (t *TreeEntry) MarshalJSON() ([]byte, error) { 62 if t.SHA == nil && t.Content == nil { 63 return json.Marshal(struct { 64 SHA *string `json:"sha"` 65 Path *string `json:"path,omitempty"` 66 Mode *string `json:"mode,omitempty"` 67 Type *string `json:"type,omitempty"` 68 }{ 69 nil, 70 t.Path, 71 t.Mode, 72 t.Type, 73 }) 74 } 75 return json.Marshal(struct { 76 SHA *string `json:"sha,omitempty"` 77 Path *string `json:"path,omitempty"` 78 Mode *string `json:"mode,omitempty"` 79 Type *string `json:"type,omitempty"` 80 Size *int `json:"size,omitempty"` 81 Content *string `json:"content,omitempty"` 82 URL *string `json:"url,omitempty"` 83 }{ 84 SHA: t.SHA, 85 Path: t.Path, 86 Mode: t.Mode, 87 Type: t.Type, 88 Size: t.Size, 89 Content: t.Content, 90 URL: t.URL, 91 }) 92 } 93 94 // GetTree fetches the Tree object for a given sha hash from a repository. 95 // 96 // GitHub API docs: https://docs.github.com/en/rest/git/trees#get-a-tree 97 func (s *GitService) GetTree(ctx context.Context, owner string, repo string, sha string, recursive bool) (*Tree, *Response, error) { 98 u := fmt.Sprintf("repos/%v/%v/git/trees/%v", owner, repo, sha) 99 if recursive { 100 u += "?recursive=1" 101 } 102 103 req, err := s.client.NewRequest("GET", u, nil) 104 if err != nil { 105 return nil, nil, err 106 } 107 108 t := new(Tree) 109 resp, err := s.client.Do(ctx, req, t) 110 if err != nil { 111 return nil, resp, err 112 } 113 114 return t, resp, nil 115 } 116 117 // createTree represents the body of a CreateTree request. 118 type createTree struct { 119 BaseTree string `json:"base_tree,omitempty"` 120 Entries []interface{} `json:"tree"` 121 } 122 123 // CreateTree creates a new tree in a repository. If both a tree and a nested 124 // path modifying that tree are specified, it will overwrite the contents of 125 // that tree with the new path contents and write a new tree out. 126 // 127 // GitHub API docs: https://docs.github.com/en/rest/git/trees#create-a-tree 128 func (s *GitService) CreateTree(ctx context.Context, owner string, repo string, baseTree string, entries []*TreeEntry) (*Tree, *Response, error) { 129 u := fmt.Sprintf("repos/%v/%v/git/trees", owner, repo) 130 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 146 body := &createTree{ 147 BaseTree: baseTree, 148 Entries: newEntries, 149 } 150 req, err := s.client.NewRequest("POST", u, body) 151 if err != nil { 152 return nil, nil, err 153 } 154 155 t := new(Tree) 156 resp, err := s.client.Do(ctx, req, t) 157 if err != nil { 158 return nil, resp, err 159 } 160 161 return t, resp, nil 162 }