@@ -1141,17 +1141,38 @@ export class Buddy {
1141
1141
labels : dashboardConfig . labels || [ 'dependencies' , 'dashboard' ] ,
1142
1142
assignees : dashboardConfig . assignees ,
1143
1143
} )
1144
+
1145
+ this . logger . success ( `✅ Successfully updated dashboard issue #${ issue . number } ` )
1144
1146
}
1145
1147
else {
1146
1148
this . logger . info ( 'Creating new dashboard issue' )
1147
1149
1148
- // Create new dashboard
1149
- issue = await gitProvider . createIssue ( {
1150
- title : dashboardConfig . title || title ,
1151
- body,
1152
- labels : dashboardConfig . labels || [ 'dependencies' , 'dashboard' ] ,
1153
- assignees : dashboardConfig . assignees ,
1154
- } )
1150
+ // Double-check for race condition: search again right before creating
1151
+ // This helps prevent duplicates if multiple workflow runs are happening simultaneously
1152
+ this . logger . info ( 'Performing final check for existing dashboards before creation...' )
1153
+ const raceCheckIssue = await this . findExistingDashboard ( gitProvider , dashboardConfig . issueNumber )
1154
+
1155
+ if ( raceCheckIssue ) {
1156
+ this . logger . info ( `Race condition detected! Found existing dashboard #${ raceCheckIssue . number } during final check` )
1157
+ // Update the found issue instead of creating a new one
1158
+ issue = await gitProvider . updateIssue ( raceCheckIssue . number , {
1159
+ title : dashboardConfig . title || title ,
1160
+ body,
1161
+ labels : dashboardConfig . labels || [ 'dependencies' , 'dashboard' ] ,
1162
+ assignees : dashboardConfig . assignees ,
1163
+ } )
1164
+ this . logger . success ( `✅ Updated existing dashboard issue #${ issue . number } (race condition avoided)` )
1165
+ }
1166
+ else {
1167
+ // Safe to create new dashboard
1168
+ issue = await gitProvider . createIssue ( {
1169
+ title : dashboardConfig . title || title ,
1170
+ body,
1171
+ labels : dashboardConfig . labels || [ 'dependencies' , 'dashboard' ] ,
1172
+ assignees : dashboardConfig . assignees ,
1173
+ } )
1174
+ this . logger . success ( `✅ Successfully created new dashboard issue #${ issue . number } ` )
1175
+ }
1155
1176
}
1156
1177
1157
1178
this . logger . success ( `✅ Dashboard updated: ${ issue . url } ` )
@@ -1227,19 +1248,62 @@ export class Buddy {
1227
1248
*/
1228
1249
private async findExistingDashboard ( gitProvider : GitHubProvider , issueNumber ?: number ) : Promise < Issue | null > {
1229
1250
try {
1251
+ this . logger . info ( 'Searching for existing dashboard issue...' )
1252
+
1230
1253
// If issue number is provided, try to get that specific issue
1231
1254
if ( issueNumber ) {
1255
+ this . logger . info ( `Looking for specific dashboard issue #${ issueNumber } ` )
1232
1256
const issues = await gitProvider . getIssues ( 'open' )
1233
- return issues . find ( issue => issue . number === issueNumber ) || null
1257
+ const specificIssue = issues . find ( issue => issue . number === issueNumber )
1258
+ if ( specificIssue ) {
1259
+ this . logger . info ( `Found specified dashboard issue #${ specificIssue . number } : ${ specificIssue . title } ` )
1260
+ return specificIssue
1261
+ }
1262
+ else {
1263
+ this . logger . warn ( `Specified dashboard issue #${ issueNumber } not found` )
1264
+ return null
1265
+ }
1234
1266
}
1235
1267
1236
- // Otherwise, search for existing dashboard by title and labels
1268
+ // Get all open issues
1237
1269
const issues = await gitProvider . getIssues ( 'open' )
1238
- return issues . find ( issue =>
1239
- ( issue . title . toLowerCase ( ) . includes ( 'dependency dashboard' )
1240
- || issue . labels . includes ( 'dashboard' ) )
1241
- && issue . labels . includes ( 'dependencies' ) ,
1242
- ) || null
1270
+ this . logger . info ( `Found ${ issues . length } open issues to search through` )
1271
+
1272
+ // Search for existing dashboard with multiple criteria for better matching
1273
+ for ( const issue of issues ) {
1274
+ const hasRequiredLabels = issue . labels . includes ( 'dashboard' ) && issue . labels . includes ( 'dependencies' )
1275
+ const titleMatches = issue . title . toLowerCase ( ) . includes ( 'dependency dashboard' )
1276
+ const bodyHasMarker = issue . body . includes ( 'This issue lists Buddy Bot updates and detected dependencies' )
1277
+
1278
+ // Be more strict: require both proper labels AND (title match OR body marker)
1279
+ if ( hasRequiredLabels && ( titleMatches || bodyHasMarker ) ) {
1280
+ this . logger . info ( `Found existing dashboard issue #${ issue . number } : ${ issue . title } ` )
1281
+ this . logger . info ( ` - Labels: ${ issue . labels . join ( ', ' ) } ` )
1282
+ this . logger . info ( ` - Title matches: ${ titleMatches } ` )
1283
+ this . logger . info ( ` - Body has marker: ${ bodyHasMarker } ` )
1284
+ return issue
1285
+ }
1286
+ }
1287
+
1288
+ // If no exact match found, log what we found for debugging
1289
+ const dashboardLabeled = issues . filter ( issue => issue . labels . includes ( 'dashboard' ) )
1290
+ const dependenciesLabeled = issues . filter ( issue => issue . labels . includes ( 'dependencies' ) )
1291
+ const titleMatches = issues . filter ( issue => issue . title . toLowerCase ( ) . includes ( 'dependency dashboard' ) )
1292
+
1293
+ this . logger . info ( `Dashboard search results:` )
1294
+ this . logger . info ( ` - Issues with 'dashboard' label: ${ dashboardLabeled . length } ` )
1295
+ this . logger . info ( ` - Issues with 'dependencies' label: ${ dependenciesLabeled . length } ` )
1296
+ this . logger . info ( ` - Issues with 'dependency dashboard' in title: ${ titleMatches . length } ` )
1297
+
1298
+ if ( dashboardLabeled . length > 0 ) {
1299
+ this . logger . info ( `Issues with 'dashboard' label:` )
1300
+ for ( const issue of dashboardLabeled ) {
1301
+ this . logger . info ( ` - #${ issue . number } : ${ issue . title } (labels: ${ issue . labels . join ( ', ' ) } )` )
1302
+ }
1303
+ }
1304
+
1305
+ this . logger . info ( 'No existing dashboard issue found' )
1306
+ return null
1243
1307
}
1244
1308
catch ( error ) {
1245
1309
this . logger . warn ( `Failed to search for existing dashboard: ${ error } ` )
0 commit comments