@saltcorn/cli 1.6.0-alpha.0 → 1.6.0-alpha.10
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 +106 -58
- package/npm-shrinkwrap.json +1206 -1265
- package/oclif.manifest.json +106 -1
- package/package.json +8 -8
- package/src/commands/build-app.js +53 -22
- package/src/commands/dev/build.js +47 -0
- package/src/commands/dev/plugin-test.js +73 -22
- package/src/commands/dev/release.js +1 -0
- package/src/commands/dev/serve.js +75 -0
- package/src/commands/restore.js +3 -1
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",
|
|
@@ -291,6 +303,13 @@
|
|
|
291
303
|
"multiple": false,
|
|
292
304
|
"type": "option"
|
|
293
305
|
},
|
|
306
|
+
"appGroupId": {
|
|
307
|
+
"description": "An app group identifier to share data between the main app and the share extension on iOS, e.g. group.com.saltcorn.myapp",
|
|
308
|
+
"name": "appGroupId",
|
|
309
|
+
"hasDynamicHelp": false,
|
|
310
|
+
"multiple": false,
|
|
311
|
+
"type": "option"
|
|
312
|
+
},
|
|
294
313
|
"buildType": {
|
|
295
314
|
"description": "debug or release build",
|
|
296
315
|
"name": "buildType",
|
|
@@ -298,6 +317,12 @@
|
|
|
298
317
|
"multiple": false,
|
|
299
318
|
"type": "option"
|
|
300
319
|
},
|
|
320
|
+
"allowClearTextTraffic": {
|
|
321
|
+
"description": "Enable this to allow unsecure HTTP connections. Useful for local testing.",
|
|
322
|
+
"name": "allowClearTextTraffic",
|
|
323
|
+
"allowNo": false,
|
|
324
|
+
"type": "boolean"
|
|
325
|
+
},
|
|
301
326
|
"androidKeystore": {
|
|
302
327
|
"description": "A self-signed certificate that includes the private key used to sign your app.",
|
|
303
328
|
"name": "androidKeystore",
|
|
@@ -2022,6 +2047,38 @@
|
|
|
2022
2047
|
"transform-field.js"
|
|
2023
2048
|
]
|
|
2024
2049
|
},
|
|
2050
|
+
"dev:build": {
|
|
2051
|
+
"aliases": [],
|
|
2052
|
+
"args": {
|
|
2053
|
+
"component": {
|
|
2054
|
+
"description": "Component to rebuild",
|
|
2055
|
+
"name": "component",
|
|
2056
|
+
"options": [
|
|
2057
|
+
"builder",
|
|
2058
|
+
"filemanager",
|
|
2059
|
+
"workflow-editor"
|
|
2060
|
+
],
|
|
2061
|
+
"required": false
|
|
2062
|
+
}
|
|
2063
|
+
},
|
|
2064
|
+
"description": "Rebuild static assets",
|
|
2065
|
+
"flags": {},
|
|
2066
|
+
"hasDynamicHelp": false,
|
|
2067
|
+
"hiddenAliases": [],
|
|
2068
|
+
"id": "dev:build",
|
|
2069
|
+
"pluginAlias": "@saltcorn/cli",
|
|
2070
|
+
"pluginName": "@saltcorn/cli",
|
|
2071
|
+
"pluginType": "core",
|
|
2072
|
+
"strict": true,
|
|
2073
|
+
"enableJsonFlag": false,
|
|
2074
|
+
"isESM": false,
|
|
2075
|
+
"relativePath": [
|
|
2076
|
+
"src",
|
|
2077
|
+
"commands",
|
|
2078
|
+
"dev",
|
|
2079
|
+
"build.js"
|
|
2080
|
+
]
|
|
2081
|
+
},
|
|
2025
2082
|
"dev:localize-plugin": {
|
|
2026
2083
|
"aliases": [],
|
|
2027
2084
|
"args": {
|
|
@@ -2127,6 +2184,14 @@
|
|
|
2127
2184
|
"hasDynamicHelp": false,
|
|
2128
2185
|
"multiple": false,
|
|
2129
2186
|
"type": "option"
|
|
2187
|
+
},
|
|
2188
|
+
"overwriteDependency": {
|
|
2189
|
+
"char": "o",
|
|
2190
|
+
"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.",
|
|
2191
|
+
"name": "overwriteDependency",
|
|
2192
|
+
"hasDynamicHelp": false,
|
|
2193
|
+
"multiple": true,
|
|
2194
|
+
"type": "option"
|
|
2130
2195
|
}
|
|
2131
2196
|
},
|
|
2132
2197
|
"hasDynamicHelp": false,
|
|
@@ -2251,6 +2316,46 @@
|
|
|
2251
2316
|
"release.js"
|
|
2252
2317
|
]
|
|
2253
2318
|
},
|
|
2319
|
+
"dev:serve": {
|
|
2320
|
+
"aliases": [],
|
|
2321
|
+
"args": {},
|
|
2322
|
+
"description": "Development server. Serve on port 3000, restart when source files change",
|
|
2323
|
+
"flags": {
|
|
2324
|
+
"port": {
|
|
2325
|
+
"char": "p",
|
|
2326
|
+
"description": "port",
|
|
2327
|
+
"name": "port",
|
|
2328
|
+
"default": 3000,
|
|
2329
|
+
"hasDynamicHelp": false,
|
|
2330
|
+
"multiple": false,
|
|
2331
|
+
"type": "option"
|
|
2332
|
+
},
|
|
2333
|
+
"workers": {
|
|
2334
|
+
"char": "w",
|
|
2335
|
+
"description": "workers",
|
|
2336
|
+
"name": "workers",
|
|
2337
|
+
"default": 1,
|
|
2338
|
+
"hasDynamicHelp": false,
|
|
2339
|
+
"multiple": false,
|
|
2340
|
+
"type": "option"
|
|
2341
|
+
}
|
|
2342
|
+
},
|
|
2343
|
+
"hasDynamicHelp": false,
|
|
2344
|
+
"hiddenAliases": [],
|
|
2345
|
+
"id": "dev:serve",
|
|
2346
|
+
"pluginAlias": "@saltcorn/cli",
|
|
2347
|
+
"pluginName": "@saltcorn/cli",
|
|
2348
|
+
"pluginType": "core",
|
|
2349
|
+
"strict": true,
|
|
2350
|
+
"enableJsonFlag": false,
|
|
2351
|
+
"isESM": false,
|
|
2352
|
+
"relativePath": [
|
|
2353
|
+
"src",
|
|
2354
|
+
"commands",
|
|
2355
|
+
"dev",
|
|
2356
|
+
"serve.js"
|
|
2357
|
+
]
|
|
2358
|
+
},
|
|
2254
2359
|
"dev:test-plugin": {
|
|
2255
2360
|
"aliases": [],
|
|
2256
2361
|
"args": {
|
|
@@ -2315,5 +2420,5 @@
|
|
|
2315
2420
|
]
|
|
2316
2421
|
}
|
|
2317
2422
|
},
|
|
2318
|
-
"version": "1.6.0-alpha.
|
|
2423
|
+
"version": "1.6.0-alpha.10"
|
|
2319
2424
|
}
|
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.10",
|
|
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.10",
|
|
15
|
+
"@saltcorn/common-code": "1.6.0-alpha.10",
|
|
16
|
+
"@saltcorn/data": "1.6.0-alpha.10",
|
|
17
|
+
"@saltcorn/mobile-app": "1.6.0-alpha.10",
|
|
18
|
+
"@saltcorn/mobile-builder": "1.6.0-alpha.10",
|
|
19
|
+
"@saltcorn/plugins-loader": "1.6.0-alpha.10",
|
|
20
|
+
"@saltcorn/server": "1.6.0-alpha.10",
|
|
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,31 @@ 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
|
+
...(flags.appGroupId ? { appGroupId: flags.appGroupId } : {}),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
96
99
|
}
|
|
97
100
|
}
|
|
98
101
|
return result;
|
|
@@ -138,6 +141,7 @@ class BuildAppCommand extends Command {
|
|
|
138
141
|
showContinueAsPublicUser: flags.showContinueAsPublicUser,
|
|
139
142
|
allowOfflineMode: flags.allowOfflineMode,
|
|
140
143
|
syncOnReconnect: flags.syncOnReconnect,
|
|
144
|
+
syncOnAppResume: flags.syncOnAppResume,
|
|
141
145
|
pushSync: flags.pushSync,
|
|
142
146
|
syncInterval: flags.syncInterval,
|
|
143
147
|
allowShareTo: flags.allowShareTo,
|
|
@@ -147,6 +151,7 @@ class BuildAppCommand extends Command {
|
|
|
147
151
|
iosParams: iosParams,
|
|
148
152
|
tenantAppName: flags.tenantAppName,
|
|
149
153
|
buildType: flags.buildType,
|
|
154
|
+
allowClearTextTraffic: flags.allowClearTextTraffic,
|
|
150
155
|
keyStorePath: flags.androidKeystore,
|
|
151
156
|
keyStoreAlias: flags.androidKeyStoreAlias,
|
|
152
157
|
keyStorePassword: flags.androidKeystorePassword,
|
|
@@ -324,6 +329,12 @@ BuildAppCommand.flags = {
|
|
|
324
329
|
"Run Synchronizations and return into online mode when the network connection is restored. " +
|
|
325
330
|
"When disabled, you still can do this manually.",
|
|
326
331
|
}),
|
|
332
|
+
syncOnAppResume: Flags.boolean({
|
|
333
|
+
name: "Sync on app resume",
|
|
334
|
+
string: "syncOnAppResume",
|
|
335
|
+
description:
|
|
336
|
+
"When offline mode is enabled, synchronize the synchedTables tables when the app is resumed.",
|
|
337
|
+
}),
|
|
327
338
|
pushSync: Flags.boolean({
|
|
328
339
|
name: "Push sync",
|
|
329
340
|
string: "pushSync",
|
|
@@ -337,6 +348,13 @@ BuildAppCommand.flags = {
|
|
|
337
348
|
"Perdiodic interval (in minutes) to run synchronizations in the background. " +
|
|
338
349
|
"This is just a min interval, depending on system conditions, the actual time may be longer.",
|
|
339
350
|
}),
|
|
351
|
+
noProvisioningProfile: Flags.boolean({
|
|
352
|
+
name: "no provisioning profile",
|
|
353
|
+
string: "noProvisioningProfile",
|
|
354
|
+
description:
|
|
355
|
+
"Do not use a provisioning profile, only for simulator builds (iOS only)",
|
|
356
|
+
default: false,
|
|
357
|
+
}),
|
|
340
358
|
provisioningProfile: Flags.string({
|
|
341
359
|
name: "provisioning profile",
|
|
342
360
|
string: "provisioningProfile",
|
|
@@ -348,11 +366,24 @@ BuildAppCommand.flags = {
|
|
|
348
366
|
description:
|
|
349
367
|
"This profile will be used to sign your share extension on iOS",
|
|
350
368
|
}),
|
|
369
|
+
appGroupId: Flags.string({
|
|
370
|
+
name: "app group id",
|
|
371
|
+
string: "appGroupId",
|
|
372
|
+
description:
|
|
373
|
+
"An app group identifier to share data between the main app and the share extension on iOS, e.g. group.com.saltcorn.myapp",
|
|
374
|
+
}),
|
|
351
375
|
buildType: Flags.string({
|
|
352
376
|
name: "build type",
|
|
353
377
|
string: "buildType",
|
|
354
378
|
description: "debug or release build",
|
|
355
379
|
}),
|
|
380
|
+
allowClearTextTraffic: Flags.boolean({
|
|
381
|
+
name: "allow clear text traffic",
|
|
382
|
+
string: "allowClearTextTraffic",
|
|
383
|
+
description:
|
|
384
|
+
"Enable this to allow unsecure HTTP connections. Useful for local testing.",
|
|
385
|
+
default: false,
|
|
386
|
+
}),
|
|
356
387
|
androidKeystore: Flags.string({
|
|
357
388
|
name: "android key store",
|
|
358
389
|
string: "androidKeyStore",
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @category saltcorn-cli
|
|
3
|
+
* @module commands/dev/build
|
|
4
|
+
*/
|
|
5
|
+
const { Command, Flags, Args } = require("@oclif/core");
|
|
6
|
+
const { spawnSync } = require("child_process");
|
|
7
|
+
const { sleep } = require("../../common");
|
|
8
|
+
/**
|
|
9
|
+
* DevBuildCommand Class
|
|
10
|
+
* @extends oclif.Command
|
|
11
|
+
* @category saltcorn-cli
|
|
12
|
+
*/
|
|
13
|
+
class DevBuildCommand extends Command {
|
|
14
|
+
/**
|
|
15
|
+
* @returns {Promise<void>}
|
|
16
|
+
*/
|
|
17
|
+
async run() {
|
|
18
|
+
const { args } = await this.parse(DevBuildCommand);
|
|
19
|
+
|
|
20
|
+
const { reactPackages } = require("@saltcorn/server/restart_watcher");
|
|
21
|
+
|
|
22
|
+
for (const { buildDir } of reactPackages) {
|
|
23
|
+
if (args.component && !buildDir.includes(args.component)) continue;
|
|
24
|
+
|
|
25
|
+
const { status, signal } = spawnSync("npm", ["run", "build"], {
|
|
26
|
+
stdio: "inherit",
|
|
27
|
+
cwd: buildDir,
|
|
28
|
+
});
|
|
29
|
+
if (status) process.exit(status);
|
|
30
|
+
if (signal) process.exit();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @type {string}
|
|
37
|
+
*/
|
|
38
|
+
DevBuildCommand.description = `Rebuild static assets`;
|
|
39
|
+
|
|
40
|
+
DevBuildCommand.args = {
|
|
41
|
+
component: Args.string({
|
|
42
|
+
required: false,
|
|
43
|
+
description: "Component to rebuild",
|
|
44
|
+
options: ["builder", "filemanager", "workflow-editor"],
|
|
45
|
+
}),
|
|
46
|
+
};
|
|
47
|
+
module.exports = DevBuildCommand;
|
|
@@ -15,7 +15,10 @@ 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 modName = state.plugin_module_names[plugin.name];
|
|
21
|
+
const module = state.plugins[modName];
|
|
19
22
|
fs.writeFileSync(
|
|
20
23
|
path.join(location, "jest.config.js"),
|
|
21
24
|
`const sqliteDir = process.env.JEST_SC_SQLITE_DIR;
|
|
@@ -35,6 +38,17 @@ const config = {
|
|
|
35
38
|
"@saltcorn/markup$": markupDir,
|
|
36
39
|
"@saltcorn/markup/(.*)": markupDir + "/$1",
|
|
37
40
|
"@saltcorn/admin-models/(.*)": adminModelsDir + "/$1",
|
|
41
|
+
${(module?.dependencies || [])
|
|
42
|
+
.map((dep) => {
|
|
43
|
+
let pluginLocation = state.plugin_locations[dep];
|
|
44
|
+
if (!pluginLocation) {
|
|
45
|
+
// try without org
|
|
46
|
+
const orgRemoved = dep.replace(/^@[^/]+\//, "");
|
|
47
|
+
pluginLocation = state.plugin_locations[orgRemoved];
|
|
48
|
+
}
|
|
49
|
+
return pluginLocation ? `"${dep}": "${pluginLocation}",` : "";
|
|
50
|
+
})
|
|
51
|
+
.join("\n ")}
|
|
38
52
|
},
|
|
39
53
|
modulePaths: [modulePath],
|
|
40
54
|
};
|
|
@@ -77,42 +91,48 @@ const spawnTest = async (installDir, env) => {
|
|
|
77
91
|
return ret.status;
|
|
78
92
|
};
|
|
79
93
|
|
|
80
|
-
const
|
|
94
|
+
const preparePlugin = async (plugin, overwrites) => {
|
|
81
95
|
await removeOldPlugin(plugin);
|
|
82
96
|
removePluginsDir();
|
|
83
|
-
await loadAndSaveNewPlugin(
|
|
97
|
+
await loadAndSaveNewPlugin(
|
|
98
|
+
plugin,
|
|
99
|
+
false,
|
|
100
|
+
false,
|
|
101
|
+
(str) => str,
|
|
102
|
+
false,
|
|
103
|
+
overwrites
|
|
104
|
+
);
|
|
84
105
|
const location = getPluginLocation(plugin.name);
|
|
85
106
|
writeMockFilesIntoPluginDir(location);
|
|
86
|
-
writeJestConfigIntoPluginDir(location);
|
|
107
|
+
writeJestConfigIntoPluginDir(location, plugin);
|
|
87
108
|
return location;
|
|
88
109
|
};
|
|
89
110
|
|
|
90
|
-
const removeOldPlugin = async (
|
|
91
|
-
const byName = await Plugin.findOne({ name:
|
|
111
|
+
const removeOldPlugin = async (newPlugin) => {
|
|
112
|
+
const byName = await Plugin.findOne({ name: newPlugin.name });
|
|
92
113
|
if (byName) {
|
|
93
114
|
await byName.delete();
|
|
94
115
|
await new PluginInstaller(byName).remove();
|
|
95
116
|
}
|
|
96
|
-
let
|
|
97
|
-
if (!
|
|
98
|
-
const withOrg = await Plugin.findOne({
|
|
117
|
+
let oldDbPlugin = null;
|
|
118
|
+
if (!newPlugin.name.startsWith("@saltcorn/")) {
|
|
119
|
+
const withOrg = await Plugin.findOne({
|
|
120
|
+
name: `@saltcorn/${newPlugin.name}`,
|
|
121
|
+
});
|
|
99
122
|
if (withOrg) {
|
|
100
123
|
await withOrg.delete();
|
|
101
|
-
|
|
124
|
+
oldDbPlugin = withOrg;
|
|
102
125
|
}
|
|
103
126
|
} else {
|
|
104
127
|
const withoutOrg = await Plugin.findOne({
|
|
105
|
-
name:
|
|
128
|
+
name: newPlugin.name.replace(/^@saltcorn\//, ""),
|
|
106
129
|
});
|
|
107
130
|
if (withoutOrg) {
|
|
108
131
|
await withoutOrg.delete();
|
|
109
|
-
|
|
132
|
+
oldDbPlugin = withoutOrg;
|
|
110
133
|
}
|
|
111
134
|
}
|
|
112
|
-
|
|
113
|
-
const installer = new PluginInstaller(oldPlugin);
|
|
114
|
-
await installer.remove();
|
|
115
|
-
}
|
|
135
|
+
await new PluginInstaller(oldDbPlugin || newPlugin).remove();
|
|
116
136
|
};
|
|
117
137
|
|
|
118
138
|
const getPluginLocation = (pluginName) => {
|
|
@@ -123,7 +143,7 @@ const getPluginLocation = (pluginName) => {
|
|
|
123
143
|
);
|
|
124
144
|
};
|
|
125
145
|
|
|
126
|
-
const testLocalPlugin = async (dir, env, backupFile) => {
|
|
146
|
+
const testLocalPlugin = async (dir, env, backupFile, overwrites) => {
|
|
127
147
|
if (backupFile) {
|
|
128
148
|
await prep_test_db(path.join(dir, "tests", backupFile));
|
|
129
149
|
} else await require("@saltcorn/data/db/reset_schema")();
|
|
@@ -135,27 +155,49 @@ const testLocalPlugin = async (dir, env, backupFile) => {
|
|
|
135
155
|
source: "local",
|
|
136
156
|
location: path.resolve(dir),
|
|
137
157
|
});
|
|
138
|
-
const installDir = await
|
|
158
|
+
const installDir = await preparePlugin(plugin, overwrites);
|
|
139
159
|
return await spawnTest(installDir, env);
|
|
140
160
|
};
|
|
141
161
|
|
|
142
|
-
const testReleasedPlugin = async (pluginName, env, backupFile) => {
|
|
162
|
+
const testReleasedPlugin = async (pluginName, env, backupFile, overwrites) => {
|
|
143
163
|
await require("@saltcorn/data/db/reset_schema")();
|
|
144
164
|
const plugin = await Plugin.store_by_name(pluginName);
|
|
145
165
|
delete plugin.id;
|
|
146
|
-
const installDir = await
|
|
166
|
+
const installDir = await preparePlugin(plugin, overwrites);
|
|
147
167
|
if (backupFile) {
|
|
148
168
|
await prep_test_db(path.join(installDir, "tests", backupFile));
|
|
149
169
|
}
|
|
150
170
|
return await spawnTest(installDir, env);
|
|
151
171
|
};
|
|
152
172
|
|
|
173
|
+
/**
|
|
174
|
+
*
|
|
175
|
+
* @param {string[]} overwrites paths to local plugins
|
|
176
|
+
* @returns an object mapping module names to paths
|
|
177
|
+
*/
|
|
178
|
+
const prepOverwritesCfg = (overwrites) => {
|
|
179
|
+
const result = {};
|
|
180
|
+
if (overwrites) {
|
|
181
|
+
for (const flag of overwrites) {
|
|
182
|
+
const pkgpath = path.join(flag, "package.json");
|
|
183
|
+
if (!fs.existsSync(pkgpath))
|
|
184
|
+
throw new Error(
|
|
185
|
+
`Overwrite dependency package.json not found in ${flag}`
|
|
186
|
+
);
|
|
187
|
+
const pkg = require(pkgpath);
|
|
188
|
+
result[pkg.name] = flag;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return result;
|
|
192
|
+
};
|
|
193
|
+
|
|
153
194
|
/**
|
|
154
195
|
* Install a plugin, spawn 'npm run test' in the install dir and check the return code
|
|
155
196
|
*/
|
|
156
197
|
class PluginTestCommand extends Command {
|
|
157
198
|
async run() {
|
|
158
199
|
const { flags } = await this.parse(PluginTestCommand);
|
|
200
|
+
const overwrites = prepOverwritesCfg(flags.overwriteDependency);
|
|
159
201
|
const dbname = flags.database ? flags.database : "saltcorn_test";
|
|
160
202
|
let env = null;
|
|
161
203
|
const db = require("@saltcorn/data/db");
|
|
@@ -174,14 +216,16 @@ class PluginTestCommand extends Command {
|
|
|
174
216
|
jestStatus = await testLocalPlugin(
|
|
175
217
|
flags.directory,
|
|
176
218
|
env,
|
|
177
|
-
flags.backupFile
|
|
219
|
+
flags.backupFile,
|
|
220
|
+
overwrites
|
|
178
221
|
);
|
|
179
222
|
} else if (flags.name) {
|
|
180
223
|
console.log(`Testing released plugin '${flags.name}'`);
|
|
181
224
|
jestStatus = await testReleasedPlugin(
|
|
182
225
|
flags.name,
|
|
183
226
|
env,
|
|
184
|
-
flags.backupFile
|
|
227
|
+
flags.backupFile,
|
|
228
|
+
overwrites
|
|
185
229
|
);
|
|
186
230
|
}
|
|
187
231
|
} catch (error) {
|
|
@@ -218,6 +262,13 @@ PluginTestCommand.flags = {
|
|
|
218
262
|
string: "database",
|
|
219
263
|
description: "Run on specified database. Default is 'saltcorn_test''",
|
|
220
264
|
}),
|
|
265
|
+
overwriteDependency: Flags.string({
|
|
266
|
+
char: "o",
|
|
267
|
+
description:
|
|
268
|
+
"Dependency to overwrite with a local plugin (can be used multiple times). " +
|
|
269
|
+
"Please specify the path to the local plugin, the module name will be taken from there.",
|
|
270
|
+
multiple: true,
|
|
271
|
+
}),
|
|
221
272
|
};
|
|
222
273
|
|
|
223
274
|
PluginTestCommand.description =
|
|
@@ -71,6 +71,7 @@ class ReleaseCommand extends Command {
|
|
|
71
71
|
"@saltcorn/postgres": { dir: "postgres", publish: true },
|
|
72
72
|
"@saltcorn/types": { dir: "saltcorn-types", publish: true },
|
|
73
73
|
"@saltcorn/builder": { dir: "saltcorn-builder", publish: true },
|
|
74
|
+
"@saltcorn/workflow-editor": { dir: "workflow-editor", publish: true },
|
|
74
75
|
"@saltcorn/filemanager": { dir: "filemanager", publish: true },
|
|
75
76
|
"@saltcorn/data": { dir: "saltcorn-data", publish: true },
|
|
76
77
|
"@saltcorn/admin-models": {
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @category saltcorn-cli
|
|
3
|
+
* @module commands/dev/serve
|
|
4
|
+
*/
|
|
5
|
+
const { Command, Flags } = require("@oclif/core");
|
|
6
|
+
const { execSync, spawnSync } = require("child_process");
|
|
7
|
+
const { sleep } = require("../../common");
|
|
8
|
+
/**
|
|
9
|
+
* DevServeCommand Class
|
|
10
|
+
* @extends oclif.Command
|
|
11
|
+
* @category saltcorn-cli
|
|
12
|
+
*/
|
|
13
|
+
class DevServeCommand extends Command {
|
|
14
|
+
/**
|
|
15
|
+
* @returns {Promise<void>}
|
|
16
|
+
*/
|
|
17
|
+
async run() {
|
|
18
|
+
const { flags } = await this.parse(DevServeCommand);
|
|
19
|
+
|
|
20
|
+
await this.tryTsc();
|
|
21
|
+
for (;;) {
|
|
22
|
+
const scResult = spawnSync(
|
|
23
|
+
"saltcorn",
|
|
24
|
+
[
|
|
25
|
+
"serve",
|
|
26
|
+
"--dev",
|
|
27
|
+
"--addschema",
|
|
28
|
+
...(flags.port ? ["-p", flags.port] : []),
|
|
29
|
+
],
|
|
30
|
+
{
|
|
31
|
+
env: {
|
|
32
|
+
...process.env,
|
|
33
|
+
SALTCORN_NWORKERS:
|
|
34
|
+
flags.workers || process.env.SALTCORN_NWORKERS || 1,
|
|
35
|
+
},
|
|
36
|
+
stdio: "inherit",
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
|
+
if (scResult.signal) process.exit();
|
|
40
|
+
switch (scResult.status) {
|
|
41
|
+
case 3:
|
|
42
|
+
//root tsc error
|
|
43
|
+
await this.tryTsc();
|
|
44
|
+
break;
|
|
45
|
+
|
|
46
|
+
// todo builder error
|
|
47
|
+
default:
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async tryTsc() {
|
|
54
|
+
const tscResult = spawnSync("npm", ["run", "tsc"], {
|
|
55
|
+
stdio: "inherit",
|
|
56
|
+
});
|
|
57
|
+
if (tscResult.status) {
|
|
58
|
+
//todo watch instead
|
|
59
|
+
await sleep(3000);
|
|
60
|
+
await this.tryTsc();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @type {string}
|
|
67
|
+
*/
|
|
68
|
+
DevServeCommand.description = `Development server. Serve on port 3000, restart when source files change`;
|
|
69
|
+
|
|
70
|
+
DevServeCommand.flags = {
|
|
71
|
+
port: Flags.integer({ char: "p", description: "port", default: 3000 }),
|
|
72
|
+
workers: Flags.integer({ char: "w", description: "workers", default: 1 }),
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
module.exports = DevServeCommand;
|
package/src/commands/restore.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
const { Command, Flags, Args } = require("@oclif/core");
|
|
6
6
|
const { spawnSync } = require("child_process");
|
|
7
7
|
const path = require("path");
|
|
8
|
-
const { maybe_as_tenant } = require("../common");
|
|
8
|
+
const { maybe_as_tenant, init_some_tenants } = require("../common");
|
|
9
9
|
const fs = require("fs");
|
|
10
10
|
|
|
11
11
|
/**
|
|
@@ -45,6 +45,8 @@ class RestoreCommand extends Command {
|
|
|
45
45
|
const { restore } = require("@saltcorn/admin-models/models/backup");
|
|
46
46
|
const User = require("@saltcorn/data/models/user");
|
|
47
47
|
const load_plugins = require("@saltcorn/server/load_plugins");
|
|
48
|
+
await init_some_tenants(tenant);
|
|
49
|
+
|
|
48
50
|
await maybe_as_tenant(tenant, async () => {
|
|
49
51
|
await load_plugins.loadAllPlugins();
|
|
50
52
|
const hasUsers = await User.nonEmpty();
|