fetchTree resolves a directory listing for dirPath at ref. It uses the repository.object(expression) field, which returns a Tree for a directory, a Blob for a file, or null when the path or ref cannot be resolved. Unlike the REST Contents API, GraphQL has no 1000-entry cap and exposes the git mode,
(httpClient *http.Client, repo ghrepo.Interface, dirPath, ref string)
| 127 | // the path points to a file rather than a directory. The original ref (empty for |
| 128 | // the default branch) is only used when building error messages. |
| 129 | func fetchTree(httpClient *http.Client, repo ghrepo.Interface, dirPath, ref string) (*repoDir, error) { |
| 130 | client := api.NewClientFromHTTP(httpClient) |
| 131 | |
| 132 | expressionRef := ref |
| 133 | if expressionRef == "" { |
| 134 | expressionRef = "HEAD" |
| 135 | } |
| 136 | expression := fmt.Sprintf("%s:%s", expressionRef, strings.TrimPrefix(dirPath, "/")) |
| 137 | |
| 138 | var query struct { |
| 139 | Repository struct { |
| 140 | Object *struct { |
| 141 | TypeName string `graphql:"__typename"` |
| 142 | Tree struct { |
| 143 | OID string `graphql:"oid"` |
| 144 | ID string `graphql:"id"` |
| 145 | Entries []struct { |
| 146 | Name string |
| 147 | Path string |
| 148 | NameRaw string |
| 149 | PathRaw string |
| 150 | Type string |
| 151 | Mode int |
| 152 | OID string `graphql:"oid"` |
| 153 | Size int |
| 154 | Submodule *struct { |
| 155 | GitURL string `graphql:"gitUrl"` |
| 156 | Branch *string |
| 157 | SubprojectCommitOid string |
| 158 | } |
| 159 | } |
| 160 | } `graphql:"... on Tree"` |
| 161 | } `graphql:"object(expression: $expression)"` |
| 162 | } `graphql:"repository(owner: $owner, name: $name)"` |
| 163 | } |
| 164 | |
| 165 | variables := map[string]interface{}{ |
| 166 | "owner": githubv4.String(repo.RepoOwner()), |
| 167 | "name": githubv4.String(repo.RepoName()), |
| 168 | "expression": githubv4.String(expression), |
| 169 | } |
| 170 | |
| 171 | if err := client.Query(repo.RepoHost(), "RepoReadDir", &query, variables); err != nil { |
| 172 | return nil, err |
| 173 | } |
| 174 | |
| 175 | obj := query.Repository.Object |
| 176 | if obj == nil { |
| 177 | // The API returns a null object for both missing paths or refs, so we |
| 178 | // cannot tell which one is wrong and infer the message from whether a ref was given. |
| 179 | if ref != "" { |
| 180 | return nil, fmt.Errorf("could not find %q at %q in %s (the path or ref may not exist)", dirPath, ref, ghrepo.FullName(repo)) |
| 181 | } |
| 182 | return nil, fmt.Errorf("could not find %q in %s", dirPath, ghrepo.FullName(repo)) |
| 183 | } |
| 184 | |
| 185 | if obj.TypeName != "Tree" { |
| 186 | if obj.TypeName == "Blob" { |
no test coverage detected