@contentful/app-scripts 1.11.0 → 1.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14,7 +14,7 @@ const bundlesFixture = [
14
14
  { sys: { id: 'test-8' } },
15
15
  ];
16
16
 
17
- describe.only('cleanUpBundles', () => {
17
+ describe('cleanUpBundles', () => {
18
18
  let subject, clientMock, deleteMock, createClientArgs;
19
19
  let mockedBundles = bundlesFixture;
20
20
 
@@ -92,7 +92,7 @@ describe.only('cleanUpBundles', () => {
92
92
  mockedBundles.unshift({ sys: { id: 'slow' } });
93
93
  mockedBundles = mockedBundles.reverse();
94
94
  clientMock.appBundle.delete = stub().callsFake(
95
- ({ appBundleId }) => new Promise((r) => setTimeout(r, appBundleId === 'slow' ? 200 : 100))
95
+ ({ appBundleId }) => new Promise((r) => setTimeout(r, appBundleId === 'slow' ? 200 : 100)),
96
96
  );
97
97
  subject({ ...mockedSettings, keep: 0 });
98
98
  await clock.tickAsync(50);
@@ -2,13 +2,15 @@
2
2
 
3
3
  const inquirer = require('inquirer');
4
4
  const { getAppInfo } = require('../get-app-info');
5
- const { getActionsManifest } = require('../utils');
5
+ const { getEntityFromManifest } = require('../utils');
6
6
  const { CONTENTFUL_API_HOST } = require('../../utils/constants');
7
7
 
8
8
  async function buildAppUploadSettings(options) {
9
- const actionsManifest = getActionsManifest();
9
+ const actionsManifest = getEntityFromManifest('actions');
10
+ const deliveryFnManifest = getEntityFromManifest('deliveryFunctions');
10
11
  const prompts = [];
11
12
  const { bundleDir, comment, skipActivation, host } = options;
13
+
12
14
  if (!bundleDir) {
13
15
  prompts.push({
14
16
  name: 'bundleDirectory',
@@ -49,6 +51,7 @@ async function buildAppUploadSettings(options) {
49
51
  comment,
50
52
  host,
51
53
  actions: actionsManifest,
54
+ deliveryFunctions: deliveryFnManifest,
52
55
  ...appUploadSettings,
53
56
  ...appInfo,
54
57
  };
@@ -6,7 +6,7 @@ const { createClient } = require('contentful-management');
6
6
  const { createAppUpload } = require('./create-app-upload');
7
7
 
8
8
  async function createAppBundleFromUpload(settings, appUploadId) {
9
- const { accessToken, host, userAgentApplication, comment, actions } = settings;
9
+ const { accessToken, host, userAgentApplication, comment, actions, deliveryFunctions } = settings;
10
10
  const clientSpinner = ora('Verifying your upload...').start();
11
11
  const client = createClient({
12
12
  accessToken,
@@ -24,6 +24,7 @@ async function createAppBundleFromUpload(settings, appUploadId) {
24
24
  appUploadId,
25
25
  comment: comment && comment.length > 0 ? comment : undefined,
26
26
  actions,
27
+ deliveryFunctions,
27
28
  });
28
29
  } catch (err) {
29
30
  showCreationError('app upload', err.message);
@@ -38,8 +39,8 @@ async function createAppBundleFromSettings(settings) {
38
39
  appUpload = await createAppUpload(settings);
39
40
  console.log(`
40
41
  ${chalk.yellow('Done!')} Your files were successfully uploaded and a new AppUpload (${chalk.dim(
41
- appUpload.sys.id
42
- )}) has been created.`);
42
+ appUpload.sys.id,
43
+ )}) has been created.`);
43
44
  } catch (err) {
44
45
  showCreationError('app upload', err.message);
45
46
  }
@@ -54,7 +55,7 @@ async function createAppBundleFromSettings(settings) {
54
55
 
55
56
  console.log(`
56
57
  ${chalk.cyan('Success!')} Created a new app bundle for ${chalk.cyan(
57
- settings.definition.name
58
+ settings.definition.name,
58
59
  )} in ${chalk.bold(settings.organization.name)}.
59
60
 
60
61
  Bundle Id: ${chalk.yellow(appBundle.sys.id)}
@@ -2,7 +2,7 @@ const chalk = require('chalk');
2
2
  const ora = require('ora');
3
3
  const { getAppInfo } = require('../get-app-info');
4
4
  const { validateArguments } = require('../validate-arguments');
5
- const { getActionsManifest } = require('../utils');
5
+ const { getEntityFromManifest } = require('../utils');
6
6
 
7
7
  const requiredOptions = {
8
8
  definitionId: '--definition-id',
@@ -13,7 +13,8 @@ const requiredOptions = {
13
13
 
14
14
  async function getUploadSettingsArgs(options) {
15
15
  const validateSpinner = ora('Validating your input...').start();
16
- const actionsManifest = getActionsManifest();
16
+ const actionsManifest = getEntityFromManifest('actions');
17
+ const deliveryFnManifest = getEntityFromManifest('deliveryFunctions');
17
18
  const { bundleDir, comment, skipActivation, host, userAgentApplication } = options;
18
19
 
19
20
  try {
@@ -27,6 +28,7 @@ async function getUploadSettingsArgs(options) {
27
28
  host,
28
29
  userAgentApplication,
29
30
  actions: actionsManifest,
31
+ deliveryFunctions: deliveryFnManifest,
30
32
  };
31
33
  } catch (err) {
32
34
  console.log(`
package/lib/utils.js CHANGED
@@ -35,6 +35,14 @@ const showCreationError = (subject, message) => {
35
35
  `);
36
36
  };
37
37
 
38
+ const logProgress = (message) => {
39
+ console.log('');
40
+ console.log(` ----------------------------
41
+ ${message}
42
+ ----------------------------`);
43
+ console.log('');
44
+ };
45
+
38
46
  const throwError = (err, message) => {
39
47
  console.log(`
40
48
  ${chalk.red('Error:')} ${message}.
@@ -50,10 +58,8 @@ const selectFromList = async (list, message, cachedOptionEnvVar) => {
50
58
  const cachedElement = list.find((item) => item.value === cachedEnvVar);
51
59
 
52
60
  if (cachedElement) {
53
- console.log(`
54
- ${message}
55
- Using environment variable: ${cachedElement.name} (${chalk.blue(cachedElement.value)})
56
- `);
61
+ logProgress(`${message}
62
+ Using environment variable: ${cachedElement.name} (${chalk.blue(cachedElement.value)})`);
57
63
  return cachedElement;
58
64
  } else {
59
65
  const { elementId } = await inquirer.prompt([
@@ -73,7 +79,7 @@ const selectFromList = async (list, message, cachedOptionEnvVar) => {
73
79
  }
74
80
  };
75
81
 
76
- function getActionsManifest() {
82
+ function getEntityFromManifest(type) {
77
83
  const isManifestExists = fs.existsSync(DEFAULT_MANIFEST_PATH);
78
84
 
79
85
  if (!isManifestExists) {
@@ -83,29 +89,29 @@ function getActionsManifest() {
83
89
  try {
84
90
  const manifest = JSON.parse(fs.readFileSync(DEFAULT_MANIFEST_PATH, { encoding: 'utf8' }));
85
91
 
86
- if (!Array.isArray(manifest.actions) || manifest.actions.length === 0) {
92
+ if (!Array.isArray(manifest[type]) || manifest[type].length === 0) {
87
93
  return;
88
94
  }
89
95
 
90
- console.log('');
91
- console.log(` ----------------------------
92
- App actions manifest found in ${chalk.bold(DEFAULT_MANIFEST_PATH)}.
93
- ----------------------------`);
94
- console.log('');
96
+ logProgress(
97
+ `${type === 'actions' ? 'App Actions' : 'Delivery functions'} found in ${chalk.bold(
98
+ DEFAULT_MANIFEST_PATH,
99
+ )}.`,
100
+ );
95
101
 
96
- const actions = manifest.actions.map((action) => {
97
- const allowNetworks = Array.isArray(action.allowNetworks)
98
- ? action.allowNetworks.map(stripProtocol)
102
+ const items = manifest[type].map((item) => {
103
+ const allowNetworks = Array.isArray(item.allowNetworks)
104
+ ? item.allowNetworks.map(stripProtocol)
99
105
  : [];
100
106
 
101
107
  const hasInvalidNetwork = allowNetworks.find((netWork) => !isValidNetwork(netWork));
102
108
  if (hasInvalidNetwork) {
103
109
  console.log(
104
110
  `${chalk.red(
105
- 'Error:'
106
- )} Invalid IP address ${hasInvalidNetwork} found in the allowNetworks array for action "${
107
- action.name
108
- }".`
111
+ 'Error:',
112
+ )} Invalid IP address ${hasInvalidNetwork} found in the allowNetworks array for ${type} "${
113
+ item.name
114
+ }".`,
109
115
  );
110
116
  // eslint-disable-next-line no-process-exit
111
117
  process.exit(1);
@@ -113,20 +119,20 @@ function getActionsManifest() {
113
119
 
114
120
  // EntryFile is not used but we do want to strip it from action
115
121
  // eslint-disable-next-line no-unused-vars
116
- const { entryFile: _, ...actionWithoutEntryFile } = action;
122
+ const { entryFile: _, ...itemWithoutEntryFile } = item;
117
123
 
118
124
  return {
119
- ...actionWithoutEntryFile,
125
+ ...itemWithoutEntryFile,
120
126
  allowNetworks,
121
127
  };
122
128
  });
123
129
 
124
- return actions;
130
+ return items;
125
131
  } catch {
126
132
  console.log(
127
133
  `${chalk.red('Error:')} Invalid JSON in manifest file at ${chalk.bold(
128
- DEFAULT_MANIFEST_PATH
129
- )}.`
134
+ DEFAULT_MANIFEST_PATH,
135
+ )}.`,
130
136
  );
131
137
  // eslint-disable-next-line no-process-exit
132
138
  process.exit(1);
@@ -138,7 +144,7 @@ module.exports = {
138
144
  throwError,
139
145
  selectFromList,
140
146
  showCreationError,
141
- getActionsManifest,
147
+ getEntityFromManifest,
142
148
  isValidNetwork,
143
149
  stripProtocol,
144
150
  };
package/lib/utils.test.js CHANGED
@@ -68,9 +68,8 @@ describe('removeProtocolFromUrl', () => {
68
68
  });
69
69
  });
70
70
 
71
- describe('getActionsManifest', () => {
71
+ describe('get actions from manifest', () => {
72
72
  let fs, exitStub, consoleLog, chalk;
73
- let DEFAULT_MANIFEST_PATH = 'path/to/manifest';
74
73
 
75
74
  const actionMock = {
76
75
  name: 'name',
@@ -94,7 +93,7 @@ describe('getActionsManifest', () => {
94
93
  red: stub(),
95
94
  };
96
95
 
97
- let { getActionsManifest } = proxyquire('./utils', { fs, chalk });
96
+ let { getEntityFromManifest } = proxyquire('./utils', { fs, chalk });
98
97
 
99
98
  beforeEach(() => {
100
99
  exitStub = stub(process, 'exit');
@@ -108,7 +107,7 @@ describe('getActionsManifest', () => {
108
107
  it('should return undefined if manifest does not exist', () => {
109
108
  fs.existsSync.returns(false);
110
109
 
111
- const result = getActionsManifest(DEFAULT_MANIFEST_PATH);
110
+ const result = getEntityFromManifest('actions');
112
111
 
113
112
  assert.equal(result, undefined);
114
113
  });
@@ -117,7 +116,7 @@ describe('getActionsManifest', () => {
117
116
  fs.existsSync.returns(true);
118
117
  fs.readFileSync.returns(JSON.stringify({ actions: [] }));
119
118
 
120
- const result = getActionsManifest(DEFAULT_MANIFEST_PATH);
119
+ const result = getEntityFromManifest('actions');
121
120
  assert.equal(result, undefined);
122
121
  });
123
122
 
@@ -126,10 +125,10 @@ describe('getActionsManifest', () => {
126
125
  fs.readFileSync.returns(
127
126
  JSON.stringify({
128
127
  actions: [actionMock],
129
- })
128
+ }),
130
129
  );
131
130
 
132
- const result = getActionsManifest();
131
+ const result = getEntityFromManifest('actions');
133
132
 
134
133
  assert.deepEqual(result, [resultMock]);
135
134
  assert.ok(consoleLog.called);
@@ -146,10 +145,10 @@ describe('getActionsManifest', () => {
146
145
  fs.readFileSync.returns(
147
146
  JSON.stringify({
148
147
  actions: [mockAction],
149
- })
148
+ }),
150
149
  );
151
150
 
152
- const result = getActionsManifest();
151
+ const result = getEntityFromManifest('actions');
153
152
 
154
153
  assert.deepEqual(result, [{ ...resultMock, allowNetworks: ['some.domain.tld'] }]);
155
154
  assert.ok(consoleLog.called);
@@ -160,10 +159,10 @@ describe('getActionsManifest', () => {
160
159
  fs.readFileSync.returns(
161
160
  JSON.stringify({
162
161
  actions: [actionMock],
163
- })
162
+ }),
164
163
  );
165
164
 
166
- const result = getActionsManifest();
165
+ const result = getEntityFromManifest('actions');
167
166
 
168
167
  assert.notDeepEqual(result, [actionMock]);
169
168
  });
@@ -179,10 +178,10 @@ describe('getActionsManifest', () => {
179
178
  allowNetworks: ['412.1.1.1'],
180
179
  },
181
180
  ],
182
- })
181
+ }),
183
182
  );
184
183
 
185
- getActionsManifest();
184
+ getEntityFromManifest('actions');
186
185
 
187
186
  assert.ok(exitStub.calledOnceWith(1));
188
187
  });
@@ -191,7 +190,133 @@ describe('getActionsManifest', () => {
191
190
  fs.existsSync.returns(true);
192
191
  fs.readFileSync.throws();
193
192
 
194
- getActionsManifest();
193
+ getEntityFromManifest('actions');
194
+
195
+ assert.ok(exitStub.calledOnceWith(1));
196
+ });
197
+ });
198
+
199
+ describe('get delivery functions from manifest', () => {
200
+ let fs, exitStub, consoleLog, chalk;
201
+
202
+ const deliveryFnMock = {
203
+ id: 'test',
204
+ name: 'name',
205
+ description: 'descriptoin',
206
+ path: 'delivery-functions/mock.js',
207
+ entryFile: './delivery-functions/mock.ts',
208
+ allowNetworks: ['127.0.0.1', 'some.domain.tld'],
209
+ };
210
+ // eslint-disable-next-line no-unused-vars
211
+ const { entryFile: _, ...resultMock } = deliveryFnMock;
212
+
213
+ fs = {
214
+ existsSync: stub(),
215
+ readFileSync: stub(),
216
+ };
217
+ chalk = {
218
+ bold: stub(),
219
+ red: stub(),
220
+ };
221
+
222
+ let { getEntityFromManifest } = proxyquire('./utils', { fs, chalk });
223
+
224
+ beforeEach(() => {
225
+ exitStub = stub(process, 'exit');
226
+ consoleLog = stub(console, 'log');
227
+ });
228
+ afterEach(() => {
229
+ exitStub.restore();
230
+ consoleLog.restore();
231
+ });
232
+
233
+ it('should return undefined if manifest does not exist', () => {
234
+ fs.existsSync.returns(false);
235
+
236
+ const result = getEntityFromManifest('deliveryFunctions');
237
+
238
+ assert.equal(result, undefined);
239
+ });
240
+
241
+ it('should return undefined if manifest has no delivery functions', () => {
242
+ fs.existsSync.returns(true);
243
+ fs.readFileSync.returns(JSON.stringify({ deliveryFunctions: [] }));
244
+
245
+ const result = getEntityFromManifest('deliveryFunctions');
246
+ assert.equal(result, undefined);
247
+ });
248
+
249
+ it('should return an array of delivery functions if manifest is valid', () => {
250
+ fs.existsSync.returns(true);
251
+ fs.readFileSync.returns(
252
+ JSON.stringify({
253
+ deliveryFunctions: [deliveryFnMock],
254
+ }),
255
+ );
256
+
257
+ const result = getEntityFromManifest('deliveryFunctions');
258
+
259
+ assert.deepEqual(result, [resultMock]);
260
+ assert.ok(consoleLog.called);
261
+ });
262
+
263
+ it('should strip the protocol when a domain has a protocol in allowNetworks', () => {
264
+ const mockDeliveryFn = {
265
+ ...deliveryFnMock,
266
+ allowNetworks: ['http://some.domain.tld'],
267
+ };
268
+ // eslint-disable-next-line no-unused-vars
269
+ const { entryFile: _, ...resultMock } = mockDeliveryFn;
270
+ fs.existsSync.returns(true);
271
+ fs.readFileSync.returns(
272
+ JSON.stringify({
273
+ deliveryFunctions: [mockDeliveryFn],
274
+ }),
275
+ );
276
+
277
+ const result = getEntityFromManifest('deliveryFunctions');
278
+
279
+ assert.deepEqual(result, [{ ...resultMock, allowNetworks: ['some.domain.tld'] }]);
280
+ assert.ok(consoleLog.called);
281
+ });
282
+
283
+ it('should return an array of delivery functions without entryFile prop if manifest is valid', () => {
284
+ fs.existsSync.returns(true);
285
+ fs.readFileSync.returns(
286
+ JSON.stringify({
287
+ deliveryFunctions: [deliveryFnMock],
288
+ }),
289
+ );
290
+
291
+ const result = getEntityFromManifest('deliveryFunctions');
292
+
293
+ assert.notDeepEqual(result, [deliveryFnMock]);
294
+ });
295
+
296
+ it('should exit with error if invalid network is found in allowNetworks', () => {
297
+ fs.existsSync.returns(true);
298
+ fs.readFileSync.returns(
299
+ JSON.stringify({
300
+ deliveryFunctions: [
301
+ {
302
+ name: 'test resolver fn',
303
+ entryFile: 'entry1',
304
+ allowNetworks: ['412.1.1.1'],
305
+ },
306
+ ],
307
+ }),
308
+ );
309
+
310
+ getEntityFromManifest('deliveryFunctions');
311
+
312
+ assert.ok(exitStub.calledOnceWith(1));
313
+ });
314
+
315
+ it('should exit with error if manifest is invalid JSON', () => {
316
+ fs.existsSync.returns(true);
317
+ fs.readFileSync.throws();
318
+
319
+ getEntityFromManifest('deliveryFunctions');
195
320
 
196
321
  assert.ok(exitStub.calledOnceWith(1));
197
322
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/app-scripts",
3
- "version": "1.11.0",
3
+ "version": "1.12.0",
4
4
  "description": "A collection of scripts for building Contentful Apps",
5
5
  "author": "Contentful GmbH",
6
6
  "license": "MIT",
@@ -27,7 +27,7 @@
27
27
  "prettier": "prettier **/*.js --write --ignore-path .gitignore",
28
28
  "lint": "eslint ./lib",
29
29
  "lint:fix": "npm run lint -- --fix",
30
- "test": "mocha ./lib/**/*.test.js ./lib/*.test.js ./utils/**/*.test.js",
30
+ "test": "mocha \"./{,!(node_modules)/**/}*.test.js\" --exit",
31
31
  "test:watch": "npm t -- --watch",
32
32
  "pre-commit": "lint-staged"
33
33
  },
@@ -53,7 +53,7 @@
53
53
  "bottleneck": "2.19.5",
54
54
  "chalk": "4.1.2",
55
55
  "commander": "11.0.0",
56
- "contentful-management": "10.39.2",
56
+ "contentful-management": "10.40.0",
57
57
  "dotenv": "16.3.1",
58
58
  "ignore": "5.2.4",
59
59
  "inquirer": "8.2.6",
@@ -61,5 +61,5 @@
61
61
  "open": "8.4.2",
62
62
  "ora": "5.4.1"
63
63
  },
64
- "gitHead": "5c1470b0d752ec3e8e6cdf412b8ea2d1183a32ab"
64
+ "gitHead": "e6ee977c9fc8db111bcd36c8caa1550f4829afb6"
65
65
  }