From 0a1aec04a328698b2c3cd15612431ea4b76552f4 Mon Sep 17 00:00:00 2001 From: Joe Lencioni Date: Wed, 24 Jul 2024 12:01:07 -0500 Subject: [PATCH] Improve error message for missing apiKey and apiSecret I was debugging an error recently where I saw the following logged: > No `apiKey` or `apiSecret` found in config. Falling back to > pull-request authentication. I believe in this particular case that only one of these was missing and I thought it might be nice if this error message was a little more specifically helpful. --- src/loadUserConfig.js | 22 ++++++++++++++++------ test/loadUserConfig-test.js | 24 ++++++++++++++++++++---- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/loadUserConfig.js b/src/loadUserConfig.js index d5e16f1..522e6ed 100644 --- a/src/loadUserConfig.js +++ b/src/loadUserConfig.js @@ -60,17 +60,25 @@ export default async function loadUserConfig(pathToConfigFile, env = process.env const config = await load(pathToConfigFile); if (!config.apiKey || !config.apiSecret) { + const missing = [ + !config.apiKey ? 'apiKey' : null, + !config.apiSecret ? 'apiSecret' : null, + ] + .filter(Boolean) + .map((key) => `\`${key}\``) + .join(' and '); + const prUrl = CHANGE_URL || resolvePRLink(env); if (!prUrl) { throw new Error( - 'You need an `apiKey` and `apiSecret` in your config. ' + - 'To obtain one, go to https://happo.io/settings', + `Missing ${missing} in your Happo config. Reference yours at https://happo.io/settings`, ); } + try { - // Reassign api tokens to temporary ones provided for the PR + // Reassign API tokens to temporary ones provided for the PR new Logger().info( - 'No `apiKey` or `apiSecret` found in config. Falling back to pull-request authentication.', + `Missing ${missing} in Happo config. Falling back to pull-request authentication.`, ); config.apiKey = prUrl; config.apiSecret = await getPullRequestSecret(config, prUrl); @@ -78,12 +86,13 @@ export default async function loadUserConfig(pathToConfigFile, env = process.env throw new WrappedError('Failed to obtain temporary pull-request token', e); } } + if (!config.targets || Object.keys(config.targets).length === 0) { throw new Error( - 'You need at least one target defined under `targets`. ' + - 'See https://github.com/happo/happo.io#targets for more info.', + 'You need at least one target defined under `targets` in your Happo config. See https://github.com/happo/happo.io#targets for more info.', ); } + const defaultKeys = Object.keys(defaultConfig); const usedKeys = Object.keys(config); usedKeys.forEach((key) => { @@ -91,6 +100,7 @@ export default async function loadUserConfig(pathToConfigFile, env = process.env new Logger().warn(`Unknown config key used in .happo.js: "${key}"`); } }); + config.publicFolders.push(config.tmpdir); config.plugins.forEach(({ publicFolders }) => { if (publicFolders) { diff --git a/test/loadUserConfig-test.js b/test/loadUserConfig-test.js index 6b46252..73e15ca 100644 --- a/test/loadUserConfig-test.js +++ b/test/loadUserConfig-test.js @@ -26,9 +26,25 @@ beforeEach(() => { })); }); -it('yells if api tokens are missing', async () => { +it('yells if both API tokens are missing', async () => { requireRelative.mockImplementation(() => ({})); - await expect(loadUserConfig('bogus', {})).rejects.toThrow(/You need an `apiKey`/); + await expect(loadUserConfig('bogus', {})).rejects.toThrow(/Missing `apiKey` and `apiSecret` in your Happo config/); +}); + +it('yells if apiKey is missing', async () => { + requireRelative.mockImplementation(() => ({ + apiSecret: '2', + targets: {}, + })); + await expect(loadUserConfig('bogus', {})).rejects.toThrow(/Missing `apiKey` in your Happo config/); +}); + +it('yells if apiSecret is missing', async () => { + requireRelative.mockImplementation(() => ({ + apiKey: '1', + targets: {}, + })); + await expect(loadUserConfig('bogus', {})).rejects.toThrow(/Missing `apiSecret` in your Happo config/); }); it('yells if targets are missing', async () => { @@ -101,7 +117,7 @@ describe('when CHANGE_URL is defined', () => { it('adds a log', async () => { await loadUserConfig('bogus', { CHANGE_URL: 'foo.bar' }); expect(info.mock.calls[0][0]).toEqual( - 'No `apiKey` or `apiSecret` found in config. Falling back to pull-request authentication.', + 'Missing `apiKey` and `apiSecret` in Happo config. Falling back to pull-request authentication.', ); }); @@ -146,7 +162,7 @@ describe('when GITHUB_EVENT_PATH is defined', () => { loadUserConfig('bogus', { GITHUB_EVENT_PATH: path.resolve(__dirname, 'github_push_event.json'), }), - ).rejects.toThrow(/You need an.*apiSecret/); + ).rejects.toThrow(/Missing `apiKey` and `apiSecret`/); }); }); });