Skip to content

Commit 8815ccb

Browse files
authored
Merge branch 'main' into add-endpoint-tip
2 parents ed84450 + 81ef50c commit 8815ccb

File tree

4 files changed

+426
-82
lines changed

4 files changed

+426
-82
lines changed

cmd/src/repos.go

Lines changed: 2 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"context"
55
"flag"
66
"fmt"
7-
"time"
87

98
"github.com/sourcegraph/sourcegraph/lib/errors"
109

@@ -51,53 +50,17 @@ Use "src repos [command] -h" for more information about a command.
5150

5251
const repositoryFragment = `
5352
fragment RepositoryFields on Repository {
54-
id
5553
name
56-
url
57-
description
58-
language
59-
createdAt
60-
updatedAt
61-
externalRepository {
62-
id
63-
serviceType
64-
serviceID
65-
}
6654
defaultBranch {
6755
name
6856
displayName
6957
}
70-
viewerCanAdminister
71-
keyValuePairs {
72-
key
73-
value
74-
}
7558
}
7659
`
7760

7861
type Repository struct {
79-
ID string `json:"id"`
80-
Name string `json:"name"`
81-
URL string `json:"url"`
82-
Description string `json:"description"`
83-
Language string `json:"language"`
84-
CreatedAt time.Time `json:"createdAt"`
85-
UpdatedAt *time.Time `json:"updatedAt"`
86-
ExternalRepository ExternalRepository `json:"externalRepository"`
87-
DefaultBranch GitRef `json:"defaultBranch"`
88-
ViewerCanAdminister bool `json:"viewerCanAdminister"`
89-
KeyValuePairs []KeyValuePair `json:"keyValuePairs"`
90-
}
91-
92-
type KeyValuePair struct {
93-
Key string `json:"key"`
94-
Value *string `json:"value"`
95-
}
96-
97-
type ExternalRepository struct {
98-
ID string `json:"id"`
99-
ServiceType string `json:"serviceType"`
100-
ServiceID string `json:"serviceID"`
62+
Name string `json:"name"`
63+
DefaultBranch GitRef `json:"defaultBranch"`
10164
}
10265

10366
type GitRef struct {

cmd/src/repos_list.go

Lines changed: 164 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,157 @@ package main
22

33
import (
44
"context"
5+
"encoding/json"
56
"flag"
67
"fmt"
78
"strings"
89

910
"github.com/sourcegraph/src-cli/internal/api"
1011
)
1112

13+
type reposListOptions struct {
14+
first int
15+
query string
16+
cloned bool
17+
notCloned bool
18+
indexed bool
19+
notIndexed bool
20+
orderBy string
21+
descending bool
22+
}
23+
24+
type repositoriesListResult struct {
25+
Data struct {
26+
Repositories struct {
27+
Nodes []Repository `json:"nodes"`
28+
} `json:"repositories"`
29+
} `json:"data"`
30+
Errors []json.RawMessage `json:"errors,omitempty"`
31+
}
32+
33+
// listRepositories returns the repositories from the response, any GraphQL
34+
// errors returned alongside data (should be treated as warnings), and
35+
// a hard error when the query fails without usable repository data.
36+
func listRepositories(ctx context.Context, client api.Client, params reposListOptions) ([]Repository, api.GraphQlErrors, error) {
37+
query := `query Repositories(
38+
$first: Int,
39+
$query: String,
40+
$cloned: Boolean,
41+
$notCloned: Boolean,
42+
$indexed: Boolean,
43+
$notIndexed: Boolean,
44+
$orderBy: RepositoryOrderBy,
45+
$descending: Boolean,
46+
) {
47+
repositories(
48+
first: $first,
49+
query: $query,
50+
cloned: $cloned,
51+
notCloned: $notCloned,
52+
indexed: $indexed,
53+
notIndexed: $notIndexed,
54+
orderBy: $orderBy,
55+
descending: $descending,
56+
) {
57+
nodes {
58+
...RepositoryFields
59+
}
60+
}
61+
}
62+
` + repositoryFragment
63+
64+
var result repositoriesListResult
65+
ok, err := client.NewRequest(query, map[string]any{
66+
"first": api.NullInt(params.first),
67+
"query": api.NullString(params.query),
68+
"cloned": params.cloned,
69+
"notCloned": params.notCloned,
70+
"indexed": params.indexed,
71+
"notIndexed": params.notIndexed,
72+
"orderBy": params.orderBy,
73+
"descending": params.descending,
74+
}).DoRaw(ctx, &result)
75+
if err != nil || !ok {
76+
return nil, nil, err
77+
}
78+
repos := result.Data.Repositories.Nodes
79+
if len(result.Errors) == 0 {
80+
return repos, nil, nil
81+
}
82+
83+
errors := api.NewGraphQlErrors(result.Errors)
84+
if len(repos) > 0 {
85+
return repos, errors, nil
86+
}
87+
88+
return nil, nil, errors
89+
}
90+
91+
func gqlErrorPathString(pathSegment any) (string, bool) {
92+
value, ok := pathSegment.(string)
93+
return value, ok
94+
}
95+
96+
func gqlErrorIndex(pathSegment any) (int, bool) {
97+
switch value := pathSegment.(type) {
98+
case float64:
99+
index := int(value)
100+
return index, float64(index) == value && index >= 0
101+
case int:
102+
return value, value >= 0
103+
default:
104+
return 0, false
105+
}
106+
}
107+
108+
func gqlWarningPath(graphQLError *api.GraphQlError) string {
109+
path, err := graphQLError.Path()
110+
if err != nil || len(path) == 0 {
111+
return ""
112+
}
113+
114+
var b strings.Builder
115+
for _, pathSegment := range path {
116+
if segment, ok := gqlErrorPathString(pathSegment); ok {
117+
if b.Len() > 0 {
118+
b.WriteByte('.')
119+
}
120+
b.WriteString(segment)
121+
continue
122+
}
123+
124+
if index, ok := gqlErrorIndex(pathSegment); ok {
125+
fmt.Fprintf(&b, "[%d]", index)
126+
}
127+
}
128+
129+
return b.String()
130+
}
131+
132+
func gqlWarningMessage(graphQLError *api.GraphQlError) string {
133+
message, err := graphQLError.Message()
134+
if err != nil || message == "" {
135+
return graphQLError.Error()
136+
}
137+
return message
138+
}
139+
140+
func formatRepositoryListWarnings(warnings api.GraphQlErrors) string {
141+
var b strings.Builder
142+
fmt.Fprintf(&b, "warnings: %d errors during listing\n", len(warnings))
143+
for _, warning := range warnings {
144+
path := gqlWarningPath(warning)
145+
message := gqlWarningMessage(warning)
146+
if path != "" {
147+
fmt.Fprintf(&b, "%s - %s\n", path, message)
148+
} else {
149+
fmt.Fprintf(&b, "%s\n", message)
150+
}
151+
fmt.Fprintf(&b, "%s\n", warning.Error())
152+
}
153+
return b.String()
154+
}
155+
12156
func init() {
13157
usage := `
14158
Examples:
@@ -64,33 +208,6 @@ Examples:
64208
return err
65209
}
66210

67-
query := `query Repositories(
68-
$first: Int,
69-
$query: String,
70-
$cloned: Boolean,
71-
$notCloned: Boolean,
72-
$indexed: Boolean,
73-
$notIndexed: Boolean,
74-
$orderBy: RepositoryOrderBy,
75-
$descending: Boolean,
76-
) {
77-
repositories(
78-
first: $first,
79-
query: $query,
80-
cloned: $cloned,
81-
notCloned: $notCloned,
82-
indexed: $indexed,
83-
notIndexed: $notIndexed,
84-
orderBy: $orderBy,
85-
descending: $descending,
86-
) {
87-
nodes {
88-
...RepositoryFields
89-
}
90-
}
91-
}
92-
` + repositoryFragment
93-
94211
var orderBy string
95212
switch *orderByFlag {
96213
case "name":
@@ -101,25 +218,22 @@ Examples:
101218
return fmt.Errorf("invalid -order-by flag value: %q", *orderByFlag)
102219
}
103220

104-
var result struct {
105-
Repositories struct {
106-
Nodes []Repository
107-
}
108-
}
109-
if ok, err := client.NewRequest(query, map[string]any{
110-
"first": api.NullInt(*firstFlag),
111-
"query": api.NullString(*queryFlag),
112-
"cloned": *clonedFlag,
113-
"notCloned": *notClonedFlag,
114-
"indexed": *indexedFlag,
115-
"notIndexed": *notIndexedFlag,
116-
"orderBy": orderBy,
117-
"descending": *descendingFlag,
118-
}).Do(context.Background(), &result); err != nil || !ok {
221+
// if we get repos and errors during a listing, we consider the errors as warnings and the data partially complete
222+
repos, warnings, err := listRepositories(context.Background(), client, reposListOptions{
223+
first: *firstFlag,
224+
query: *queryFlag,
225+
cloned: *clonedFlag,
226+
notCloned: *notClonedFlag,
227+
indexed: *indexedFlag,
228+
notIndexed: *notIndexedFlag,
229+
orderBy: orderBy,
230+
descending: *descendingFlag,
231+
})
232+
if err != nil {
119233
return err
120234
}
121235

122-
for _, repo := range result.Repositories.Nodes {
236+
for _, repo := range repos {
123237
if *namesWithoutHostFlag {
124238
firstSlash := strings.Index(repo.Name, "/")
125239
fmt.Println(repo.Name[firstSlash+len("/"):])
@@ -130,6 +244,13 @@ Examples:
130244
return err
131245
}
132246
}
247+
if len(warnings) > 0 {
248+
if *verbose {
249+
fmt.Fprint(flagSet.Output(), formatRepositoryListWarnings(warnings))
250+
} else {
251+
fmt.Fprintf(flagSet.Output(), "warning: %d errors during listing; rerun with -v to inspect them\n", len(warnings))
252+
}
253+
}
133254
return nil
134255
}
135256

0 commit comments

Comments
 (0)