From 9bb7a61df2a4700d1d5a6c17507551d03d291e72 Mon Sep 17 00:00:00 2001 From: Dolan Antenucci Date: Wed, 1 Apr 2026 06:00:51 -0600 Subject: [PATCH 1/5] fix (full-sync): Adding pino logger for probot update --- full-sync.js | 35 +++++++++++++++++++++++++++++------ test/unit/full-sync.test.js | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 6 deletions(-) create mode 100644 test/unit/full-sync.test.js diff --git a/full-sync.js b/full-sync.js index 8ba1c735..e72c6b89 100644 --- a/full-sync.js +++ b/full-sync.js @@ -1,16 +1,33 @@ const appFn = require('./') const { FULL_SYNC_NOP } = require('./lib/env') const { createProbot } = require('probot') +const pino = require('pino') async function performFullSync (appFn, nop) { - const probot = createProbot() + const logLevel = process.env.LOG_LEVEL || 'info' + const logger = pino({ + level: logLevel, + transport: { + target: 'pino-pretty', + options: { + colorize: true, + translateTime: 'HH:mm:ss.l', + ignore: 'pid,hostname', + messageFormat: '{msg}', + customColors: 'info:blue,warn:yellow,error:red', + levelFirst: true + } + } + }) + + const probot = createProbot({ overrides: { log: logger } }) probot.log.info(`Starting full sync with NOP=${nop}`) try { const app = appFn(probot, {}) const settings = await app.syncInstallation(nop) - if (settings.errors && settings.errors.length > 0) { + if (settings && settings.errors && settings.errors.length > 0) { probot.log.error('Errors occurred during full sync.') process.exit(1) } @@ -22,7 +39,13 @@ async function performFullSync (appFn, nop) { } } -performFullSync(appFn, FULL_SYNC_NOP).catch((error) => { - console.error('Fatal error during full sync:', error) - process.exit(1) -}) +// Only run if executed directly (not when imported for testing) +if (require.main === module) { + performFullSync(appFn, FULL_SYNC_NOP).catch((error) => { + console.error('Fatal error during full sync:', error) + process.exit(1) + }) +} + +// Export for testing +module.exports = { performFullSync } diff --git a/test/unit/full-sync.test.js b/test/unit/full-sync.test.js new file mode 100644 index 00000000..df37564f --- /dev/null +++ b/test/unit/full-sync.test.js @@ -0,0 +1,37 @@ +/* eslint-disable no-undef */ +const { performFullSync } = require("../../full-sync"); + +jest.mock("probot", () => ({ createProbot: jest.fn() })); +jest.mock("pino", () => jest.fn(() => ({ info: jest.fn() }))); + +describe("full-sync.js", () => { + let mockProbot, mockApp; + + beforeEach(() => { + mockProbot = { log: { info: jest.fn() } }; + require("probot").createProbot.mockReturnValue(mockProbot); + mockApp = { syncInstallation: jest.fn() }; + jest.clearAllMocks(); + }); + + it("should pass logger to createProbot via overrides (v14 fix)", async () => { + mockApp.syncInstallation.mockResolvedValue({ errors: [] }); + await performFullSync(jest.fn().mockReturnValue(mockApp), true); + + expect(require("probot").createProbot).toHaveBeenCalledWith( + expect.objectContaining({ + overrides: expect.objectContaining({ log: expect.any(Object) }), + }), + ); + }); + + it("should handle null settings without crashing (null safety)", async () => { + mockApp.syncInstallation.mockResolvedValue(null); + await performFullSync(jest.fn().mockReturnValue(mockApp), true); + + // Just verify it completes without throwing + expect(mockProbot.log.info).toHaveBeenCalledWith( + "Full sync completed successfully.", + ); + }); +}); From ecee1fff9bb2ba01aee513173851f62b31334cbb Mon Sep 17 00:00:00 2001 From: Dolan Antenucci Date: Wed, 1 Apr 2026 06:20:09 -0600 Subject: [PATCH 2/5] Removing time translation --- full-sync.js | 1 - 1 file changed, 1 deletion(-) diff --git a/full-sync.js b/full-sync.js index e72c6b89..930f191a 100644 --- a/full-sync.js +++ b/full-sync.js @@ -11,7 +11,6 @@ async function performFullSync (appFn, nop) { target: 'pino-pretty', options: { colorize: true, - translateTime: 'HH:mm:ss.l', ignore: 'pid,hostname', messageFormat: '{msg}', customColors: 'info:blue,warn:yellow,error:red', From 07a600d2b482345b5c2e75aa74fdd87852bd970b Mon Sep 17 00:00:00 2001 From: Dolan Antenucci Date: Sat, 13 Jun 2026 07:33:50 -0600 Subject: [PATCH 3/5] chore(npm): explicit include of pino packages --- package-lock.json | 2 ++ package.json | 2 ++ 2 files changed, 4 insertions(+) diff --git a/package-lock.json b/package-lock.json index cdb55710..19d3a6dd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,8 @@ "minimatch": "^10.2.1", "node-cron": "^4.2.1", "octokit": "^5.0.2", + "pino": "^10.3.1", + "pino-pretty": "^13.1.3", "probot": "^14.2.4", "proxy-from-env": "^2.1.0", "undici": "^7.7.0" diff --git a/package.json b/package.json index 302f9f20..705a909b 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,8 @@ "minimatch": "^10.2.1", "node-cron": "^4.2.1", "octokit": "^5.0.2", + "pino": "^10.3.1", + "pino-pretty": "^13.1.3", "probot": "^14.2.4", "proxy-from-env": "^2.1.0", "undici": "^7.7.0" From 705ce00893a36d647f14851890829d52662db4c0 Mon Sep 17 00:00:00 2001 From: Dolan Antenucci Date: Sat, 13 Jun 2026 07:34:10 -0600 Subject: [PATCH 4/5] chore(lint): formatting of new test file --- test/unit/full-sync.test.js | 60 ++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/test/unit/full-sync.test.js b/test/unit/full-sync.test.js index df37564f..1379d914 100644 --- a/test/unit/full-sync.test.js +++ b/test/unit/full-sync.test.js @@ -1,37 +1,41 @@ -/* eslint-disable no-undef */ -const { performFullSync } = require("../../full-sync"); +const { performFullSync } = require('../../full-sync') -jest.mock("probot", () => ({ createProbot: jest.fn() })); -jest.mock("pino", () => jest.fn(() => ({ info: jest.fn() }))); +jest.mock('probot', () => ({ + createProbot: jest.fn() +})) +jest.mock('pino', () => jest.fn(() => ({ info: jest.fn() }))) -describe("full-sync.js", () => { - let mockProbot, mockApp; +describe('full-sync.js', () => { + let mockApp beforeEach(() => { - mockProbot = { log: { info: jest.fn() } }; - require("probot").createProbot.mockReturnValue(mockProbot); - mockApp = { syncInstallation: jest.fn() }; - jest.clearAllMocks(); - }); + require('probot').createProbot.mockImplementation(({ overrides }) => ({ + log: overrides.log + })) + mockApp = { syncInstallation: jest.fn() } + jest.clearAllMocks() + }) - it("should pass logger to createProbot via overrides (v14 fix)", async () => { - mockApp.syncInstallation.mockResolvedValue({ errors: [] }); - await performFullSync(jest.fn().mockReturnValue(mockApp), true); + it('should pass logger to createProbot via overrides (v14 fix)', async () => { + mockApp.syncInstallation.mockResolvedValue({ errors: [] }) + await performFullSync(jest.fn().mockReturnValue(mockApp), true) - expect(require("probot").createProbot).toHaveBeenCalledWith( + expect(require('probot').createProbot).toHaveBeenCalledWith( expect.objectContaining({ - overrides: expect.objectContaining({ log: expect.any(Object) }), - }), - ); - }); + overrides: expect.objectContaining({ log: expect.any(Object) }) + }) + ) + }) - it("should handle null settings without crashing (null safety)", async () => { - mockApp.syncInstallation.mockResolvedValue(null); - await performFullSync(jest.fn().mockReturnValue(mockApp), true); + it('should handle null settings without crashing (null safety)', async () => { + mockApp.syncInstallation.mockResolvedValue(null) + const mockLogger = { info: jest.fn(), error: jest.fn() } + require('pino').mockReturnValueOnce(mockLogger) + require('probot').createProbot.mockImplementationOnce(({ overrides }) => ({ + log: overrides.log + })) + await performFullSync(jest.fn().mockReturnValue(mockApp), true) - // Just verify it completes without throwing - expect(mockProbot.log.info).toHaveBeenCalledWith( - "Full sync completed successfully.", - ); - }); -}); + expect(mockLogger.info).toHaveBeenCalledWith('Full sync completed successfully.') + }) +}) From fb5cf2dcd9decf351499c60dc050cbe580258c23 Mon Sep 17 00:00:00 2001 From: Dolan Antenucci Date: Sat, 13 Jun 2026 08:33:52 -0600 Subject: [PATCH 5/5] fix(test): move jest.clearAllMocks to start of beforeEach Clearing mocks after setting them up wiped the mockImplementation before each test ran, making the setup a no-op. --- test/unit/full-sync.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/full-sync.test.js b/test/unit/full-sync.test.js index 1379d914..584c07df 100644 --- a/test/unit/full-sync.test.js +++ b/test/unit/full-sync.test.js @@ -9,11 +9,11 @@ describe('full-sync.js', () => { let mockApp beforeEach(() => { + jest.clearAllMocks() require('probot').createProbot.mockImplementation(({ overrides }) => ({ log: overrides.log })) mockApp = { syncInstallation: jest.fn() } - jest.clearAllMocks() }) it('should pass logger to createProbot via overrides (v14 fix)', async () => {