Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 4c68b1b

Browse filesBrowse files
zwickCopilot
authored andcommitted
Add node IDs to project resolver results
Split out of #2903 as a small prerequisite refactor. - Add a NodeID field to ResolvedField, populated for all three field variants in listAllProjectFields. - Refactor resolveProjectItemIDByIssueNumber into a thin wrapper over a new resolveProjectItemByIssueNumber that also returns the item node ID, delegating to resolveProjectItemByIssueNumberWithProjectID for an already-resolved project ID. The projectItems query now selects the item node ID alongside its full database ID. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 89f897b0-115f-4435-a071-46fb6c49be86
1 parent 9d13004 commit 4c68b1b
Copy full SHA for 4c68b1b

2 files changed

+31-12Lines changed: 31 additions & 12 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎pkg/github/projects_resolver.go‎

Copy file name to clipboardExpand all lines: pkg/github/projects_resolver.go
+22-9Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@ type ResolvedFieldOption struct {
2020
Name string
2121
}
2222

23-
// ResolvedField is a project field resolved by name; Options is only set when
24-
// DataType == "SINGLE_SELECT".
23+
// ResolvedField contains a project's numeric database ID, GraphQL node ID, and
24+
// type-specific options.
2525
type ResolvedField struct {
2626
ID string
27+
NodeID string
2728
Name string
2829
DataType string
2930
Options []ResolvedFieldOption
@@ -117,19 +118,22 @@ func listAllProjectFields(ctx context.Context, gqlClient *githubv4.Client, owner
117118
}
118119
all = append(all, ResolvedField{
119120
ID: fmt.Sprintf("%d", n.ProjectV2SingleSelectField.DatabaseID),
121+
NodeID: fmt.Sprintf("%v", n.ProjectV2SingleSelectField.ID),
120122
Name: string(n.ProjectV2SingleSelectField.Name),
121123
DataType: string(n.ProjectV2SingleSelectField.DataType),
122124
Options: opts,
123125
})
124126
case n.ProjectV2IterationField.ID != nil:
125127
all = append(all, ResolvedField{
126128
ID: fmt.Sprintf("%d", n.ProjectV2IterationField.DatabaseID),
129+
NodeID: fmt.Sprintf("%v", n.ProjectV2IterationField.ID),
127130
Name: string(n.ProjectV2IterationField.Name),
128131
DataType: string(n.ProjectV2IterationField.DataType),
129132
})
130133
case n.ProjectV2Field.ID != nil:
131134
all = append(all, ResolvedField{
132135
ID: fmt.Sprintf("%d", n.ProjectV2Field.DatabaseID),
136+
NodeID: fmt.Sprintf("%v", n.ProjectV2Field.ID),
133137
Name: string(n.ProjectV2Field.Name),
134138
DataType: string(n.ProjectV2Field.DataType),
135139
})
@@ -266,13 +270,22 @@ func resolveSingleSelectOptionByName(field *ResolvedField, optionName string) (s
266270
// project item's full database ID in one GraphQL hop. Returns a structured
267271
// error if the issue is not an item on the project.
268272
func resolveProjectItemIDByIssueNumber(ctx context.Context, gqlClient *githubv4.Client, owner, ownerType string, projectNumber int, issueOwner, issueRepo string, issueNumber int) (int64, error) {
273+
_, itemID, err := resolveProjectItemByIssueNumber(ctx, gqlClient, owner, ownerType, projectNumber, issueOwner, issueRepo, issueNumber)
274+
return itemID, err
275+
}
276+
277+
func resolveProjectItemByIssueNumber(ctx context.Context, gqlClient *githubv4.Client, owner, ownerType string, projectNumber int, issueOwner, issueRepo string, issueNumber int) (nodeID string, itemID int64, err error) {
269278
projectID, err := resolveProjectNodeID(ctx, gqlClient, owner, ownerType, projectNumber)
270279
if err != nil {
271-
return 0, err
280+
return "", 0, err
272281
}
282+
return resolveProjectItemByIssueNumberWithProjectID(ctx, gqlClient, projectID, issueOwner, issueRepo, issueNumber)
283+
}
273284

285+
func resolveProjectItemByIssueNumberWithProjectID(ctx context.Context, gqlClient *githubv4.Client, projectID githubv4.ID, issueOwner, issueRepo string, issueNumber int) (nodeID string, itemID int64, err error) {
274286
type projectItemsConnection struct {
275287
Nodes []struct {
288+
ID githubv4.ID
276289
FullDatabaseID githubv4.String `graphql:"fullDatabaseId"`
277290
Project struct {
278291
ID githubv4.ID
@@ -296,18 +309,18 @@ func resolveProjectItemIDByIssueNumber(ctx context.Context, gqlClient *githubv4.
296309
}
297310

298311
if err := gqlClient.Query(ctx, &firstPageQuery, vars); err != nil {
299-
return 0, fmt.Errorf("failed to resolve project item for %s/%s#%d: %w", issueOwner, issueRepo, issueNumber, err)
312+
return "", 0, fmt.Errorf("failed to resolve project item for %s/%s#%d: %w", issueOwner, issueRepo, issueNumber, err)
300313
}
301314

302315
projectItems := firstPageQuery.Repository.Issue.ProjectItems
303316
for {
304317
for _, item := range projectItems.Nodes {
305318
if item.Project.ID == projectID {
306-
itemID, parseErr := parseInt64(string(item.FullDatabaseID))
319+
parsedItemID, parseErr := parseInt64(string(item.FullDatabaseID))
307320
if parseErr != nil {
308-
return 0, fmt.Errorf("project item ID %q is not an integer: %w", string(item.FullDatabaseID), parseErr)
321+
return "", 0, fmt.Errorf("project item ID %q is not an integer: %w", string(item.FullDatabaseID), parseErr)
309322
}
310-
return itemID, nil
323+
return fmt.Sprintf("%v", item.ID), parsedItemID, nil
311324
}
312325
}
313326

@@ -324,12 +337,12 @@ func resolveProjectItemIDByIssueNumber(ctx context.Context, gqlClient *githubv4.
324337
}
325338
vars["after"] = projectItems.PageInfo.EndCursor
326339
if err := gqlClient.Query(ctx, &nextPageQuery, vars); err != nil {
327-
return 0, fmt.Errorf("failed to resolve project item for %s/%s#%d: %w", issueOwner, issueRepo, issueNumber, err)
340+
return "", 0, fmt.Errorf("failed to resolve project item for %s/%s#%d: %w", issueOwner, issueRepo, issueNumber, err)
328341
}
329342
projectItems = nextPageQuery.Repository.Issue.ProjectItems
330343
}
331344

332-
return 0, ghErrors.NewStructuredResolutionError(
345+
return "", 0, ghErrors.NewStructuredResolutionError(
333346
"item_not_in_project",
334347
fmt.Sprintf("%s/%s#%d", issueOwner, issueRepo, issueNumber),
335348
"the issue exists but is not an item on the named project; add it first via add_project_item",
Collapse file

‎pkg/github/projects_resolver_test.go‎

Copy file name to clipboardExpand all lines: pkg/github/projects_resolver_test.go
+9-3Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ type resolveItemByIssueQuery struct {
204204
Issue struct {
205205
ProjectItems struct {
206206
Nodes []struct {
207+
ID githubv4.ID
207208
FullDatabaseID githubv4.String `graphql:"fullDatabaseId"`
208209
Project struct {
209210
ID githubv4.ID
@@ -220,6 +221,7 @@ type resolveItemByIssuePageQuery struct {
220221
Issue struct {
221222
ProjectItems struct {
222223
Nodes []struct {
224+
ID githubv4.ID
223225
FullDatabaseID githubv4.String `graphql:"fullDatabaseId"`
224226
Project struct {
225227
ID githubv4.ID
@@ -282,6 +284,7 @@ func Test_ResolveProjectItemIDByIssueNumber_Success(t *testing.T) {
282284
"project": map[string]any{"id": "PVT_other"},
283285
},
284286
map[string]any{
287+
"id": "PVTI_target",
285288
"fullDatabaseId": "4242",
286289
"project": map[string]any{"id": "PVT_project1"},
287290
},
@@ -300,12 +303,13 @@ func Test_ResolveProjectItemIDByIssueNumber_Success(t *testing.T) {
300303
)
301304
gql := githubv4.NewClient(mocked)
302305

303-
itemID, err := resolveProjectItemIDByIssueNumber(context.Background(), gql, "octo-org", "org", 1, "octo-issue-owner", "repo", 123)
306+
nodeID, itemID, err := resolveProjectItemByIssueNumber(context.Background(), gql, "octo-org", "org", 1, "octo-issue-owner", "repo", 123)
304307
require.NoError(t, err)
308+
assert.Equal(t, "PVTI_target", nodeID)
305309
assert.Equal(t, int64(4242), itemID)
306310
}
307311

308-
func Test_ResolveProjectItemIDByIssueNumber_TargetOnSecondPage(t *testing.T) {
312+
func Test_ResolveProjectItemByIssueNumber_TargetOnSecondPage(t *testing.T) {
309313
mocked := githubv4mock.NewMockedHTTPClient(
310314
githubv4mock.NewQueryMatcher(
311315
struct {
@@ -367,6 +371,7 @@ func Test_ResolveProjectItemIDByIssueNumber_TargetOnSecondPage(t *testing.T) {
367371
"projectItems": map[string]any{
368372
"nodes": []any{
369373
map[string]any{
374+
"id": "PVTI_target",
370375
"fullDatabaseId": "4242",
371376
"project": map[string]any{"id": "PVT_project1"},
372377
},
@@ -385,8 +390,9 @@ func Test_ResolveProjectItemIDByIssueNumber_TargetOnSecondPage(t *testing.T) {
385390
)
386391
gql := githubv4.NewClient(mocked)
387392

388-
itemID, err := resolveProjectItemIDByIssueNumber(context.Background(), gql, "octo-org", "org", 1, "octo-issue-owner", "repo", 123)
393+
nodeID, itemID, err := resolveProjectItemByIssueNumber(context.Background(), gql, "octo-org", "org", 1, "octo-issue-owner", "repo", 123)
389394
require.NoError(t, err)
395+
assert.Equal(t, "PVTI_target", nodeID)
390396
assert.Equal(t, int64(4242), itemID)
391397
}
392398

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.