Skip to content

Commit cddd3c3

Browse files
authored
feat: use regex to extract all checksuite attributes (#849)
* feat: use regex to extract all checksuite attributes * feat: use regex to extract all checksuite attributes * feat: use regex to extract all checksuite attributes
1 parent e9cacd5 commit cddd3c3

File tree

3 files changed

+102
-29
lines changed

3 files changed

+102
-29
lines changed

src/typesGithub.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,3 +211,11 @@ export interface DiscussionSubcommentEdge {
211211
createdAt: string;
212212
};
213213
}
214+
215+
export interface CheckSuiteAttributes {
216+
workflowName: string;
217+
attemptNumber?: number;
218+
statusDisplayName: string;
219+
status: CheckSuiteStatus | null;
220+
branchName: string;
221+
}

src/utils/state.test.ts

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import nock from 'nock';
44
import { mockAccounts } from '../__mocks__/mock-state';
55
import { mockedSingleNotification } from '../__mocks__/mockedData';
66
import {
7-
getCheckSuiteState,
7+
getCheckSuiteAttributes,
88
getDiscussionState,
99
getIssueState,
1010
getPullRequestState,
@@ -26,9 +26,12 @@ describe('utils/state.ts', () => {
2626
},
2727
};
2828

29-
const result = getCheckSuiteState(mockNotification);
29+
const result = getCheckSuiteAttributes(mockNotification);
3030

31-
expect(result).toBe('cancelled');
31+
expect(result.workflowName).toBe('Demo');
32+
expect(result.attemptNumber).toBeNull();
33+
expect(result.status).toBe('cancelled');
34+
expect(result.branchName).toBe('main');
3235
});
3336

3437
it('failed check suite state', async () => {
@@ -40,9 +43,29 @@ describe('utils/state.ts', () => {
4043
},
4144
};
4245

43-
const result = getCheckSuiteState(mockNotification);
46+
const result = getCheckSuiteAttributes(mockNotification);
4447

45-
expect(result).toBe('failure');
48+
expect(result.workflowName).toBe('Demo');
49+
expect(result.attemptNumber).toBeNull();
50+
expect(result.status).toBe('failure');
51+
expect(result.branchName).toBe('main');
52+
});
53+
54+
it('multiple attempts failed check suite state', async () => {
55+
const mockNotification = {
56+
...mockedSingleNotification,
57+
subject: {
58+
...mockedSingleNotification.subject,
59+
title: 'Demo workflow run, Attempt #3 failed for main branch',
60+
},
61+
};
62+
63+
const result = getCheckSuiteAttributes(mockNotification);
64+
65+
expect(result.workflowName).toBe('Demo');
66+
expect(result.attemptNumber).toBe(3);
67+
expect(result.status).toBe('failure');
68+
expect(result.branchName).toBe('main');
4669
});
4770

4871
it('skipped check suite state', async () => {
@@ -54,9 +77,12 @@ describe('utils/state.ts', () => {
5477
},
5578
};
5679

57-
const result = getCheckSuiteState(mockNotification);
80+
const result = getCheckSuiteAttributes(mockNotification);
5881

59-
expect(result).toBe('skipped');
82+
expect(result.workflowName).toBe('Demo');
83+
expect(result.attemptNumber).toBeNull();
84+
expect(result.status).toBe('skipped');
85+
expect(result.branchName).toBe('main');
6086
});
6187

6288
it('successful check suite state', async () => {
@@ -68,21 +94,41 @@ describe('utils/state.ts', () => {
6894
},
6995
};
7096

71-
const result = getCheckSuiteState(mockNotification);
97+
const result = getCheckSuiteAttributes(mockNotification);
7298

73-
expect(result).toBe('success');
99+
expect(result.workflowName).toBe('Demo');
100+
expect(result.attemptNumber).toBeNull();
101+
expect(result.status).toBe('success');
102+
expect(result.branchName).toBe('main');
74103
});
75104

76105
it('unknown check suite state', async () => {
77106
const mockNotification = {
78107
...mockedSingleNotification,
79108
subject: {
80109
...mockedSingleNotification.subject,
81-
title: 'Demo workflow run for main branch',
110+
title: 'Demo workflow run unknown-status for main branch',
111+
},
112+
};
113+
114+
const result = getCheckSuiteAttributes(mockNotification);
115+
116+
expect(result.workflowName).toBe('Demo');
117+
expect(result.attemptNumber).toBeNull();
118+
expect(result.status).toBeNull();
119+
expect(result.branchName).toBe('main');
120+
});
121+
122+
it('unhandled check suite title', async () => {
123+
const mockNotification = {
124+
...mockedSingleNotification,
125+
subject: {
126+
...mockedSingleNotification.subject,
127+
title: 'A title that is not in the structure we expect',
82128
},
83129
};
84130

85-
const result = getCheckSuiteState(mockNotification);
131+
const result = getCheckSuiteAttributes(mockNotification);
86132

87133
expect(result).toBeNull();
88134
});

src/utils/state.ts

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { formatSearchQueryString } from './helpers';
22
import {
3+
CheckSuiteAttributes,
34
CheckSuiteStatus,
45
DiscussionStateSearchResultEdge,
56
DiscussionStateType,
@@ -17,7 +18,7 @@ export async function getNotificationState(
1718
): Promise<StateType> {
1819
switch (notification.subject.type) {
1920
case 'CheckSuite':
20-
return getCheckSuiteState(notification);
21+
return getCheckSuiteAttributes(notification)?.status;
2122
case 'Discussion':
2223
return await getDiscussionState(notification, token);
2324
case 'Issue':
@@ -33,28 +34,46 @@ export async function getNotificationState(
3334
* Ideally we would be using a GitHub API to fetch the CheckSuite / WorkflowRun state,
3435
* but there isn't an obvious/clean way to do this currently.
3536
*/
36-
export function getCheckSuiteState(
37+
export function getCheckSuiteAttributes(
3738
notification: Notification,
38-
): CheckSuiteStatus | null {
39-
const lowerTitle = notification.subject.title.toLowerCase();
40-
41-
if (lowerTitle.includes('cancelled for')) {
42-
return 'cancelled';
43-
}
44-
45-
if (lowerTitle.includes('failed for')) {
46-
return 'failure';
39+
): CheckSuiteAttributes | null {
40+
const regexPattern =
41+
/^(?<workflowName>.*?) workflow run(, Attempt #(?<attemptNumber>\d+))? (?<statusDisplayName>.*?) for (?<branchName>.*?) branch$/;
42+
43+
const matches = regexPattern.exec(notification.subject.title);
44+
45+
if (matches) {
46+
const { groups } = matches;
47+
48+
return {
49+
workflowName: groups.workflowName,
50+
attemptNumber: groups.attemptNumber
51+
? parseInt(groups.attemptNumber)
52+
: null,
53+
status: getCheckSuiteStatus(groups.statusDisplayName),
54+
statusDisplayName: groups.statusDisplayName,
55+
branchName: groups.branchName,
56+
};
4757
}
4858

49-
if (lowerTitle.includes('skipped for')) {
50-
return 'skipped';
51-
}
59+
return null;
60+
}
5261

53-
if (lowerTitle.includes('succeeded for')) {
54-
return 'success';
62+
export function getCheckSuiteStatus(
63+
statusDisplayName: string,
64+
): CheckSuiteStatus {
65+
switch (statusDisplayName) {
66+
case 'cancelled':
67+
return 'cancelled';
68+
case 'failed':
69+
return 'failure';
70+
case 'skipped':
71+
return 'skipped';
72+
case 'succeeded':
73+
return 'success';
74+
default:
75+
return null;
5576
}
56-
57-
return null;
5877
}
5978

6079
export async function getDiscussionState(

0 commit comments

Comments
 (0)