1
1
const axios = require ( "axios" ) ;
2
- const { WebClient } = require ( "@slack/web-api" ) ;
3
-
4
- const slackWrapper = ( token , channel ) => {
5
- const client = new WebClient ( token ) ;
6
-
7
- const sendMessage = async ( args ) => {
8
- try {
9
- await client . chat . postMessage ( {
10
- ...args ,
11
- channel,
12
- unfurl_links : false ,
13
- unfurl_media : false ,
14
- } ) ;
15
- } catch ( e ) {
16
- console . error ( "Unable to send Slack message:" , e . message ) ;
17
- }
18
- } ;
19
-
20
- return {
21
- sendMessage,
22
- client,
23
- channel,
24
- } ;
25
- } ;
26
-
27
- const delay = ( ms ) => new Promise ( ( resolve ) => setTimeout ( resolve , ms ) ) ;
2
+ const sendSlackNotification = require ( "./integrations/slack" ) ;
3
+ const sendDiscordNotification = require ( "./integrations/discord" ) ;
28
4
29
5
/**
30
6
* Fetch new issues created within a configurable timeframe.
31
- *
7
+ *
32
8
* @param {string } gitToken - GitHub API token for authentication.
33
9
* @param {string } owner - Repository owner.
34
10
* @param {string } repo - Repository name.
35
11
* @param {number } hoursAgo - Timeframe in hours to fetch issues created since then.
36
12
* @returns {Promise<Array> } - List of new issues created within the specified timeframe.
37
13
*/
38
14
const fetchNewIssues = async ( gitToken , owner , repo , hoursAgo ) => {
39
- const apiUrl = `https://api.github.com/repos/${ owner } /${ repo } /issues` ;
40
- const sinceDate = new Date ( new Date ( ) . getTime ( ) - hoursAgo * 60 * 60 * 1000 ) . toISOString ( ) ;
41
-
42
- let newIssues = [ ] ;
43
- let page = 1 ;
44
-
45
- try {
46
- while ( true ) {
47
- const response = await axios . get ( apiUrl , {
48
- headers : { Authorization : `token ${ gitToken } ` } ,
49
- params : {
50
- state : "open" , // Only fetch open issues
51
- sort : "created" , // Sort by creation date
52
- direction : "desc" , // Fetch the most recent issues first
53
- since : sinceDate , // Fetch issues created or updated after this timestamp
54
- per_page : 100 , // Maximum results per page
55
- page, // Current page of the results
56
- } ,
57
- } ) ;
58
-
59
- const issues = response . data . filter ( ( issue ) => {
60
- // Exclude pull requests and ensure the issue is newly created
61
- const createdAt = new Date ( issue . created_at ) ;
62
- return ! issue . pull_request && createdAt >= new Date ( sinceDate ) ;
63
- } ) ;
64
-
65
- // Map issues to include required fields
66
- newIssues . push (
67
- ...issues . map ( ( issue ) => ( {
68
- title : issue . title ,
69
- url : issue . html_url ,
70
- createdAt : issue . created_at ,
71
- labels : issue . labels . map ( ( label ) => label . name ) ,
72
- comments : issue . comments ,
73
- } ) )
74
- ) ;
75
-
76
- // Exit loop if no more pages to fetch
77
- if ( ! response . headers [ "link" ] ?. includes ( 'rel="next"' ) ) break ;
78
-
79
- page ++ ; // Move to the next page
80
- }
81
-
82
- return newIssues ;
83
- } catch ( error ) {
84
- console . error ( "Error fetching issues:" , error . message ) ;
85
- return [ ] ;
86
- }
87
- } ;
88
-
89
-
90
- const sendSlackNotification = async ( slackToken , slackChannel , slackIDType , slackID , issues , repo ) => {
91
- if ( ! issues . length ) {
92
- console . log ( "No issues found within the specified time frame." ) ;
93
- return ;
94
- }
95
-
96
- const slack = slackWrapper ( slackToken , slackChannel ) ;
97
-
98
- const assigneeText =
99
- slackIDType === "group"
100
- ? `*Assignee:* <!subteam^${ slackID } > *(Mark as ACK or Done after triaging)*`
101
- : slackIDType === "user"
102
- ? `*Assignee:* <@${ slackID } > *(Mark as ACK or Done after triaging)*`
103
- : "" ;
15
+ const apiUrl = `https://api.github.com/repos/${ owner } /${ repo } /issues` ;
16
+ const sinceDate = new Date (
17
+ new Date ( ) . getTime ( ) - hoursAgo * 60 * 60 * 1000
18
+ ) . toISOString ( ) ;
19
+
20
+ let newIssues = [ ] ;
21
+ let page = 1 ;
22
+
23
+ try {
24
+ while ( true ) {
25
+ const response = await axios . get ( apiUrl , {
26
+ headers : { Authorization : `token ${ gitToken } ` } ,
27
+ params : {
28
+ state : "open" , // Only fetch open issues
29
+ sort : "created" , // Sort by creation date
30
+ direction : "desc" , // Fetch the most recent issues first
31
+ since : sinceDate , // Fetch issues created or updated after this timestamp
32
+ per_page : 100 , // Maximum results per page
33
+ page, // Current page of the results
34
+ } ,
35
+ } ) ;
104
36
105
- for ( const issue of issues ) {
106
- const message = `
107
- :chart_with_upwards_trend: *New Issue in ${ repo } *
108
- *-* *Title:* ${ issue . title }
109
- *-* *Labels:* ${ issue . labels . map ( ( label ) => `\`${ label } \`` ) . join ( ", " ) }
110
- *-* *Link:* <${ issue . url } |View Issue>
111
- ${ assigneeText }
112
- ` ;
37
+ const issues = response . data . filter ( ( issue ) => {
38
+ // Exclude pull requests and ensure the issue is newly created
39
+ const createdAt = new Date ( issue . created_at ) ;
40
+ return ! issue . pull_request && createdAt >= new Date ( sinceDate ) ;
41
+ } ) ;
113
42
114
- try {
115
- await slack . sendMessage ( { text : message } ) ;
116
- console . log ( `Posted issue "${ issue . title } " to Slack.` ) ;
117
- } catch ( error ) {
118
- console . error ( `Failed to post issue "${ issue . title } " to Slack:` , error . message ) ;
43
+ // Map issues to include required fields
44
+ newIssues . push (
45
+ ...issues . map ( ( issue ) => ( {
46
+ title : issue . title ,
47
+ url : issue . html_url ,
48
+ createdAt : issue . created_at ,
49
+ labels : issue . labels . map ( ( label ) => label . name ) ,
50
+ comments : issue . comments ,
51
+ } ) )
52
+ ) ;
53
+
54
+ // Exit loop if no more pages to fetch
55
+ if ( ! response . headers [ "link" ] ?. includes ( 'rel="next"' ) ) break ;
56
+
57
+ page ++ ; // Move to the next page
119
58
}
120
59
121
- console . log ( "Waiting for 30 seconds before sending the next message..." ) ;
122
- await delay ( 30 * 1000 ) ;
60
+ return newIssues ;
61
+ } catch ( error ) {
62
+ console . error ( "Error fetching issues:" , error . message ) ;
63
+ return [ ] ;
123
64
}
124
-
125
- console . log ( `*** All issues posted on Slack for ${ repo } ***` ) ;
126
65
} ;
127
66
128
- async function monitorIssues ( gitToken , slackToken , slackChannel , owner , repo , slackIDType , slackID ) {
129
- const hoursAgo = 6 ;
67
+ async function monitorIssues ( {
68
+ gitToken,
69
+ owner,
70
+ repo,
71
+ notifier,
72
+ slackConfig,
73
+ discordConfig,
74
+ } ) {
75
+ const hoursAgo = 24 ;
130
76
131
77
const issues = await fetchNewIssues ( gitToken , owner , repo , hoursAgo ) ;
132
- console . log ( "Issues to be notified via Slack:" , issues . map ( ( issue ) => issue . title ) ) ;
133
78
134
- await sendSlackNotification ( slackToken , slackChannel , slackIDType , slackID , issues , repo ) ;
79
+ if ( notifier === "slack" ) {
80
+ const {
81
+ slackToken,
82
+ slackChannel,
83
+ slackIDType,
84
+ slackID,
85
+ } = slackConfig ;
86
+ console . log (
87
+ "Sending notifications to Slack for issues:" ,
88
+ issues . map ( ( issue ) => issue . title )
89
+ ) ;
90
+ await sendSlackNotification (
91
+ slackToken ,
92
+ slackChannel ,
93
+ slackIDType ,
94
+ slackID ,
95
+ issues ,
96
+ repo
97
+ ) ;
98
+ } else if ( notifier === "discord" ) {
99
+ const {
100
+ discordWebhookUrl,
101
+ } = discordConfig ;
102
+ console . log (
103
+ "Sending notifications to Discord for issues:" ,
104
+ issues . map ( ( issue ) => issue . title )
105
+ ) ;
106
+ await sendDiscordNotification ( discordWebhookUrl , issues , repo ) ;
107
+ } else {
108
+ throw new Error ( "Unsupported notifier. Use 'slack' or 'discord'." ) ;
135
109
}
136
-
137
- module . exports = { monitorIssues } ;
110
+ }
111
+
112
+ module . exports = monitorIssues ;
0 commit comments