@saltcorn/cli 1.6.0-alpha.0 → 1.6.0-alpha.2
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.
- package/README.md +67 -58
- package/npm-shrinkwrap.json +562 -602
- package/oclif.manifest.json +27 -1
- package/package.json +8 -8
- package/src/commands/build-app.js +46 -22
- package/src/commands/dev/plugin-test.js +72 -22
package/oclif.manifest.json
CHANGED
|
@@ -264,6 +264,12 @@
|
|
|
264
264
|
"allowNo": false,
|
|
265
265
|
"type": "boolean"
|
|
266
266
|
},
|
|
267
|
+
"syncOnAppResume": {
|
|
268
|
+
"description": "When offline mode is enabled, synchronize the synchedTables tables when the app is resumed.",
|
|
269
|
+
"name": "syncOnAppResume",
|
|
270
|
+
"allowNo": false,
|
|
271
|
+
"type": "boolean"
|
|
272
|
+
},
|
|
267
273
|
"pushSync": {
|
|
268
274
|
"description": "When offline mode is enabled, synchronize the synchedTables tables when a push notification is received.",
|
|
269
275
|
"name": "pushSync",
|
|
@@ -277,6 +283,12 @@
|
|
|
277
283
|
"multiple": false,
|
|
278
284
|
"type": "option"
|
|
279
285
|
},
|
|
286
|
+
"noProvisioningProfile": {
|
|
287
|
+
"description": "Do not use a provisioning profile, only for simulator builds (iOS only)",
|
|
288
|
+
"name": "noProvisioningProfile",
|
|
289
|
+
"allowNo": false,
|
|
290
|
+
"type": "boolean"
|
|
291
|
+
},
|
|
280
292
|
"provisioningProfile": {
|
|
281
293
|
"description": "This profile will be used to sign your app",
|
|
282
294
|
"name": "provisioningProfile",
|
|
@@ -298,6 +310,12 @@
|
|
|
298
310
|
"multiple": false,
|
|
299
311
|
"type": "option"
|
|
300
312
|
},
|
|
313
|
+
"allowClearTextTraffic": {
|
|
314
|
+
"description": "Enable this to allow unsecure HTTP connections. Useful for local testing.",
|
|
315
|
+
"name": "allowClearTextTraffic",
|
|
316
|
+
"allowNo": false,
|
|
317
|
+
"type": "boolean"
|
|
318
|
+
},
|
|
301
319
|
"androidKeystore": {
|
|
302
320
|
"description": "A self-signed certificate that includes the private key used to sign your app.",
|
|
303
321
|
"name": "androidKeystore",
|
|
@@ -2127,6 +2145,14 @@
|
|
|
2127
2145
|
"hasDynamicHelp": false,
|
|
2128
2146
|
"multiple": false,
|
|
2129
2147
|
"type": "option"
|
|
2148
|
+
},
|
|
2149
|
+
"overwriteDependency": {
|
|
2150
|
+
"char": "o",
|
|
2151
|
+
"description": "Dependency to overwrite with a local plugin (can be used multiple times). Please specify the path to the local plugin, the module name will be taken from there.",
|
|
2152
|
+
"name": "overwriteDependency",
|
|
2153
|
+
"hasDynamicHelp": false,
|
|
2154
|
+
"multiple": true,
|
|
2155
|
+
"type": "option"
|
|
2130
2156
|
}
|
|
2131
2157
|
},
|
|
2132
2158
|
"hasDynamicHelp": false,
|
|
@@ -2315,5 +2341,5 @@
|
|
|
2315
2341
|
]
|
|
2316
2342
|
}
|
|
2317
2343
|
},
|
|
2318
|
-
"version": "1.6.0-alpha.
|
|
2344
|
+
"version": "1.6.0-alpha.2"
|
|
2319
2345
|
}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@saltcorn/cli",
|
|
3
3
|
"description": "Command-line interface for Saltcorn, open-source no-code platform",
|
|
4
4
|
"homepage": "https://saltcorn.com",
|
|
5
|
-
"version": "1.6.0-alpha.
|
|
5
|
+
"version": "1.6.0-alpha.2",
|
|
6
6
|
"author": "Tom Nielsen @glutamate",
|
|
7
7
|
"bin": {
|
|
8
8
|
"saltcorn": "./bin/saltcorn"
|
|
@@ -11,13 +11,13 @@
|
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@oclif/core": "4.4.0",
|
|
13
13
|
"@oclif/plugin-plugins": "^5.4.26",
|
|
14
|
-
"@saltcorn/admin-models": "1.6.0-alpha.
|
|
15
|
-
"@saltcorn/common-code": "1.6.0-alpha.
|
|
16
|
-
"@saltcorn/data": "1.6.0-alpha.
|
|
17
|
-
"@saltcorn/mobile-app": "1.6.0-alpha.
|
|
18
|
-
"@saltcorn/mobile-builder": "1.6.0-alpha.
|
|
19
|
-
"@saltcorn/plugins-loader": "1.6.0-alpha.
|
|
20
|
-
"@saltcorn/server": "1.6.0-alpha.
|
|
14
|
+
"@saltcorn/admin-models": "1.6.0-alpha.2",
|
|
15
|
+
"@saltcorn/common-code": "1.6.0-alpha.2",
|
|
16
|
+
"@saltcorn/data": "1.6.0-alpha.2",
|
|
17
|
+
"@saltcorn/mobile-app": "1.6.0-alpha.2",
|
|
18
|
+
"@saltcorn/mobile-builder": "1.6.0-alpha.2",
|
|
19
|
+
"@saltcorn/plugins-loader": "1.6.0-alpha.2",
|
|
20
|
+
"@saltcorn/server": "1.6.0-alpha.2",
|
|
21
21
|
"contractis": "^0.1.0",
|
|
22
22
|
"dateformat": "^4.6.3",
|
|
23
23
|
"inquirer": "^12.3.3",
|
|
@@ -2,9 +2,7 @@ const { Command, Flags } = require("@oclif/core");
|
|
|
2
2
|
const path = require("path");
|
|
3
3
|
const Plugin = require("@saltcorn/data/models/plugin");
|
|
4
4
|
const { MobileBuilder } = require("@saltcorn/mobile-builder/mobile-builder");
|
|
5
|
-
const {
|
|
6
|
-
decodeProvisioningProfile,
|
|
7
|
-
} = require("@saltcorn/mobile-builder/utils/common-build-utils");
|
|
5
|
+
const { decodeProvisioningProfile } = require("@saltcorn/data/utils");
|
|
8
6
|
const { init_multi_tenant, getState } = require("@saltcorn/data/db/state");
|
|
9
7
|
const { loadAllPlugins } = require("@saltcorn/server/load_plugins");
|
|
10
8
|
const User = require("@saltcorn/data/models/user");
|
|
@@ -44,7 +42,7 @@ class BuildAppCommand extends Command {
|
|
|
44
42
|
);
|
|
45
43
|
}
|
|
46
44
|
|
|
47
|
-
if (flags.platforms.includes("ios")) {
|
|
45
|
+
if (flags.platforms.includes("ios") && !flags.noProvisioningProfile) {
|
|
48
46
|
if (!flags.provisioningProfile)
|
|
49
47
|
throw new Error("Please specify a provisioning profile");
|
|
50
48
|
if (flags.allowShareTo && !flags.shareExtensionProvisioningProfile)
|
|
@@ -73,26 +71,30 @@ class BuildAppCommand extends Command {
|
|
|
73
71
|
async buildIosParams(flags) {
|
|
74
72
|
let result = undefined;
|
|
75
73
|
if (flags.platforms.includes("ios")) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
guuid: mainProfileVals.guuid,
|
|
84
|
-
},
|
|
85
|
-
};
|
|
86
|
-
if (flags.allowShareTo) {
|
|
87
|
-
const shareExtProfileVals = await decodeProvisioningProfile(
|
|
88
|
-
flags.buildDirectory,
|
|
89
|
-
flags.shareExtensionProvisioningProfile
|
|
74
|
+
if (flags.noProvisioningProfile)
|
|
75
|
+
result = {
|
|
76
|
+
noProvisioningProfile: true,
|
|
77
|
+
};
|
|
78
|
+
else {
|
|
79
|
+
const mainProfileVals = await decodeProvisioningProfile(
|
|
80
|
+
flags.provisioningProfile
|
|
90
81
|
);
|
|
91
|
-
result
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
82
|
+
result = {
|
|
83
|
+
appleTeamId: mainProfileVals.teamId,
|
|
84
|
+
mainProvisioningProfile: {
|
|
85
|
+
guuid: mainProfileVals.guuid,
|
|
86
|
+
},
|
|
95
87
|
};
|
|
88
|
+
if (flags.allowShareTo) {
|
|
89
|
+
const shareExtProfileVals = await decodeProvisioningProfile(
|
|
90
|
+
flags.shareExtensionProvisioningProfile
|
|
91
|
+
);
|
|
92
|
+
result.shareExtensionProvisioningProfile = {
|
|
93
|
+
guuid: shareExtProfileVals.guuid,
|
|
94
|
+
specifier: shareExtProfileVals.specifier,
|
|
95
|
+
identifier: shareExtProfileVals.identifier,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
96
98
|
}
|
|
97
99
|
}
|
|
98
100
|
return result;
|
|
@@ -138,6 +140,7 @@ class BuildAppCommand extends Command {
|
|
|
138
140
|
showContinueAsPublicUser: flags.showContinueAsPublicUser,
|
|
139
141
|
allowOfflineMode: flags.allowOfflineMode,
|
|
140
142
|
syncOnReconnect: flags.syncOnReconnect,
|
|
143
|
+
syncOnAppResume: flags.syncOnAppResume,
|
|
141
144
|
pushSync: flags.pushSync,
|
|
142
145
|
syncInterval: flags.syncInterval,
|
|
143
146
|
allowShareTo: flags.allowShareTo,
|
|
@@ -147,6 +150,7 @@ class BuildAppCommand extends Command {
|
|
|
147
150
|
iosParams: iosParams,
|
|
148
151
|
tenantAppName: flags.tenantAppName,
|
|
149
152
|
buildType: flags.buildType,
|
|
153
|
+
allowClearTextTraffic: flags.allowClearTextTraffic,
|
|
150
154
|
keyStorePath: flags.androidKeystore,
|
|
151
155
|
keyStoreAlias: flags.androidKeyStoreAlias,
|
|
152
156
|
keyStorePassword: flags.androidKeystorePassword,
|
|
@@ -324,6 +328,12 @@ BuildAppCommand.flags = {
|
|
|
324
328
|
"Run Synchronizations and return into online mode when the network connection is restored. " +
|
|
325
329
|
"When disabled, you still can do this manually.",
|
|
326
330
|
}),
|
|
331
|
+
syncOnAppResume: Flags.boolean({
|
|
332
|
+
name: "Sync on app resume",
|
|
333
|
+
string: "syncOnAppResume",
|
|
334
|
+
description:
|
|
335
|
+
"When offline mode is enabled, synchronize the synchedTables tables when the app is resumed.",
|
|
336
|
+
}),
|
|
327
337
|
pushSync: Flags.boolean({
|
|
328
338
|
name: "Push sync",
|
|
329
339
|
string: "pushSync",
|
|
@@ -337,6 +347,13 @@ BuildAppCommand.flags = {
|
|
|
337
347
|
"Perdiodic interval (in minutes) to run synchronizations in the background. " +
|
|
338
348
|
"This is just a min interval, depending on system conditions, the actual time may be longer.",
|
|
339
349
|
}),
|
|
350
|
+
noProvisioningProfile: Flags.boolean({
|
|
351
|
+
name: "no provisioning profile",
|
|
352
|
+
string: "noProvisioningProfile",
|
|
353
|
+
description:
|
|
354
|
+
"Do not use a provisioning profile, only for simulator builds (iOS only)",
|
|
355
|
+
default: false,
|
|
356
|
+
}),
|
|
340
357
|
provisioningProfile: Flags.string({
|
|
341
358
|
name: "provisioning profile",
|
|
342
359
|
string: "provisioningProfile",
|
|
@@ -353,6 +370,13 @@ BuildAppCommand.flags = {
|
|
|
353
370
|
string: "buildType",
|
|
354
371
|
description: "debug or release build",
|
|
355
372
|
}),
|
|
373
|
+
allowClearTextTraffic: Flags.boolean({
|
|
374
|
+
name: "allow clear text traffic",
|
|
375
|
+
string: "allowClearTextTraffic",
|
|
376
|
+
description:
|
|
377
|
+
"Enable this to allow unsecure HTTP connections. Useful for local testing.",
|
|
378
|
+
default: false,
|
|
379
|
+
}),
|
|
356
380
|
androidKeystore: Flags.string({
|
|
357
381
|
name: "android key store",
|
|
358
382
|
string: "androidKeyStore",
|
|
@@ -15,7 +15,9 @@ const removePluginsDir = () => {
|
|
|
15
15
|
fs.rmSync(pluginsPath, { force: true, recursive: true });
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
-
const writeJestConfigIntoPluginDir = (location) => {
|
|
18
|
+
const writeJestConfigIntoPluginDir = (location, plugin) => {
|
|
19
|
+
const state = getState();
|
|
20
|
+
const module = state.plugins[plugin.name];
|
|
19
21
|
fs.writeFileSync(
|
|
20
22
|
path.join(location, "jest.config.js"),
|
|
21
23
|
`const sqliteDir = process.env.JEST_SC_SQLITE_DIR;
|
|
@@ -35,6 +37,17 @@ const config = {
|
|
|
35
37
|
"@saltcorn/markup$": markupDir,
|
|
36
38
|
"@saltcorn/markup/(.*)": markupDir + "/$1",
|
|
37
39
|
"@saltcorn/admin-models/(.*)": adminModelsDir + "/$1",
|
|
40
|
+
${(module?.dependencies || [])
|
|
41
|
+
.map((dep) => {
|
|
42
|
+
let pluginLocation = state.plugin_locations[dep];
|
|
43
|
+
if (!pluginLocation) {
|
|
44
|
+
// try without org
|
|
45
|
+
const orgRemoved = dep.replace(/^@[^/]+\//, "");
|
|
46
|
+
pluginLocation = state.plugin_locations[orgRemoved];
|
|
47
|
+
}
|
|
48
|
+
return pluginLocation ? `"${dep}": "${pluginLocation}",` : "";
|
|
49
|
+
})
|
|
50
|
+
.join("\n ")}
|
|
38
51
|
},
|
|
39
52
|
modulePaths: [modulePath],
|
|
40
53
|
};
|
|
@@ -77,42 +90,48 @@ const spawnTest = async (installDir, env) => {
|
|
|
77
90
|
return ret.status;
|
|
78
91
|
};
|
|
79
92
|
|
|
80
|
-
const
|
|
93
|
+
const preparePlugin = async (plugin, overwrites) => {
|
|
81
94
|
await removeOldPlugin(plugin);
|
|
82
95
|
removePluginsDir();
|
|
83
|
-
await loadAndSaveNewPlugin(
|
|
96
|
+
await loadAndSaveNewPlugin(
|
|
97
|
+
plugin,
|
|
98
|
+
false,
|
|
99
|
+
false,
|
|
100
|
+
(str) => str,
|
|
101
|
+
false,
|
|
102
|
+
overwrites
|
|
103
|
+
);
|
|
84
104
|
const location = getPluginLocation(plugin.name);
|
|
85
105
|
writeMockFilesIntoPluginDir(location);
|
|
86
|
-
writeJestConfigIntoPluginDir(location);
|
|
106
|
+
writeJestConfigIntoPluginDir(location, plugin);
|
|
87
107
|
return location;
|
|
88
108
|
};
|
|
89
109
|
|
|
90
|
-
const removeOldPlugin = async (
|
|
91
|
-
const byName = await Plugin.findOne({ name:
|
|
110
|
+
const removeOldPlugin = async (newPlugin) => {
|
|
111
|
+
const byName = await Plugin.findOne({ name: newPlugin.name });
|
|
92
112
|
if (byName) {
|
|
93
113
|
await byName.delete();
|
|
94
114
|
await new PluginInstaller(byName).remove();
|
|
95
115
|
}
|
|
96
|
-
let
|
|
97
|
-
if (!
|
|
98
|
-
const withOrg = await Plugin.findOne({
|
|
116
|
+
let oldDbPlugin = null;
|
|
117
|
+
if (!newPlugin.name.startsWith("@saltcorn/")) {
|
|
118
|
+
const withOrg = await Plugin.findOne({
|
|
119
|
+
name: `@saltcorn/${newPlugin.name}`,
|
|
120
|
+
});
|
|
99
121
|
if (withOrg) {
|
|
100
122
|
await withOrg.delete();
|
|
101
|
-
|
|
123
|
+
oldDbPlugin = withOrg;
|
|
102
124
|
}
|
|
103
125
|
} else {
|
|
104
126
|
const withoutOrg = await Plugin.findOne({
|
|
105
|
-
name:
|
|
127
|
+
name: newPlugin.name.replace(/^@saltcorn\//, ""),
|
|
106
128
|
});
|
|
107
129
|
if (withoutOrg) {
|
|
108
130
|
await withoutOrg.delete();
|
|
109
|
-
|
|
131
|
+
oldDbPlugin = withoutOrg;
|
|
110
132
|
}
|
|
111
133
|
}
|
|
112
|
-
|
|
113
|
-
const installer = new PluginInstaller(oldPlugin);
|
|
114
|
-
await installer.remove();
|
|
115
|
-
}
|
|
134
|
+
await new PluginInstaller(oldDbPlugin || newPlugin).remove();
|
|
116
135
|
};
|
|
117
136
|
|
|
118
137
|
const getPluginLocation = (pluginName) => {
|
|
@@ -123,7 +142,7 @@ const getPluginLocation = (pluginName) => {
|
|
|
123
142
|
);
|
|
124
143
|
};
|
|
125
144
|
|
|
126
|
-
const testLocalPlugin = async (dir, env, backupFile) => {
|
|
145
|
+
const testLocalPlugin = async (dir, env, backupFile, overwrites) => {
|
|
127
146
|
if (backupFile) {
|
|
128
147
|
await prep_test_db(path.join(dir, "tests", backupFile));
|
|
129
148
|
} else await require("@saltcorn/data/db/reset_schema")();
|
|
@@ -135,27 +154,49 @@ const testLocalPlugin = async (dir, env, backupFile) => {
|
|
|
135
154
|
source: "local",
|
|
136
155
|
location: path.resolve(dir),
|
|
137
156
|
});
|
|
138
|
-
const installDir = await
|
|
157
|
+
const installDir = await preparePlugin(plugin, overwrites);
|
|
139
158
|
return await spawnTest(installDir, env);
|
|
140
159
|
};
|
|
141
160
|
|
|
142
|
-
const testReleasedPlugin = async (pluginName, env, backupFile) => {
|
|
161
|
+
const testReleasedPlugin = async (pluginName, env, backupFile, overwrites) => {
|
|
143
162
|
await require("@saltcorn/data/db/reset_schema")();
|
|
144
163
|
const plugin = await Plugin.store_by_name(pluginName);
|
|
145
164
|
delete plugin.id;
|
|
146
|
-
const installDir = await
|
|
165
|
+
const installDir = await preparePlugin(plugin, overwrites);
|
|
147
166
|
if (backupFile) {
|
|
148
167
|
await prep_test_db(path.join(installDir, "tests", backupFile));
|
|
149
168
|
}
|
|
150
169
|
return await spawnTest(installDir, env);
|
|
151
170
|
};
|
|
152
171
|
|
|
172
|
+
/**
|
|
173
|
+
*
|
|
174
|
+
* @param {string[]} overwrites paths to local plugins
|
|
175
|
+
* @returns an object mapping module names to paths
|
|
176
|
+
*/
|
|
177
|
+
const prepOverwritesCfg = (overwrites) => {
|
|
178
|
+
const result = {};
|
|
179
|
+
if (overwrites) {
|
|
180
|
+
for (const flag of overwrites) {
|
|
181
|
+
const pkgpath = path.join(flag, "package.json");
|
|
182
|
+
if (!fs.existsSync(pkgpath))
|
|
183
|
+
throw new Error(
|
|
184
|
+
`Overwrite dependency package.json not found in ${flag}`
|
|
185
|
+
);
|
|
186
|
+
const pkg = require(pkgpath);
|
|
187
|
+
result[pkg.name] = flag;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return result;
|
|
191
|
+
};
|
|
192
|
+
|
|
153
193
|
/**
|
|
154
194
|
* Install a plugin, spawn 'npm run test' in the install dir and check the return code
|
|
155
195
|
*/
|
|
156
196
|
class PluginTestCommand extends Command {
|
|
157
197
|
async run() {
|
|
158
198
|
const { flags } = await this.parse(PluginTestCommand);
|
|
199
|
+
const overwrites = prepOverwritesCfg(flags.overwriteDependency);
|
|
159
200
|
const dbname = flags.database ? flags.database : "saltcorn_test";
|
|
160
201
|
let env = null;
|
|
161
202
|
const db = require("@saltcorn/data/db");
|
|
@@ -174,14 +215,16 @@ class PluginTestCommand extends Command {
|
|
|
174
215
|
jestStatus = await testLocalPlugin(
|
|
175
216
|
flags.directory,
|
|
176
217
|
env,
|
|
177
|
-
flags.backupFile
|
|
218
|
+
flags.backupFile,
|
|
219
|
+
overwrites
|
|
178
220
|
);
|
|
179
221
|
} else if (flags.name) {
|
|
180
222
|
console.log(`Testing released plugin '${flags.name}'`);
|
|
181
223
|
jestStatus = await testReleasedPlugin(
|
|
182
224
|
flags.name,
|
|
183
225
|
env,
|
|
184
|
-
flags.backupFile
|
|
226
|
+
flags.backupFile,
|
|
227
|
+
overwrites
|
|
185
228
|
);
|
|
186
229
|
}
|
|
187
230
|
} catch (error) {
|
|
@@ -218,6 +261,13 @@ PluginTestCommand.flags = {
|
|
|
218
261
|
string: "database",
|
|
219
262
|
description: "Run on specified database. Default is 'saltcorn_test''",
|
|
220
263
|
}),
|
|
264
|
+
overwriteDependency: Flags.string({
|
|
265
|
+
char: "o",
|
|
266
|
+
description:
|
|
267
|
+
"Dependency to overwrite with a local plugin (can be used multiple times). " +
|
|
268
|
+
"Please specify the path to the local plugin, the module name will be taken from there.",
|
|
269
|
+
multiple: true,
|
|
270
|
+
}),
|
|
221
271
|
};
|
|
222
272
|
|
|
223
273
|
PluginTestCommand.description =
|