@@ -1141,17 +1141,38 @@ export class Buddy {
11411141 labels : dashboardConfig . labels || [ 'dependencies' , 'dashboard' ] ,
11421142 assignees : dashboardConfig . assignees ,
11431143 } )
1144+
1145+ this . logger . success ( `✅ Successfully updated dashboard issue #${ issue . number } ` )
11441146 }
11451147 else {
11461148 this . logger . info ( 'Creating new dashboard issue' )
11471149
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+ }
11551176 }
11561177
11571178 this . logger . success ( `✅ Dashboard updated: ${ issue . url } ` )
@@ -1227,19 +1248,62 @@ export class Buddy {
12271248 */
12281249 private async findExistingDashboard ( gitProvider : GitHubProvider , issueNumber ?: number ) : Promise < Issue | null > {
12291250 try {
1251+ this . logger . info ( 'Searching for existing dashboard issue...' )
1252+
12301253 // If issue number is provided, try to get that specific issue
12311254 if ( issueNumber ) {
1255+ this . logger . info ( `Looking for specific dashboard issue #${ issueNumber } ` )
12321256 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+ }
12341266 }
12351267
1236- // Otherwise, search for existing dashboard by title and labels
1268+ // Get all open issues
12371269 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
12431307 }
12441308 catch ( error ) {
12451309 this . logger . warn ( `Failed to search for existing dashboard: ${ error } ` )
0 commit comments