Skip to content

Commit ba257af

Browse files
committed
adds option to fetch issues with iteration fields (closes #66)
1 parent 10d02a0 commit ba257af

File tree

5 files changed

+247
-50
lines changed

5 files changed

+247
-50
lines changed

src/v1/adapters/github/graphql.ts

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import { Repository } from "./scopes";
1+
import { Iteration, Repository } from "./scopes";
22
import {
33
type GITHUB_REPOSITORY_SCOPES,
44
GITHUB_PROJECT_SCOPES,
55
type PageSize,
66
GRAMMATICAL_NUMBER,
77
type GITHUB_MILESTONE_ISSUE_STATES,
8+
GITHUB_ITERATION_SCOPES,
89
} from "./types";
910
import { DEV_MODE } from "../../../environment";
1011

@@ -24,7 +25,7 @@ export const GITHUB_QUOTA = `{
2425
export const Project = (
2526
project_name: string | number,
2627
project_scopes: GITHUB_PROJECT_SCOPES[],
27-
repository_query: string | null = null,
28+
child_query: string | null = null
2829
) => {
2930
const name_is_text = typeof project_name === "string";
3031
const head = name_is_text
@@ -47,9 +48,10 @@ export const Project = (
4748
readme
4849
` : ""}
4950
50-
${project_scopes.includes(GITHUB_PROJECT_SCOPES.REPOSITORIES_LINKED) &&
51-
repository_query
52-
? repository_query
51+
${(project_scopes.includes(GITHUB_PROJECT_SCOPES.REPOSITORIES_LINKED) ||
52+
project_scopes.includes(GITHUB_PROJECT_SCOPES.ITERATIONS)) &&
53+
child_query
54+
? child_query
5355
: ""
5456
}
5557
@@ -120,3 +122,31 @@ export const AccountScopeEntryRoot = (
120122

121123
return query;
122124
};
125+
126+
/**
127+
* Retrieves the iterations of a project.
128+
*
129+
* @param {string | number} project_name - The name or ID of the project.
130+
* @param {number} [pageSize=100] - The amount of iterations to fetch at once.
131+
* @param {string | null} [continueAfter=null] - The cursor to continue after.
132+
* @param {string} [iterationFieldName="Sprint"] - The name of the iteration field.
133+
* @param {GITHUB_ITERATION_SCOPES[]} [scopes=[GITHUB_ITERATION_SCOPES.INFO]] - The scopes of the iterations.
134+
*
135+
* @return {string} The generated GraphQL query.
136+
*/
137+
export const getProjectIterationIssues = (
138+
project_name: string | number,
139+
pageSize: number = 100,
140+
continueAfter: string | null = null,
141+
iterationFieldName: string = "Sprint",
142+
scopes: GITHUB_ITERATION_SCOPES[] = [GITHUB_ITERATION_SCOPES.INFO]
143+
) => {
144+
const iteration = new Iteration({
145+
pageSize,
146+
continueAfter,
147+
iterationFieldName,
148+
scopes
149+
});
150+
151+
return Project(project_name, [GITHUB_PROJECT_SCOPES.ITERATIONS], iteration.getQuery());
152+
};

src/v1/adapters/github/index.ts

Lines changed: 78 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
GITHUB_QUOTA,
1111
Project,
1212
getAllRepositoriesInProject,
13+
getProjectIterationIssues,
1314
} from "./graphql";
1415
import { fetchGithubDataUsingGraphql, fetchRateLimit } from "./functions/fetch";
1516
import { createPinoLogger } from "@bogeychan/elysia-logger";
@@ -18,6 +19,7 @@ import { guardEndpoints } from "../plugins";
1819
import {
1920
GITHUB_ACCOUNT_SCOPES,
2021
GITHUB_AUTHENTICATION_STRATEGY_OPTIONS,
22+
GITHUB_ITERATION_SCOPES,
2123
GITHUB_MILESTONE_ISSUE_STATES,
2224
GITHUB_PROJECT_SCOPES,
2325
GITHUB_REPOSITORY_SCOPES,
@@ -26,6 +28,7 @@ import {
2628
} from "../github/types";
2729
import {
2830
GITHUB_ACCOUNT_PARAMS,
31+
GITHUB_ITERATION_PARAMS,
2932
GITHUB_PROJECT_PARAMS,
3033
GITHUB_REPOSITORY_PARAMS,
3134
} from "./params";
@@ -50,17 +53,17 @@ export const GITHUB_APP_WEBHOOKS = new Elysia({ prefix: "/webhooks" }).post(
5053
"",
5154
async (ctx) => {
5255
const child = log.child(ctx);
53-
if (DEV_MODE) child.info("webhook received");
54-
56+
if (DEV_MODE) child.info("webhook received");
57+
5558
const eventType = ctx.headers["x-github-event"] as keyof WebhookEventMap;
56-
59+
5760
if (eventType === "projects_v2_item") {
5861
if (DEV_MODE) log.info("projects_v2_item webhook received");
5962

6063
const payload = ctx.body as ProjectsV2ItemEvent;
61-
64+
6265
if (
63-
(payload.action === "edited" || payload.action === "created" || payload.action === "converted" || payload.action === "restored") &&
66+
(payload.action === "edited" || payload.action === "created" || payload.action === "converted" || payload.action === "restored") &&
6467
"changes" in payload &&
6568
"field_value" in payload.changes &&
6669
payload.changes?.field_value?.field_type === "iteration" &&
@@ -69,8 +72,8 @@ export const GITHUB_APP_WEBHOOKS = new Elysia({ prefix: "/webhooks" }).post(
6972
) {
7073
const octokit = await getOctokitObject(
7174
GITHUB_AUTHENTICATION_STRATEGY_OPTIONS.APP,
72-
payload.installation.id,
73-
ctx.set
75+
payload.installation.id,
76+
ctx.set
7477
);
7578

7679
const fieldValue = await octokit.graphql(`
@@ -93,19 +96,19 @@ export const GITHUB_APP_WEBHOOKS = new Elysia({ prefix: "/webhooks" }).post(
9396

9497
const result = await handleProjectItemChange(octokit, {
9598
id: payload.projects_v2_item.node_id,
96-
content: {
99+
content: {
97100
id: payload.projects_v2_item.content_node_id
98101
},
99102
fieldValues: {
100103
nodes: [{
101-
field: {
104+
field: {
102105
name: "Sprint"
103106
},
104107
value: fieldValue.node.fieldValueByName?.title || null
105108
}]
106109
},
107110
});
108-
111+
109112
if (DEV_MODE) child.info({ result }, '[Sprint Label Mutation]');
110113
}
111114
}
@@ -115,11 +118,11 @@ export const GITHUB_APP_WEBHOOKS = new Elysia({ prefix: "/webhooks" }).post(
115118
return ctx.body;
116119
},
117120
{
118-
detail: {
119-
description:
120-
"Receives a webhook event of the changes that happened in the scopes that this microservice is subscribed to, on your GitHub-App installation.",
121-
tags: ["github", "webhooks"],
122-
},
121+
detail: {
122+
description:
123+
"Receives a webhook event of the changes that happened in the scopes that this microservice is subscribed to, on your GitHub-App installation.",
124+
tags: ["github", "webhooks"],
125+
},
123126
},
124127
);
125128

@@ -428,6 +431,65 @@ const ACCOUNT_LEVEL_CHILDREN = (login_type: "organization" | "user") =>
428431
},
429432
)
430433

434+
/**
435+
* Request project iteration issues
436+
*/
437+
.get(
438+
"/iterations/issues",
439+
async ({ fetchParams, params: { login_name, project_id_or_name }, query, set }) => {
440+
const response = await fetchGithubDataUsingGraphql<{
441+
organization?: { projectV2: ProjectV2 };
442+
user?: { projectV2: ProjectV2 };
443+
}>(
444+
AccountScopeEntryRoot(
445+
login_name,
446+
getProjectIterationIssues(
447+
project_id_or_name,
448+
query.pageSize,
449+
query.continueAfter,
450+
query.iterationFieldName,
451+
(query.scopes?.split(",") ?? []) as GITHUB_ITERATION_SCOPES[]
452+
),
453+
login_type
454+
),
455+
fetchParams.auth,
456+
set,
457+
fetchParams.auth_type,
458+
);
459+
460+
const user = FETCH_PROJECTS_FROM_ORGANIZATION ? "organization" : "user";
461+
if (response?.data && user in response.data && response.data[user]?.projectV2) {
462+
const items = response.data[user].projectV2.items;
463+
// Property 'state' does not exist on type 'DraftIssue | Issue | PullRequest'. -> This is not typed correctly...
464+
// @ts-ignore
465+
const openNodes = items?.nodes?.filter(node => node?.content?.state === 'OPEN') ?? [];
466+
// @ts-ignore
467+
const closedNodes = items?.nodes?.filter(node => node?.content?.state === 'CLOSED') ?? [];
468+
469+
response.data[user].projectV2.items = {
470+
totalCount: items.totalCount,
471+
pageInfo: items.pageInfo,
472+
open_issues: { nodes: openNodes },
473+
closed_issues: { nodes: closedNodes }
474+
} as any;
475+
}
476+
477+
return response;
478+
},
479+
{
480+
query: t.Object({
481+
pageSize: t.Optional(t.Numeric({ minimum: 1, maximum: 100 })),
482+
continueAfter: t.Optional(t.String()),
483+
iterationFieldName: t.Optional(t.String()),
484+
scopes: t.Optional(t.String()) // t.Optional(t.Array(t.Enum(GITHUB_ITERATION_SCOPES)))
485+
}),
486+
detail: {
487+
description: `Request project iteration issues for ${login_type}. Scopes: ${GITHUB_ITERATION_PARAMS} (/projects/{project_id}/iteration/issues?iteration_field_name=Sprint).`,
488+
tags: ["github"],
489+
},
490+
},
491+
)
492+
431493
/**
432494
* Request repositories only in the account project. No infos.
433495
*/
@@ -1476,7 +1538,7 @@ const ACCOUNT_LEVEL_CHILDREN = (login_type: "organization" | "user") =>
14761538
},
14771539
},
14781540
),
1479-
),
1541+
),
14801542
),
14811543
),
14821544
),

src/v1/adapters/github/params.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
GITHUB_ACCOUNT_SCOPES,
3+
GITHUB_ITERATION_SCOPES,
34
GITHUB_PROJECT_SCOPES,
45
GITHUB_REPOSITORY_SCOPES,
56
} from "./types";
@@ -13,3 +14,6 @@ export const GITHUB_PROJECT_PARAMS = JSON.stringify(
1314
export const GITHUB_REPOSITORY_PARAMS = JSON.stringify(
1415
Object.values(GITHUB_REPOSITORY_SCOPES),
1516
);
17+
export const GITHUB_ITERATION_PARAMS = JSON.stringify(
18+
Object.values(GITHUB_ITERATION_SCOPES),
19+
);

0 commit comments

Comments
 (0)