Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions tools/@aws-cdk/project-sync/lib/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ const issueQuery = `
author {
login
}
labels(first: 32) {
nodes {
name
}
}
timelineItems(last: 16) {
nodes{
... on IssueComment {
Expand Down Expand Up @@ -78,6 +83,11 @@ const prQuery = `
author {
login
}
labels(first: 32) {
nodes {
name
}
}
timelineItems(last: 16) {
nodes {
... on PullRequestCommit {
Expand Down Expand Up @@ -242,6 +252,14 @@ export class Github {
id
fields(first: 100) {
nodes {
... on ProjectV2SingleSelectField {
id
name
options {
name
id
}
}
... on ProjectV2Field {
id
name
Expand Down
15 changes: 11 additions & 4 deletions tools/@aws-cdk/project-sync/lib/issue-sync.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Github } from './github.js';
import { PROJECT_NUMBER, REPOSITORY } from './config.js';
import { projectIds } from './utils.js';
import { projectIds, getPriorityFromLabels } from './utils.js';

export const syncIssue = async (issue: string) => {
const github = Github.default();
Expand Down Expand Up @@ -36,7 +36,7 @@ export const syncIssueData = async (issueDetails: any) => {
return;
}

const { projectId, createFieldId, updateFieldId, authorFieldId } = await projectIds(github);
const { projectId, createFieldId, updateFieldId, authorFieldId, priorityField } = await projectIds(github);

// Get timeline items to determine the last update date (excluding github-actions)
const timelineItems = issueDetails.timelineItems?.nodes ?? [];
Expand All @@ -60,11 +60,18 @@ export const syncIssueData = async (issueDetails: any) => {
if (reactionDate > updateDate) {updateDate = reactionDate;}
}

const result = await github.setProjectItem(projectId, projectItemId, {
const fields: Record<string, any> = {
[createFieldId]: { date: creationDate },
[updateFieldId]: { date: updateDate },
[authorFieldId]: { text: issueDetails.author?.login || '' },
});
};

const priorityOptionId = getPriorityFromLabels(issueDetails.labels?.nodes || [], priorityField);
if (priorityOptionId) {
fields[priorityField.id] = { singleSelectOptionId: priorityOptionId };
}

const result = await github.setProjectItem(projectId, projectItemId, fields);
console.log('Result from mutation request: ');
console.dir(JSON.stringify(result));
};
15 changes: 11 additions & 4 deletions tools/@aws-cdk/project-sync/lib/pr-sync.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Github } from './github.js';
import { PROJECT_NUMBER, REPOSITORY } from './config.js';
import { projectIds } from './utils.js';
import { projectIds, getPriorityFromLabels } from './utils.js';

export const syncPr = async (pr: string) => {
const github = Github.default();
Expand Down Expand Up @@ -36,7 +36,7 @@ export const syncPrData = async (prDetails: any) => {
return;
}

const { projectId, createFieldId, updateFieldId, authorFieldId } = await projectIds(github);
const { projectId, createFieldId, updateFieldId, authorFieldId, priorityField } = await projectIds(github);

// Get timeline items to determine the last update date (excluding github-actions)
const timelineItems = prDetails.timelineItems?.nodes ?? [];
Expand All @@ -60,11 +60,18 @@ export const syncPrData = async (prDetails: any) => {
if (reactionDate > updateDate) {updateDate = reactionDate;}
}

const result = await github.setProjectItem(projectId, projectItemId, {
const fields: Record<string, any> = {
[createFieldId]: { date: creationDate },
[updateFieldId]: { date: updateDate },
[authorFieldId]: { text: prDetails.author?.login || '' },
});
};

const priorityOptionId = getPriorityFromLabels(prDetails.labels?.nodes || [], priorityField);
if (priorityOptionId) {
fields[priorityField.id] = { singleSelectOptionId: priorityOptionId };
}

const result = await github.setProjectItem(projectId, projectItemId, fields);
console.log('Result from mutation request: ');
console.dir(JSON.stringify(result));
};
2 changes: 2 additions & 0 deletions tools/@aws-cdk/project-sync/lib/sync-all.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export async function syncAll() {
console.log(`Processing issue #${issueNumber}: ${issue.title}`);

try {
await new Promise(resolve => setTimeout(resolve, 500));
await syncIssueData(issue);
console.log(`Successfully synced issue #${issueNumber}`);
} catch (error) {
Expand All @@ -57,6 +58,7 @@ export async function syncAll() {
console.log(`Processing PR #${prNumber}: ${pr.title}`);

try {
await new Promise(resolve => setTimeout(resolve, 500));
await syncPrData(pr);
console.log(`Successfully synced PR #${prNumber}`);
} catch (error) {
Expand Down
60 changes: 60 additions & 0 deletions tools/@aws-cdk/project-sync/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,39 @@
import { PROJECT_NUMBER } from './config';
import { Github } from './github';

export const PRIORITIES = {
p0: 'P0',
p1: 'P1',
p2: 'P2',
p3: 'P3',
};

export const projectIds = async (github: Github) : Promise<{
projectId: string;
createFieldId: string;
updateFieldId: string;
authorFieldId: string;
priorityField: {
id: string;
options: Record<keyof typeof PRIORITIES, string>;
};
}> => {
const projectInfo = await github.getProjectInfo(PROJECT_NUMBER);
const projectId = projectInfo.data.repository.projectV2.id!;

let createFieldId = undefined;
let updateFieldId = undefined;
let authorFieldId = undefined;
let priorityField = {
id: undefined,
options: {
p0: undefined,
p1: undefined,
p2: undefined,
p3: undefined,
},
};

for (const field of projectInfo.data.repository.projectV2.fields.nodes) {
if (field.name === 'Create date') {
createFieldId = field.id;
Expand All @@ -23,6 +44,24 @@ export const projectIds = async (github: Github) : Promise<{
if (field.name === 'Item author') {
authorFieldId = field.id;
}
if (field.name === 'Priority') {
priorityField.id = field.id;
for (const option of field.options) {
switch (option.name) {
case 'P0':
priorityField.options.p0 = option.id;
break;
case 'P1':
priorityField.options.p1 = option.id;
break;
case 'P2':
priorityField.options.p2 = option.id;
break;
case 'P3':
priorityField.options.p3 = option.id;
}
}
}
}

if (createFieldId === undefined) {
Expand All @@ -37,10 +76,31 @@ export const projectIds = async (github: Github) : Promise<{
throw new Error('Project field "Item author" not found');
}

if (priorityField.id === undefined) {
throw new Error('Project field "Priority" not found');
}

for (const [priorityLabel, priorityProjectLabel] of Object.entries(PRIORITIES)) {
if (priorityField.options[priorityLabel as keyof typeof PRIORITIES] === undefined) {
throw new Error(`Project field "Priority" does not have a "${priorityProjectLabel}" option.`);
}
}

return {
projectId,
createFieldId,
updateFieldId,
authorFieldId,
priorityField: priorityField as any,
};
};

export const getPriorityFromLabels = (labels: any[], priorityField: { options: Record<keyof typeof PRIORITIES, string> }): string | undefined => {
for (const label of labels) {
const labelName = label.name.toLowerCase();
if (labelName in PRIORITIES && priorityField.options[labelName as keyof typeof PRIORITIES]) {
return priorityField.options[labelName as keyof typeof PRIORITIES];
}
}
return undefined;
};
5 changes: 4 additions & 1 deletion tools/@aws-cdk/project-sync/test/issue-sync.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ describe('Issue Sync', () => {
PVTF_lADOACIPmc4A7TlPzgvqxXA: { date: new Date('2021-08-04T15:40:27Z') },
PVTF_lADOACIPmc4A7TlPzgv350s: { date: new Date('2025-06-30T15:47:05Z') },
PVTF_lADOACIPmc4A7TlPzgyBz60: { text: 'naseemkullah' },
PVTSSF_lADOACIPmc4A7TlPzgvpNe8: { singleSelectOptionId: '0a877460' },
});
});

Expand All @@ -43,8 +44,9 @@ describe('Issue Sync', () => {
// and the expected creation and update dates
expect(mockGithub.setProjectItem).toHaveBeenCalledWith('PVT_kwDOACIPmc4A7TlP', 'PVTI_lADOACIPmc4A7TlPzgbamKo', {
PVTF_lADOACIPmc4A7TlPzgvqxXA: { date: new Date('2024-07-09T08:10:25Z') },
PVTF_lADOACIPmc4A7TlPzgv350s: { date: new Date('2025-07-08T15:43:28Z') },
PVTF_lADOACIPmc4A7TlPzgv350s: { date: new Date('2025-07-25T16:56:19Z') },
PVTF_lADOACIPmc4A7TlPzgyBz60: { text: 'greg5123334' },
PVTSSF_lADOACIPmc4A7TlPzgvpNe8: { singleSelectOptionId: '0a877460' },
});
});

Expand All @@ -60,6 +62,7 @@ describe('Issue Sync', () => {
PVTF_lADOACIPmc4A7TlPzgvqxXA: { date: new Date('2025-01-28T09:56:52Z') },
PVTF_lADOACIPmc4A7TlPzgv350s: { date: new Date('2025-06-12T16:00:02Z') },
PVTF_lADOACIPmc4A7TlPzgyBz60: { text: 'aubsamai' },
PVTSSF_lADOACIPmc4A7TlPzgvpNe8: { singleSelectOptionId: '0a877460' },
});
});

Expand Down
5 changes: 4 additions & 1 deletion tools/@aws-cdk/project-sync/test/pr-sync.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,11 @@ describe('PR Sync', () => {
// and the expected creation and update dates
expect(mockGithub.setProjectItem).toHaveBeenCalledWith('PVT_kwDOACIPmc4A7TlP', 'PVTI_lADOACIPmc4A7TlPzgceg5g', {
PVTF_lADOACIPmc4A7TlPzgvqxXA: { date: new Date('2025-07-11T04:45:56Z') },
PVTF_lADOACIPmc4A7TlPzgv350s: { date: new Date('2025-07-19T01:34:52Z') },
PVTF_lADOACIPmc4A7TlPzgv350s: { date: new Date('2025-08-07T06:44:13Z') },
PVTF_lADOACIPmc4A7TlPzgyBz60: { text: 'badmintoncryer' },
PVTSSF_lADOACIPmc4A7TlPzgvpNe8: {
singleSelectOptionId: 'da944a9c',
},
});
});
});
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"data":{"repository":{"issue":{"createdAt":"2021-08-04T15:40:27Z","author":{"login":"naseemkullah"},"timelineItems":{"nodes":[{},{},{"createdAt":"2025-05-01T13:54:36Z","author":{"login":"hassanazharkhan"}},{"createdAt":"2025-05-01T14:18:48Z","author":{"login":"hassanazharkhan"}},{"createdAt":"2025-05-01T15:49:47Z","author":{"login":"chase-robbins"}},{"createdAt":"2025-05-01T22:14:06Z","author":{"login":"SimonCMoore"}},{},{"createdAt":"2025-05-02T15:55:16Z","author":{"login":"dgcole"}},{"createdAt":"2025-06-27T13:16:35Z","actor":{"login":"Abogical"}},{},{"createdAt":"2025-06-30T15:47:05Z","actor":{"login":"Abogical"}},{},{},{},{},{}]},"reactions":{"nodes":[{"createdAt":"2025-05-01T18:36:05Z"}]},"projectItems":{"nodes":[{"id":"PVTI_lADOACIPmc4AFShhzgCNksA","project":{"number":65}},{"id":"PVTI_lADOACIPmc4A7TlPzgbanR8","project":{"number":302}}]}}}}}
{"data":{"repository":{"issue":{"createdAt":"2021-08-04T15:40:27Z","author":{"login":"naseemkullah"},"labels":{"nodes":[{"name":"bug"},{"name":"p1"},{"name":"@aws-cdk/aws-cloudfront"},{"name":"@aws-cdk/aws-s3-deployment"}]},"timelineItems":{"nodes":[{"createdAt":"2025-05-01T13:54:36Z","author":{"login":"hassanazharkhan"}},{"createdAt":"2025-05-01T14:18:48Z","author":{"login":"hassanazharkhan"}},{"createdAt":"2025-05-01T15:49:47Z","author":{"login":"chase-robbins"}},{"createdAt":"2025-05-01T22:14:06Z","author":{"login":"SimonCMoore"}},{},{"createdAt":"2025-05-02T15:55:16Z","author":{"login":"dgcole"}},{"createdAt":"2025-06-27T13:16:35Z","actor":{"login":"Abogical"}},{},{"createdAt":"2025-06-30T15:47:05Z","actor":{"login":"Abogical"}},{},{},{},{},{},{},{}]},"reactions":{"nodes":[{"createdAt":"2025-05-01T18:36:05Z"}]},"projectItems":{"nodes":[{"id":"PVTI_lADOACIPmc4AFShhzgCNksA","project":{"number":65}},{"id":"PVTI_lADOACIPmc4A7TlPzgbanR8","project":{"number":302}}]}}}}}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"data":{"repository":{"issue":{"createdAt":"2024-07-09T08:10:25Z","author":{"login":"greg5123334"},"timelineItems":{"nodes":[{"createdAt":"2025-03-26T23:22:30Z","author":{"login":"pahud"}},{"createdAt":"2025-03-26T23:22:37Z","actor":{"login":"pahud"}},{"createdAt":"2025-03-26T23:22:42Z","actor":{"login":"pahud"}},{"createdAt":"2025-04-02T09:25:32Z","author":{"login":"TheHolyWaffle"}},{},{},{},{},{},{},{"createdAt":"2025-05-09T22:39:35Z","actor":{"login":"QuantumNeuralCoder"}},{},{},{"createdAt":"2025-06-19T08:38:33Z","author":{"login":"Reiss-Cashmore"}},{"createdAt":"2025-07-08T15:43:28Z","author":{"login":"CharlesJones88"}},{}]},"reactions":{"nodes":[{"createdAt":"2025-07-07T08:56:57Z"}]},"projectItems":{"nodes":[{"id":"PVTI_lADOACIPmc4Av_32zgYvp8Y","project":{"number":263}},{"id":"PVTI_lADOACIPmc4A7TlPzgbamKo","project":{"number":302}}]}}}}}
{"data":{"repository":{"issue":{"createdAt":"2024-07-09T08:10:25Z","author":{"login":"greg5123334"},"labels":{"nodes":[{"name":"bug"},{"name":"p1"},{"name":"@aws-cdk/aws-dynamodb"},{"name":"effort/small"}]},"timelineItems":{"nodes":[{"createdAt":"2025-03-26T23:22:42Z","actor":{"login":"pahud"}},{"createdAt":"2025-04-02T09:25:32Z","author":{"login":"TheHolyWaffle"}},{},{},{},{},{},{},{"createdAt":"2025-05-09T22:39:35Z","actor":{"login":"QuantumNeuralCoder"}},{},{},{"createdAt":"2025-06-19T08:38:33Z","author":{"login":"Reiss-Cashmore"}},{"createdAt":"2025-07-08T15:43:28Z","author":{"login":"CharlesJones88"}},{},{"createdAt":"2025-07-25T16:56:19Z","actor":{"login":"pahud"}},{}]},"reactions":{"nodes":[{"createdAt":"2025-07-24T15:18:18Z"}]},"projectItems":{"nodes":[{"id":"PVTI_lADOACIPmc4Av_32zgYvp8Y","project":{"number":263}},{"id":"PVTI_lADOACIPmc4A7TlPzgbamKo","project":{"number":302}}]}}}}}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"data":{"repository":{"issue":{"createdAt":"2025-01-28T09:56:52Z","author":{"login":"aubsamai"},"timelineItems":{"nodes":[{"createdAt":"2025-05-20T14:07:47Z","author":{"login":"kumsmrit"}},{},{},{"createdAt":"2025-05-22T07:56:17Z","actor":{"login":"kumsmrit"}},{"createdAt":"2025-05-26T14:55:04Z","actor":{"login":"kumsmrit"}},{"createdAt":"2025-05-26T16:05:58Z","author":{"login":"github-actions"}},{"createdAt":"2025-05-26T16:05:59Z","actor":{"login":"github-actions"}},{},{"createdAt":"2025-05-31T20:05:40Z","actor":{"login":"github-actions"}},{"createdAt":"2025-05-31T20:21:39Z","actor":{"login":"github-actions"}},{"createdAt":"2025-06-12T16:00:02Z","actor":{"login":"kumsmrit"}},{"createdAt":"2025-06-12T16:06:30Z","author":{"login":"github-actions"}},{"createdAt":"2025-06-12T16:06:30Z","actor":{"login":"github-actions"}},{"createdAt":"2025-06-17T16:06:43Z","actor":{"login":"github-actions"}},{"createdAt":"2025-06-17T16:06:43Z","actor":{"login":"github-actions"}},{"createdAt":"2025-06-17T16:06:44Z","actor":{"login":"github-actions"}}]},"reactions":{"nodes":[]},"projectItems":{"nodes":[{"id":"PVTI_lADOACIPmc4AaumQzgWws_M","project":{"number":179}},{"id":"PVTI_lADOACIPmc4AbZkFzgWyTLQ","project":{"number":189}},{"id":"PVTI_lADOACIPmc4Av_32zgazLYE","project":{"number":263}},{"id":"PVTI_lADOACIPmc4A7TlPzgbamBo","project":{"number":302}}]}}}}}
{"data":{"repository":{"issue":{"createdAt":"2025-01-28T09:56:52Z","author":{"login":"aubsamai"},"labels":{"nodes":[{"name":"bug"},{"name":"p1"},{"name":"@aws-cdk/core"},{"name":"response-requested"},{"name":"effort/small"},{"name":"closed-for-staleness"}]},"timelineItems":{"nodes":[{"createdAt":"2025-05-20T14:07:47Z","author":{"login":"kumsmrit"}},{},{},{"createdAt":"2025-05-22T07:56:17Z","actor":{"login":"kumsmrit"}},{"createdAt":"2025-05-26T14:55:04Z","actor":{"login":"kumsmrit"}},{"createdAt":"2025-05-26T16:05:58Z","author":{"login":"github-actions"}},{"createdAt":"2025-05-26T16:05:59Z","actor":{"login":"github-actions"}},{},{"createdAt":"2025-05-31T20:05:40Z","actor":{"login":"github-actions"}},{"createdAt":"2025-05-31T20:21:39Z","actor":{"login":"github-actions"}},{"createdAt":"2025-06-12T16:00:02Z","actor":{"login":"kumsmrit"}},{"createdAt":"2025-06-12T16:06:30Z","author":{"login":"github-actions"}},{"createdAt":"2025-06-12T16:06:30Z","actor":{"login":"github-actions"}},{"createdAt":"2025-06-17T16:06:43Z","actor":{"login":"github-actions"}},{"createdAt":"2025-06-17T16:06:43Z","actor":{"login":"github-actions"}},{"createdAt":"2025-06-17T16:06:44Z","actor":{"login":"github-actions"}}]},"reactions":{"nodes":[]},"projectItems":{"nodes":[{"id":"PVTI_lADOACIPmc4AaumQzgWws_M","project":{"number":179}},{"id":"PVTI_lADOACIPmc4AbZkFzgWyTLQ","project":{"number":189}},{"id":"PVTI_lADOACIPmc4Av_32zgazLYE","project":{"number":263}},{"id":"PVTI_lADOACIPmc4A7TlPzgbamBo","project":{"number":302}}]}}}}}
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"data":{"repository":{"issue":{"createdAt":"2018-06-05T20:35:30Z","author":{"login":"eladb"},"timelineItems":{"nodes":[{"createdAt":"2018-12-17T08:09:41Z","actor":{"login":"eladb"}},{"createdAt":"2019-01-03T23:48:22Z","actor":{"login":"srchase"}},{"createdAt":"2019-03-04T08:12:57Z","actor":{"login":"eladb"}},{"createdAt":"2019-08-12T15:53:17Z","actor":{"login":"fulghum"}},{"createdAt":"2019-10-02T17:51:47Z","author":{"login":"eladb"}},{"createdAt":"2020-02-03T22:56:35Z","actor":{"login":"shivlaks"}},{"createdAt":"2020-08-26T07:08:59Z","actor":{"login":"shivlaks"}},{"createdAt":"2021-01-25T16:13:39Z","actor":{"login":"NGL321"}},{"createdAt":"2021-01-25T16:13:39Z","actor":{"login":"NGL321"}},{"createdAt":"2021-06-17T15:34:14Z","actor":{"login":"ericzbeard"}},{"createdAt":"2022-06-17T16:05:02Z","author":{"login":"github-actions"}},{"createdAt":"2022-06-17T16:05:03Z","actor":{"login":"github-actions"}},{"createdAt":"2022-06-22T16:05:26Z","actor":{"login":"github-actions"}},{"createdAt":"2022-06-22T16:05:26Z","actor":{"login":"github-actions"}},{"createdAt":"2022-06-22T16:05:27Z","actor":{"login":"github-actions"}},{"createdAt":"2024-06-24T14:05:46Z","actor":{"login":"waltervargas"}}]},"reactions":{"nodes":[]},"projectItems":{"nodes":[]}}}}}
{"data":{"repository":{"issue":{"createdAt":"2018-06-05T20:35:30Z","author":{"login":"eladb"},"labels":{"nodes":[{"name":"p1"},{"name":"feature-request"},{"name":"package/tools"},{"name":"effort/large"},{"name":"closed-for-staleness"}]},"timelineItems":{"nodes":[{"createdAt":"2018-12-17T08:09:41Z","actor":{"login":"eladb"}},{"createdAt":"2019-01-03T23:48:22Z","actor":{"login":"srchase"}},{"createdAt":"2019-03-04T08:12:57Z","actor":{"login":"eladb"}},{"createdAt":"2019-08-12T15:53:17Z","actor":{"login":"fulghum"}},{"createdAt":"2019-10-02T17:51:47Z","author":{"login":"eladb"}},{"createdAt":"2020-02-03T22:56:35Z","actor":{"login":"shivlaks"}},{"createdAt":"2020-08-26T07:08:59Z","actor":{"login":"shivlaks"}},{"createdAt":"2021-01-25T16:13:39Z","actor":{"login":"NGL321"}},{"createdAt":"2021-01-25T16:13:39Z","actor":{"login":"NGL321"}},{"createdAt":"2021-06-17T15:34:14Z","actor":{"login":"ericzbeard"}},{"createdAt":"2022-06-17T16:05:02Z","author":{"login":"github-actions"}},{"createdAt":"2022-06-17T16:05:03Z","actor":{"login":"github-actions"}},{"createdAt":"2022-06-22T16:05:26Z","actor":{"login":"github-actions"}},{"createdAt":"2022-06-22T16:05:26Z","actor":{"login":"github-actions"}},{"createdAt":"2022-06-22T16:05:27Z","actor":{"login":"github-actions"}},{"createdAt":"2024-06-24T14:05:46Z","actor":{"login":"waltervargas"}}]},"reactions":{"nodes":[]},"projectItems":{"nodes":[]}}}}}
Loading
Loading