@@ -96,7 +96,12 @@ class SyncService extends Base {
9696 // 3. Sync release notes
9797 const releaseStats = await this . #syncReleaseNotes( ) ;
9898
99- // 4. Save metadata
99+ // 4. Self-heal push failures: If a previously failed issue was successfully pulled, remove it from the failure list
100+ if ( newMetadata . push_failures ?. length > 0 ) {
101+ newMetadata . push_failures = newMetadata . push_failures . filter ( failedId => ! newMetadata . issues [ failedId ] ) ;
102+ }
103+
104+ // 5. Save metadata
100105 await this . #saveMetadata( newMetadata ) ;
101106
102107 const endTime = new Date ( ) ;
@@ -340,8 +345,9 @@ class SyncService extends Base {
340345 logger . info ( `Processing ${ allIssues . length } issues since ${ issueSyncConfig . syncStartDate } ` ) ;
341346
342347 const newMetadata = {
343- issues : { } ,
344- last_sync : new Date ( ) . toISOString ( )
348+ issues : { } ,
349+ push_failures : metadata . push_failures || [ ] ,
350+ last_sync : new Date ( ) . toISOString ( )
345351 } ;
346352
347353 const stats = {
@@ -410,21 +416,23 @@ class SyncService extends Base {
410416
411417 /**
412418 * Scans local Markdown files for modifications since the last sync and pushes
413- * changes (title and body) to the corresponding GitHub issues.
419+ * changes (title and body) to the corresponding GitHub issues. It also tracks and
420+ * skips issues that have previously failed to push.
414421 * @param {object } metadata - The last known sync metadata.
415- * @returns {Promise<object> } Statistics about the push operation ({count: number, issues: number[]}).
422+ * @returns {Promise<object> } Statistics about the push operation ({count: number, issues: number[], failures: number[] }).
416423 * @private
417424 */
418425 async #pushToGitHub( metadata ) {
419426 logger . info ( '📤 Checking for local changes to push...' ) ;
420- const stats = { count : 0 , issues : [ ] } ;
427+ const stats = { count : 0 , issues : [ ] , failures : [ ] } ;
421428
422429 if ( ! metadata . last_sync ) {
423430 logger . info ( '✨ No previous sync found, skipping push.' ) ;
424431 return stats ;
425432 }
426433
427434 const localFiles = await this . #scanLocalFiles( ) ;
435+ const previousFailures = metadata . push_failures || [ ] ;
428436
429437 for ( const filePath of localFiles ) {
430438 const fileStats = await fs . stat ( filePath ) ;
@@ -435,6 +443,12 @@ class SyncService extends Base {
435443
436444 if ( ! issueNumber ) continue ;
437445
446+ if ( previousFailures . includes ( issueNumber ) ) {
447+ logger . debug ( `Skipping previously failed push for issue #${ issueNumber } ` ) ;
448+ stats . failures . push ( issueNumber ) ;
449+ continue ;
450+ }
451+
438452 logger . info ( `📝 Local changes detected for #${ issueNumber } ` ) ;
439453
440454 try {
@@ -458,16 +472,19 @@ class SyncService extends Base {
458472 stats . count ++ ;
459473 stats . issues . push ( issueNumber ) ;
460474 } catch ( e ) {
461- logger . warn ( `⚠️ Could not push changes for #${ issueNumber } . Issue may not exist on GitHub.` ) ;
475+ logger . warn ( `⚠️ Could not push changes for #${ issueNumber } . Issue may not exist on GitHub. Error: ${ e . stderr || e . message } ` ) ;
476+ stats . failures . push ( issueNumber ) ;
462477 }
463478 }
464479 }
465480
466481 if ( stats . count > 0 ) {
467482 logger . info ( `📤 Pushed ${ stats . count } local change(s) to GitHub` ) ;
468- } else {
469- logger . info ( '✨ No local changes to push' ) ;
470483 }
484+ if ( stats . failures . length > 0 ) {
485+ logger . warn ( `⚠️ Encountered ${ stats . failures . length } push failure(s).` ) ;
486+ }
487+
471488 return stats ;
472489 }
473490
0 commit comments