10
10
* exempt labels that have been inactive for 90+ days.
11
11
* - Avoids sending duplicate Friendly Reminder comments if one was
12
12
* posted within the last 7 days.
13
+ * - Moves issues labeled 'questions' to GitHub Discussions
13
14
*/
14
15
15
16
const dedent = ( strings , ...values ) => {
@@ -47,10 +48,53 @@ async function fetchAllOpenIssues(github, owner, repo) {
47
48
return issues ;
48
49
}
49
50
51
+
52
+ async function migrateToDiscussion ( github , owner , repo , issue ) {
53
+ const discussionCategory = 'Q&A' ;
54
+
55
+ const { data : categories } = await github . rest . discussions . listCategories ( {
56
+ owner,
57
+ repo,
58
+ } ) ;
59
+
60
+ const category = categories . find ( cat =>
61
+ cat . name . toLowerCase ( ) === discussionCategory . toLowerCase ( )
62
+ ) ;
63
+
64
+ if ( ! category ) {
65
+ throw new Error ( `Discussion category '${ discussionCategory } ' not found.` ) ;
66
+ }
67
+
68
+ const { data : discussion } = await github . rest . discussions . create ( {
69
+ owner,
70
+ repo,
71
+ title : issue . title ,
72
+ body : `Originally created by @${ issue . user . login } in #${ issue . number } \n\n---\n\n${ issue . body } ` ,
73
+ category_id : category . id ,
74
+ } ) ;
75
+
76
+ await github . rest . issues . createComment ( {
77
+ owner,
78
+ repo,
79
+ issue_number : issue . number ,
80
+ body : `💬 This issue was moved to [Discussions](${ discussion . html_url } ) for better visibility.` ,
81
+ } ) ;
82
+
83
+ await github . rest . issues . update ( {
84
+ owner,
85
+ repo,
86
+ issue_number : issue . number ,
87
+ state : 'closed' ,
88
+ } ) ;
89
+
90
+ return discussion . html_url ;
91
+ }
92
+
93
+
50
94
const shouldSendReminder = ( issue , exemptLabels , closeLabels ) => {
51
- const hasExempt = issue . labels . some ( l => exemptLabels . includes ( l . name ) ) ;
52
- const hasClose = issue . labels . some ( l => closeLabels . includes ( l . name ) ) ;
53
- return issue . assignees . length > 0 && ! hasExempt && ! hasClose ;
95
+ const hasExempt = issue . labels . some ( l => exemptLabels . includes ( l . name ) ) ;
96
+ const hasClose = issue . labels . some ( l => closeLabels . includes ( l . name ) ) ;
97
+ return issue . assignees . length > 0 && ! hasExempt && ! hasClose ;
54
98
} ;
55
99
56
100
@@ -61,17 +105,25 @@ module.exports = async ({ github, context }) => {
61
105
const thresholdDays = 90 ;
62
106
const exemptLabels = [ 'to-be-discussed' ] ;
63
107
const closeLabels = [ 'awaiting-response' ] ;
108
+ const discussionLabel = 'questions' ;
64
109
const sevenDays = 7 * 24 * 60 * 60 * 1000 ;
65
110
66
111
let totalClosed = 0 ;
67
112
let totalReminders = 0 ;
68
113
let totalSkipped = 0 ;
114
+ let totalMigrated = 0 ;
69
115
70
116
for ( const issue of issues ) {
71
117
const isAssigned = issue . assignees && issue . assignees . length > 0 ;
72
118
const lastUpdate = new Date ( issue . updated_at ) ;
73
119
const daysSinceUpdate = Math . floor ( ( now - lastUpdate ) / ( 1000 * 60 * 60 * 24 ) ) ;
74
120
121
+ if ( issue . labels . some ( label => label . name === discussionLabel ) ) {
122
+ await migrateToDiscussion ( github , owner , repo , issue ) ;
123
+ totalMigrated ++ ;
124
+ continue ;
125
+ }
126
+
75
127
if ( daysSinceUpdate < thresholdDays ) {
76
128
totalSkipped ++ ;
77
129
continue ;
@@ -145,5 +197,6 @@ module.exports = async ({ github, context }) => {
145
197
Total issues processed: ${ issues . length }
146
198
Total issues closed: ${ totalClosed }
147
199
Total reminders sent: ${ totalReminders }
200
+ Total migrated to discussions: ${ totalMigrated }
148
201
Total skipped: ${ totalSkipped } ` ) ;
149
202
} ;
0 commit comments