github.com/google/go-github/v70@v70.0.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/rest/git/trees#get-a-tree 97 // 98 //meta:operation GET /repos/{owner}/{repo}/git/trees/{tree_sha} 99 func (s *GitService) GetTree(ctx context.Context, owner string, repo string, sha string, recursive bool) (*Tree, *Response, error) { 100 u := fmt.Sprintf("repos/%v/%v/git/trees/%v", owner, repo, sha) 101 if recursive { 102 u += "?recursive=1" 103 } 104 105 req, err := s.client.NewRequest("GET", u, nil) 106 if err != nil { 107 return nil, nil, err 108 } 109 110 t := new(Tree) 111 resp, err := s.client.Do(ctx, req, t) 112 if err != nil { 113 return nil, resp, err 114 } 115 116 return t, resp, nil 117 } 118 119 // createTree represents the body of a CreateTree request. 120 type createTree struct { 121 BaseTree string `json:"base_tree,omitempty"` 122 Entries []interface{} `json:"tree"` 123 } 124 125 // CreateTree creates a new tree in a repository. If both a tree and a nested 126 // path modifying that tree are specified, it will overwrite the contents of 127 // that tree with the new path contents and write a new tree out. 128 // 129 // GitHub API docs: https://docs.github.com/rest/git/trees#create-a-tree 130 // 131 //meta:operation POST /repos/{owner}/{repo}/git/trees 132 func (s *GitService) CreateTree(ctx context.Context, owner string, repo string, baseTree string, entries []*TreeEntry) (*Tree, *Response, error) { 133 u := fmt.Sprintf("repos/%v/%v/git/trees", owner, repo) 134 135 newEntries := make([]interface{}, 0, len(entries)) 136 for _, entry := range entries { 137 if entry.Content == nil && entry.SHA == nil { 138 newEntries = append(newEntries, treeEntryWithFileDelete{ 139 Path: entry.Path, 140 Mode: entry.Mode, 141 Type: entry.Type, 142 Size: entry.Size, 143 URL: entry.URL, 144 }) 145 continue 146 } 147 newEntries = append(newEntries, entry) 148 } 149 150 body := &createTree{ 151 BaseTree: baseTree, 152 Entries: newEntries, 153 } 154 req, err := s.client.NewRequest("POST", u, body) 155 if err != nil { 156 return nil, nil, err 157 } 158 159 t := new(Tree) 160 resp, err := s.client.Do(ctx, req, t) 161 if err != nil { 162 return nil, resp, err 163 } 164 165 return t, resp, nil 166 }