Skip to content

Commit 200d7b1

Browse files
committed
ci: add lint for tools/@aws-cdk/project-sync
1 parent 8aa3009 commit 200d7b1

File tree

9 files changed

+414
-198
lines changed

9 files changed

+414
-198
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
const baseConfig = require('@aws-cdk/cdk-build-tools/config/eslintrc');
2+
baseConfig.parserOptions.project = __dirname + '/tsconfig.json';
3+
4+
baseConfig.rules['import/no-extraneous-dependencies'] = ['error', { devDependencies: true, peerDependencies: true } ];
5+
baseConfig.rules['import/order'] = 'off';
6+
baseConfig.rules['@aws-cdk/invalid-cfn-imports'] = 'off';
7+
baseConfig.rules['@cdklabs/no-throw-default-error'] = ['error'];
8+
baseConfig.overrides.push({
9+
files: ["./test/**"],
10+
rules: {
11+
"@typescript-eslint/unbound-method": "off"
12+
},
13+
});
14+
baseConfig.rules['no-console'] = 'off'
15+
baseConfig.rules['@cdklabs/no-throw-default-error'] = 'off'
16+
17+
module.exports = baseConfig;

tools/@aws-cdk/project-sync/lib/github.ts

Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
export class Github {
2-
token: string
2+
token: string;
33

44
constructor(token: string) {
5-
this.token = token
5+
this.token = token;
66
}
77

88
async authGraphQL(query: string) {
@@ -12,11 +12,11 @@ export class Github {
1212
'Authorization': `token ${this.token}`,
1313
'Content-Type': 'application/json',
1414
},
15-
body: JSON.stringify({ query })
15+
body: JSON.stringify({ query }),
1616
});
1717

1818
if (!response.ok) {
19-
throw new Error(`GitHub GraphQL request failed: ${response.statusText}`);
19+
throw new Error(`GitHub GraphQL request failed: ${response.statusText}`, this);
2020
}
2121

2222
return response.json();
@@ -66,7 +66,7 @@ export class Github {
6666
}
6767
}
6868
}
69-
`)
69+
`);
7070
}
7171

7272
getIssue(issue: string) {
@@ -143,39 +143,23 @@ export class Github {
143143
}
144144
}
145145
}
146-
`)
146+
`);
147147
}
148148

149149
async setProjectItem(projectId: string, itemId: string, fields: Record<
150150
string,
151151
{date: Date} | {text: string} | {number: number} | {singleSelectOptionId: string} | {iterationId: string}
152152
>) {
153-
const results = []
153+
const results = [];
154154
for (const [key, value] of Object.entries(fields)) {
155-
console.log(`
155+
results.push(await this.authGraphQL(`
156156
mutation {
157157
updateProjectV2ItemFieldValue(
158158
input: {
159159
projectId: "${projectId}",
160160
itemId: "${itemId}",
161161
fieldId: "${key}",
162-
value: {${Object.entries(value).map(([key, value]) => `${key}: ${JSON.stringify(value)}`).join(',')}}
163-
}
164-
) {
165-
projectV2Item {
166-
id
167-
}
168-
}
169-
}
170-
`);
171-
results.push(this.authGraphQL(`
172-
mutation {
173-
updateProjectV2ItemFieldValue(
174-
input: {
175-
projectId: "${projectId}",
176-
itemId: "${itemId}",
177-
fieldId: "${key}",
178-
value: {${Object.entries(value).map(([key, value]) => `${key}: ${JSON.stringify(value)}`).join(',')}}
162+
value: {${Object.entries(value).map(([fieldKey, fieldValue]) => `${fieldKey}: ${JSON.stringify(fieldValue)}`).join(',')}}
179163
}
180164
) {
181165
projectV2Item {
@@ -185,6 +169,6 @@ export class Github {
185169
}
186170
`));
187171
}
188-
return Promise.all(results)
172+
return results;
189173
}
190-
}
174+
}
Lines changed: 73 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,93 +1,92 @@
1-
import {Github} from './github.js'
1+
import { Github } from './github.js';
22

33
export const getGithubClient = () => {
4-
if (!process.env.GITHUB_TOKEN) {
5-
throw new Error('GITHUB_TOKEN is not set')
6-
}
7-
return new Github(process.env.GITHUB_TOKEN)
8-
}
4+
if (!process.env.GITHUB_TOKEN) {
5+
throw new Error('GITHUB_TOKEN is not set');
6+
}
7+
return new Github(process.env.GITHUB_TOKEN);
8+
};
99

1010
export const PROJECT_ID = process.env.PROJECT_ID || '302';
1111

1212
export const syncIssue = async (issue: string) => {
13-
const github = getGithubClient()
14-
15-
// 1. Fetch the issue details
16-
const issueData = await github.getIssue(issue) as Record<any, any>;
17-
18-
// Extract repository data
19-
const repoData = issueData?.data?.repository;
20-
if (!repoData || !repoData.issue) {
21-
throw new Error(`Issue ${issue} not found`);
13+
const github = getGithubClient();
14+
15+
// 1. Fetch the issue details
16+
const issueData = await github.getIssue(issue) as Record<any, any>;
17+
18+
// Extract repository data
19+
const repoData = issueData?.data?.repository;
20+
if (!repoData || !repoData.issue) {
21+
throw new Error(`Issue ${issue} not found`);
22+
}
23+
24+
const issueDetails = repoData.issue;
25+
26+
// If issue is part of the project, set the issue's project properties
27+
let projectItemId = undefined;
28+
if (issueDetails.projectItems?.nodes) {
29+
for (const node of issueDetails.projectItems.nodes) {
30+
if (`${node.project?.number}` === PROJECT_ID) {
31+
projectItemId = node.id;
32+
break;
33+
}
2234
}
35+
}
2336

24-
const issueDetails = repoData.issue;
25-
26-
// If issue is part of the project, set the issue's project properties
27-
let projectItemId = undefined;
28-
if (issueDetails.projectItems?.nodes) {
29-
for (const node of issueDetails.projectItems.nodes) {
30-
if (`${node.project?.number}` === PROJECT_ID) {
31-
projectItemId = node.id;
32-
break;
33-
}
34-
}
35-
}
37+
if (projectItemId === undefined) {
38+
console.log('Issue is not included in project, skipping.');
39+
return;
40+
}
3641

37-
if(projectItemId === undefined){
38-
console.log('Issue is not included in project, skipping.')
39-
return;
40-
}
42+
const projectInfo = await github.getProjectInfo(PROJECT_ID);
43+
const projectId = projectInfo.data.repository.projectV2.id!;
4144

42-
const projectInfo = await github.getProjectInfo(PROJECT_ID);
43-
const projectId = projectInfo.data.repository.projectV2.id!
44-
45-
let creationFieldId = undefined;
46-
let updateFieldId = undefined;
47-
for(const field of projectInfo.data.repository.projectV2.fields.nodes){
48-
if(field.name === 'Creation date'){
49-
creationFieldId = field.id
50-
}
51-
if(field.name === 'Update date'){
52-
updateFieldId = field.id
53-
}
45+
let creationFieldId = undefined;
46+
let updateFieldId = undefined;
47+
for (const field of projectInfo.data.repository.projectV2.fields.nodes) {
48+
if (field.name === 'Creation date') {
49+
creationFieldId = field.id;
5450
}
55-
56-
if(creationFieldId === undefined){
57-
throw new Error('Project field "Creation date" not found')
51+
if (field.name === 'Update date') {
52+
updateFieldId = field.id;
5853
}
54+
}
5955

60-
if(updateFieldId === undefined){
61-
throw new Error('Project field "Update date" not found')
62-
}
56+
if (creationFieldId === undefined) {
57+
throw new Error('Project field "Creation date" not found');
58+
}
6359

64-
// Get timeline items to determine the last update date (excluding github-actions)
65-
const timelineItems = issueDetails.timelineItems?.nodes ?? [];
60+
if (updateFieldId === undefined) {
61+
throw new Error('Project field "Update date" not found');
62+
}
6663

67-
// Get creation date from the first reaction or use current date
68-
const creationDate = new Date(issueDetails.createdAt)
64+
// Get timeline items to determine the last update date (excluding github-actions)
65+
const timelineItems = issueDetails.timelineItems?.nodes ?? [];
6966

70-
// Get update date from the last timeline item or use creation date
71-
let updateDate = creationDate;
67+
// Get creation date from the first reaction or use current date
68+
const creationDate = new Date(issueDetails.createdAt);
7269

73-
for(let index = 0; index < timelineItems.length; index++){
74-
const item = timelineItems[timelineItems.length-index-1]
75-
if(item?.createdAt !== undefined && item.author?.login !== 'github-actions' && item.actor?.login !== 'github-actions'){
76-
updateDate = new Date(item.createdAt)
77-
break
78-
}
79-
}
70+
// Get update date from the last timeline item or use creation date
71+
let updateDate = creationDate;
8072

81-
if(issueDetails.reactions.nodes.length > 0) {
82-
const reactionDate = new Date(issueDetails.reactions.nodes[0].createdAt)
83-
if(reactionDate > updateDate)
84-
updateDate = reactionDate
73+
for (let index = 0; index < timelineItems.length; index++) {
74+
const item = timelineItems[timelineItems.length-index-1];
75+
if (item?.createdAt !== undefined && item.author?.login !== 'github-actions' && item.actor?.login !== 'github-actions') {
76+
updateDate = new Date(item.createdAt);
77+
break;
8578
}
86-
87-
const result = await github.setProjectItem(projectId, projectItemId, {
88-
[creationFieldId]: { date: creationDate },
89-
[updateFieldId]: { date: updateDate }
90-
});
91-
console.log('Result from mutation request: ')
92-
console.dir(JSON.stringify(result))
93-
}
79+
}
80+
81+
if (issueDetails.reactions.nodes.length > 0) {
82+
const reactionDate = new Date(issueDetails.reactions.nodes[0].createdAt);
83+
if (reactionDate > updateDate) {updateDate = reactionDate;}
84+
}
85+
86+
const result = await github.setProjectItem(projectId, projectItemId, {
87+
[creationFieldId]: { date: creationDate },
88+
[updateFieldId]: { date: updateDate },
89+
});
90+
console.log('Result from mutation request: ');
91+
console.dir(JSON.stringify(result));
92+
};

tools/@aws-cdk/project-sync/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"scripts": {
99
"build": "tsc --build",
1010
"build+test": "npm run build && npm run test",
11-
"lint": "eslint --ext .ts,.tsx --fix --no-error-on-unmatched-pattern src test",
11+
"lint": "eslint --ext .ts,.tsx --fix --no-error-on-unmatched-pattern lib bin test",
1212
"package": "mkdir -p dist/js && mv $(npm pack) dist/js/",
1313
"test": "jest --passWithNoTests --updateSnapshot --coverage=false",
1414
"test:watch": "jest --watch",
@@ -17,6 +17,7 @@
1717
},
1818
"devDependencies": {
1919
"@aws-cdk/cdk-build-tools": "0.0.0",
20+
"@jest/globals": "^30.0.0",
2021
"jest": "^29",
2122
"ts-jest": "^29.4.0",
2223
"typescript": "~5.5.4"
Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,34 @@
1-
import * as fs from 'node:fs/promises'
2-
import { join } from 'node:path'
1+
import * as fs from 'node:fs/promises';
2+
import { join } from 'node:path';
33

44
export class GithubMock {
5-
token: string
5+
token: string;
66

7-
constructor(token: string) {
8-
this.token = token
9-
}
7+
constructor(token: string) {
8+
this.token = token;
9+
}
1010

11-
authGraphQL(_query: string) : Promise<any> {
12-
throw Error('Not implemented in the mock.')
13-
}
11+
authGraphQL(_query: string) : Promise<any> {
12+
throw Error('Not implemented in the mock.');
13+
}
1414

15-
async getProjectInfo(_projectId: string) {
16-
return JSON.parse((await fs.readFile(join(__dirname, 'snapshots', 'get-project-info.json'))).toString())
17-
}
15+
async getProjectInfo(_projectId: string) {
16+
return JSON.parse((await fs.readFile(join(__dirname, 'snapshots', 'get-project-info.json'))).toString());
17+
}
1818

19-
async getIssue(issue: string) {
20-
return JSON.parse((await fs.readFile(join(__dirname, 'snapshots', 'get-issue', `${issue}.json`))).toString())
21-
}
22-
23-
async setProjectItem(_projectId: string, _itemId: string, _fields: Record<
24-
string,
19+
async getIssue(issue: string) {
20+
return JSON.parse((await fs.readFile(join(__dirname, 'snapshots', 'get-issue', `${issue}.json`))).toString());
21+
}
22+
23+
async setProjectItem(_projectId: string, _itemId: string, _fields: Record<
24+
string,
2525
{date: Date} | {text: string} | {number: number} | {singleSelectOptionId: string} | {iterationId: string}
26-
>): Promise<any> {
27-
// Mock implementation that just returns success
28-
return { success: true };
29-
}
26+
>): Promise<any> {
27+
// Mock implementation that just returns success
28+
return { success: true };
29+
}
3030

31-
queryIssues(_labels: string[], _state: 'OPEN' | 'CLOSED' | 'ALL' = 'OPEN', _cursor?: string): Promise<any> {
32-
throw Error('Not implemented in the mock.')
33-
}
34-
}
31+
queryIssues(_labels: string[], _state: 'OPEN' | 'CLOSED' | 'ALL' = 'OPEN', _cursor?: string): Promise<any> {
32+
throw Error('Not implemented in the mock.');
33+
}
34+
}

0 commit comments

Comments
 (0)