Skip to content

Commit cdd5981

Browse files
authored
fix: Fixes missing API Key and Secret failing Fetch builds (#81)
# Description <!-- Include a summary of the change made and also list the dependencies that are required if any --> ## Issue Ticket Number <!-- Specifiy which issue this fixes by referencing the issue number (`#11`) or issue URL. --> <!-- Example: Fixes #1 --> Fixes #80 ## Type of change <!-- Please select all options that are applicable. --> - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update # Checklist <!-- These must all be followed and checked. --> - [ ] I have followed the contributing guidelines of this project as mentioned in [CONTRIBUTING.md](/CONTRIBUTING.md) - [ ] I have created an [issue](https://github.com/colbyfayock/netlify-plugin-cloudinary/issues) ticket for this PR - [ ] I have checked to ensure there aren't other open [Pull Requests](https://github.com/colbyfayock/netlify-plugin-cloudinary/pulls) for the same update/change? - [ ] I have performed a self-review of my own code - [ ] I have run tests locally to ensure they all pass - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes needed to the documentation
1 parent 9a8b8ba commit cdd5981

File tree

5 files changed

+144
-65
lines changed

5 files changed

+144
-65
lines changed

demo/tsconfig.json

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
{
22
"compilerOptions": {
3-
"lib": ["dom", "dom.iterable", "esnext"],
3+
"lib": [
4+
"dom",
5+
"dom.iterable",
6+
"esnext"
7+
],
48
"allowJs": true,
59
"skipLibCheck": true,
610
"strict": false,
@@ -17,7 +21,8 @@
1721
"name": "next"
1822
}
1923
],
20-
"strictNullChecks": true
24+
"strictNullChecks": true,
25+
"forceConsistentCasingInFileNames": true
2126
},
2227
"include": [
2328
"next-env.d.ts",
@@ -26,5 +31,7 @@
2631
"**/*.tsx",
2732
"**/*.json"
2833
],
29-
"exclude": ["node_modules"]
34+
"exclude": [
35+
"node_modules"
36+
]
3037
}
Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
export const ERROR_API_CREDENTIALS_REQUIRED =
2+
'Both your Cloudinary API Key and API Secret are required when using a Delivery Type of Upload. Please confirm the environment variables CLOUDINARY_API_KEY and CLOUDINARY_API_SECRET are configured.';
13
export const ERROR_CLOUD_NAME_REQUIRED =
2-
'A Cloudinary Cloud Name is required. Please set cloudName input or use the environment variable CLOUDINARY_CLOUD_NAME'
3-
export const ERROR_INVALID_IMAGES_PATH = 'Invalid asset path. Please make sure your imagesPath is defined.'
4+
'A Cloudinary Cloud Name is required. Please set cloudName input or use the environment variable CLOUDINARY_CLOUD_NAME';
5+
export const ERROR_INVALID_IMAGES_PATH = 'Invalid asset path. Please make sure your imagesPath is defined.';
46
export const ERROR_NETLIFY_HOST_CLI_SUPPORT =
5-
'Note: The Netlify CLI does not currently support the ability to determine the host locally, try deploying on Netlify.'
7+
'Note: The Netlify CLI does not currently support the ability to determine the host locally, try deploying on Netlify.';
68
export const ERROR_NETLIFY_HOST_UNKNOWN =
7-
'Cannot determine Netlify host, can not proceed with plugin.'
8-
export const ERROR_SITE_NAME_REQUIRED = 'Cannot determine the site name, can not proceed with plugin'
9+
'Cannot determine Netlify host, can not proceed with plugin.';
10+
export const ERROR_SITE_NAME_REQUIRED = 'Cannot determine the site name, can not proceed with plugin';

netlify-plugin-cloudinary/src/index.ts

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { findAssetsByPath } from './lib/util';
1212

1313
import { PUBLIC_ASSET_PATH } from './data/cloudinary';
1414
import {
15+
ERROR_API_CREDENTIALS_REQUIRED,
1516
ERROR_CLOUD_NAME_REQUIRED,
1617
ERROR_INVALID_IMAGES_PATH,
1718
ERROR_NETLIFY_HOST_CLI_SUPPORT,
@@ -160,11 +161,18 @@ export async function onBuild({
160161
const apiKey = process.env.CLOUDINARY_API_KEY;
161162
const apiSecret = process.env.CLOUDINARY_API_SECRET;
162163

163-
if (!cloudName || !apiKey || !apiSecret) {
164+
if (!cloudName) {
165+
console.error(`[Cloudinary] ${ERROR_CLOUD_NAME_REQUIRED}`);
164166
utils.build.failBuild(ERROR_CLOUD_NAME_REQUIRED);
165167
return;
166168
}
167169

170+
if (deliveryType === 'upload' && (!apiKey || !apiSecret)) {
171+
console.error(`[Cloudinary] ${ERROR_API_CREDENTIALS_REQUIRED}`);
172+
utils.build.failBuild(ERROR_API_CREDENTIALS_REQUIRED);
173+
return;
174+
}
175+
168176
configureCloudinary({
169177
// Base credentials
170178
cloudName,
@@ -176,19 +184,17 @@ export async function onBuild({
176184
privateCdn,
177185
});
178186

179-
180-
181187
// Look for any available images in the provided imagesPath to collect
182188
// asset details and to grab a Cloudinary URL to use later
183189

184-
if ( typeof imagesPath === 'undefined' ) {
190+
if (typeof imagesPath === 'undefined') {
185191
throw new Error(ERROR_INVALID_IMAGES_PATH);
186192
}
187193

188194
const imagesFiles = findAssetsByPath({
189195
baseDir: PUBLISH_DIR,
190-
path: imagesPath
191-
})
196+
path: imagesPath,
197+
});
192198

193199
if (imagesFiles.length === 0) {
194200
console.warn(`[Cloudinary] No image files found in ${imagesPath}`);
@@ -260,9 +266,10 @@ export async function onBuild({
260266

261267
// Unsure how to type the above so that Inputs['privateCdn'] doesnt mess up types here
262268

263-
if ( !Array.isArray(mediaPaths) && typeof mediaPaths !== 'string' ) return;
269+
if (!Array.isArray(mediaPaths) && typeof mediaPaths !== 'string')
270+
return;
264271

265-
if ( !Array.isArray(mediaPaths) ) {
272+
if (!Array.isArray(mediaPaths)) {
266273
mediaPaths = [mediaPaths];
267274
}
268275

@@ -290,7 +297,7 @@ export async function onBuild({
290297
status: 302,
291298
force: true,
292299
});
293-
})
300+
});
294301
},
295302
),
296303
);
@@ -334,11 +341,18 @@ export async function onPostBuild({
334341
const apiKey = process.env.CLOUDINARY_API_KEY;
335342
const apiSecret = process.env.CLOUDINARY_API_SECRET;
336343

337-
if (!cloudName || !apiKey || !apiSecret) {
344+
if (!cloudName) {
345+
console.error(`[Cloudinary] ${ERROR_CLOUD_NAME_REQUIRED}`);
338346
utils.build.failBuild(ERROR_CLOUD_NAME_REQUIRED);
339347
return;
340348
}
341349

350+
if (deliveryType === 'upload' && (!apiKey || !apiSecret)) {
351+
console.error(`[Cloudinary] ${ERROR_API_CREDENTIALS_REQUIRED}`);
352+
utils.build.failBuild(ERROR_API_CREDENTIALS_REQUIRED);
353+
return;
354+
}
355+
342356
configureCloudinary({
343357
// Base credentials
344358
cloudName,

netlify-plugin-cloudinary/tests/on-build.test.js

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,64 @@
11
const fs = require('fs').promises;
22
const { onBuild } = require('../src/');
3+
const { ERROR_API_CREDENTIALS_REQUIRED } = require('../src/data/errors');
34

45
describe('onBuild', () => {
6+
const ENV_ORIGINAL = process.env;
57
const readdir = fs.readdir;
68

79
beforeEach(() => {
810
fs.readdir = jest.fn();
11+
jest.resetModules();
12+
13+
process.env = { ...ENV_ORIGINAL };
14+
15+
process.env.SITE_NAME = 'cool-site';
16+
process.env.CLOUDINARY_CLOUD_NAME = 'testcloud';
17+
process.env.CLOUDINARY_API_KEY = '123456789012345';
18+
process.env.CLOUDINARY_API_SECRET = 'abcd1234';
919
});
1020

1121
afterEach(() => {
1222
fs.readdir = readdir;
13-
})
23+
process.env = ENV_ORIGINAL;
24+
});
25+
26+
describe('Config', () => {
27+
28+
test('should error when using delivery type of upload without API Key and Secret', async () => {
29+
// Test that verifies that delivery of type of fetch works without API Key and Secret can be found
30+
// below under test: should create redirects with defaut fetch-based configuration in production context
31+
// We don't need a "special" test for this as it's default functionality that should work with
32+
// any valid test, so we can isntead ensure the keys don't exist and delete them
33+
34+
jest.spyOn(global.console, 'error').mockImplementation();
35+
36+
delete process.env.CLOUDINARY_API_KEY;
37+
delete process.env.CLOUDINARY_API_SECRET;
38+
39+
process.env.DEPLOY_PRIME_URL = 'https://deploy-preview-1234--netlify-plugin-cloudinary.netlify.app';
40+
41+
const deliveryType = 'upload';
42+
const imagesPath = '/images';
43+
44+
await onBuild({
45+
constants: {
46+
PUBLISH_DIR: `.next/out${imagesPath}`
47+
},
48+
inputs: {
49+
deliveryType
50+
},
51+
utils: {
52+
build: {
53+
failBuild: () => {}
54+
}
55+
}
56+
});
57+
58+
expect(console.error).toBeCalledWith(`[Cloudinary] ${ERROR_API_CREDENTIALS_REQUIRED}`);
59+
});
60+
61+
});
1462

1563
describe('Redirects', () => {
1664

@@ -19,11 +67,14 @@ describe('onBuild', () => {
1967

2068
fs.readdir.mockResolvedValue([imagesFunctionName]);
2169

22-
process.env.SITE_NAME = 'cool-site';
23-
process.env.CLOUDINARY_CLOUD_NAME = 'testcloud';
2470
process.env.CONTEXT = 'production';
2571
process.env.NETLIFY_HOST = 'https://netlify-plugin-cloudinary.netlify.app';
2672

73+
// Tests to ensure that delivery type of fetch works without API Key and Secret as it should
74+
75+
delete process.env.CLOUDINARY_API_KEY;
76+
delete process.env.CLOUDINARY_API_SECRET;
77+
2778
const deliveryType = 'fetch';
2879
const imagesPath = '/images';
2980

@@ -70,8 +121,6 @@ describe('onBuild', () => {
70121

71122
fs.readdir.mockResolvedValue([imagesFunctionName]);
72123

73-
process.env.SITE_NAME = 'cool-site';
74-
process.env.CLOUDINARY_CLOUD_NAME = 'testcloud';
75124
process.env.CONTEXT = 'deploy-preview';
76125
process.env.DEPLOY_PRIME_URL = 'https://deploy-preview-1234--netlify-plugin-cloudinary.netlify.app';
77126

@@ -122,8 +171,6 @@ describe('onBuild', () => {
122171

123172
fs.readdir.mockResolvedValue([imagesFunctionName]);
124173

125-
process.env.SITE_NAME = 'cool-site';
126-
process.env.CLOUDINARY_CLOUD_NAME = 'testcloud';
127174
process.env.CONTEXT = 'deploy-preview';
128175
process.env.DEPLOY_PRIME_URL = 'https://deploy-preview-1234--netlify-plugin-cloudinary.netlify.app';
129176

0 commit comments

Comments
 (0)