diff --git a/get-shit-done/workflows/update.md b/get-shit-done/workflows/update.md index 77cf8988e..5a14cb199 100644 --- a/get-shit-done/workflows/update.md +++ b/get-shit-done/workflows/update.md @@ -486,10 +486,15 @@ const path = require('path'); for (const relPath of custom_files) { const src = path.join(runtimeDir, relPath); const dst = path.join(backupDir, relPath); - if (fs.existsSync(src)) { + if (!fs.existsSync(src)) continue; + + try { fs.mkdirSync(path.dirname(dst), { recursive: true }); fs.copyFileSync(src, dst); console.log(' Backed up: ' + relPath); + } catch (err) { + const code = err && err.code ? String(err.code) : 'ERROR'; + console.log(' Skipped (non-fatal): ' + relPath + ' [' + code + ']'); } } JSEOF diff --git a/tests/bug-3050-update-backup-eacces-nonfatal.test.cjs b/tests/bug-3050-update-backup-eacces-nonfatal.test.cjs new file mode 100644 index 000000000..3bb4091b5 --- /dev/null +++ b/tests/bug-3050-update-backup-eacces-nonfatal.test.cjs @@ -0,0 +1,23 @@ +'use strict'; + +const { test, describe } = require('node:test'); +const assert = require('node:assert/strict'); +const fs = require('node:fs'); +const path = require('node:path'); + +describe('bug #3050: update backup skips unreadable files non-fatally', () => { + test('update workflow backup loop wraps copyFileSync in try/catch and logs non-fatal skip', () => { + const content = fs.readFileSync( + path.join(__dirname, '..', 'get-shit-done', 'workflows', 'update.md'), + 'utf8', + ); + + const hasTryCatch = /try\s*\{[\s\S]*copyFileSync\([\s\S]*\}[\s\S]*catch\s*\(err\)/.test(content); + assert.ok(hasTryCatch, 'backup copy loop must catch per-file copy errors'); + + assert.ok( + content.includes('Skipped (non-fatal):'), + 'workflow must log a non-fatal skip message for unreadable custom files', + ); + }); +});