sitevision-cli 1.0.1 → 1.1.0-beta.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.
- package/CHANGELOG.md +23 -0
- package/dist/cli.js +1 -1
- package/dist/commands/dev.js +12 -0
- package/dist/shell/ConfigForm.js +1 -1
- package/dist/shell/Help.js +1 -1
- package/dist/shell/Shell.js +36 -14
- package/dist/shell/actions.js +28 -12
- package/dist/utils/i18n.js +8 -4
- package/dist/utils/sitevision-api.js +3 -36
- package/dist/utils/tasks.js +18 -14
- package/package.json +1 -1
- package/readme.md +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.1.0-beta.0
|
|
4
|
+
|
|
5
|
+
- Production deploys ask whether to activate the new version or only upload
|
|
6
|
+
it. Press `p` or `P` on a production environment and pick; Esc cancels.
|
|
7
|
+
- Production deploys no longer overwrite an existing version on their own.
|
|
8
|
+
`P` in the shell and `--force` on the command line do that, as on dev.
|
|
9
|
+
- `svc deploy --activate` works with any deploy, not only `--production`.
|
|
10
|
+
- Dev (`d`) runs on a production environment. It needs signing credentials
|
|
11
|
+
and asks for confirmation before it starts, then signs and deploys every
|
|
12
|
+
build. `svc dev` needs `--signed` on a production base and asks the same.
|
|
13
|
+
- The Production help text in the Config tab and both user guides describe
|
|
14
|
+
the new behaviour.
|
|
15
|
+
|
|
16
|
+
## 1.0.2
|
|
17
|
+
|
|
18
|
+
- Workspace settings can switch environment again. Press `v` in the settings
|
|
19
|
+
pane to cycle the workspace's environments; the pane now cycles the ones
|
|
20
|
+
defined in the workspace's root file, so an environment that only exists
|
|
21
|
+
in one app can no longer become a root override.
|
|
22
|
+
- Adding an environment in a workspace checks the name against the file
|
|
23
|
+
being written, not the current app, so a name that clashes with the
|
|
24
|
+
workspace's base environment is rejected there too.
|
|
25
|
+
|
|
3
26
|
## 1.0.1
|
|
4
27
|
|
|
5
28
|
- The "what's new" panel shown after an update now lists the earlier releases
|
package/dist/cli.js
CHANGED
|
@@ -39,7 +39,7 @@ const cli = meow(`
|
|
|
39
39
|
--signed, -s dev/watch: sign after each build
|
|
40
40
|
--force, -f deploy: overwrite the existing addon version
|
|
41
41
|
--production, -p deploy: upload the signed zip to production
|
|
42
|
-
--activate, -a deploy: activate
|
|
42
|
+
--activate, -a deploy: activate the uploaded version
|
|
43
43
|
--no-zip build: skip the zip archive
|
|
44
44
|
--global setup-signing: save for every project on this machine
|
|
45
45
|
--minimal Shell: compact layout for small terminals
|
package/dist/commands/dev.js
CHANGED
|
@@ -96,6 +96,18 @@ export const devCommand = {
|
|
|
96
96
|
process.exitCode = 1;
|
|
97
97
|
return;
|
|
98
98
|
}
|
|
99
|
+
if (dev.production) {
|
|
100
|
+
if (!flags['signed']) {
|
|
101
|
+
say('\n\x1b[31mThe base environment is production, which only takes the signed zip. Run `svc dev --signed`.\x1b[0m\n');
|
|
102
|
+
process.exitCode = 1;
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const go = await promptYesNo(`\x1b[31m${dev.domain} is PRODUCTION.\x1b[0m Dev will sign and deploy every build of ${project.manifest.id} there (addon ${dev.addonName}). Start it? (y/N): `);
|
|
106
|
+
if (!go) {
|
|
107
|
+
process.exitCode = 1;
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
99
111
|
if (!(await resolveDeployPasswordForCli(dev)))
|
|
100
112
|
return;
|
|
101
113
|
let signingCredentials;
|
package/dist/shell/ConfigForm.js
CHANGED
|
@@ -109,7 +109,7 @@ const FIELDS = [
|
|
|
109
109
|
label: 'Production',
|
|
110
110
|
kind: 'bool',
|
|
111
111
|
section: 'ENVIRONMENT',
|
|
112
|
-
help: 'Treat
|
|
112
|
+
help: 'Treat this base environment as production: deploys use the signed zip, ask for confirmation and offer activation, and dev confirms before it starts. Off by default even when the name says prod.',
|
|
113
113
|
},
|
|
114
114
|
{
|
|
115
115
|
key: 'signingUsername',
|
package/dist/shell/Help.js
CHANGED
|
@@ -40,7 +40,7 @@ const GUIDE = {
|
|
|
40
40
|
title: 'Versions',
|
|
41
41
|
text: [
|
|
42
42
|
"The versions uploaded to the addon on the active environment's site, the domain in the top bar. v switches environment.",
|
|
43
|
-
'↑↓ select, a activates the selected version, r refreshes.
|
|
43
|
+
'↑↓ select, a activates the selected version, r refreshes. A production deploy asks whether to activate.',
|
|
44
44
|
],
|
|
45
45
|
},
|
|
46
46
|
log: {
|
package/dist/shell/Shell.js
CHANGED
|
@@ -90,27 +90,33 @@ export function Shell({ apps: initialApps, workspaceRoot, version, minimal = fal
|
|
|
90
90
|
// Active environment, remembered per workspace (or app) in .svcconfig.
|
|
91
91
|
const configRoot = workspaceRoot ?? rawProject.root;
|
|
92
92
|
const [envChoice, setEnvChoice] = useState(() => readSvcConfig(configRoot).environment ?? '');
|
|
93
|
-
const
|
|
93
|
+
const rootDev = useMemo(() => workspaceRoot
|
|
94
|
+
? readWorkspaceDevProperties(workspaceRoot)
|
|
95
|
+
: undefined,
|
|
96
|
+
// Re-read after any reload so saved values show up.
|
|
97
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
98
|
+
[workspaceRoot, apps]);
|
|
99
|
+
// The settings pane edits the shared root file, so it only cycles the
|
|
100
|
+
// root's environments: an app-only one must never become a root override.
|
|
101
|
+
const envDev = settings ? rootDev : rawProject.devProperties;
|
|
102
|
+
const envNames = environmentNames(envDev);
|
|
94
103
|
const envList = envNames.join(',');
|
|
95
104
|
const env = envNames.includes(envChoice)
|
|
96
105
|
? envChoice
|
|
97
|
-
: baseEnvironment(
|
|
106
|
+
: baseEnvironment(envDev);
|
|
98
107
|
const project = useMemo(() => environmentProject(rawProject, env), [rawProject, env]);
|
|
99
|
-
const isProduction = isProductionEnvironment(env,
|
|
108
|
+
const isProduction = isProductionEnvironment(env, envDev);
|
|
100
109
|
const versionsKey = `${project.root}|${env}`;
|
|
101
110
|
const single = !workspaceRoot;
|
|
102
|
-
const workspaceTarget = useMemo(() => workspaceRoot
|
|
111
|
+
const workspaceTarget = useMemo(() => workspaceRoot && rootDev
|
|
103
112
|
? {
|
|
104
113
|
root: workspaceRoot,
|
|
105
|
-
base:
|
|
106
|
-
devProperties: resolveEnvironment(
|
|
114
|
+
base: rootDev,
|
|
115
|
+
devProperties: resolveEnvironment(rootDev, env),
|
|
107
116
|
environment: env,
|
|
108
117
|
workspace: true,
|
|
109
118
|
}
|
|
110
|
-
: undefined,
|
|
111
|
-
// Re-read after any reload so saved values show up.
|
|
112
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
113
|
-
[workspaceRoot, apps, env]);
|
|
119
|
+
: undefined, [workspaceRoot, rootDev, env]);
|
|
114
120
|
const narrow = minimal || columns < NARROW_BELOW;
|
|
115
121
|
const sidebar = navWidth(columns);
|
|
116
122
|
// The navigator shows the fuzzy matches; `selected` stays an index into
|
|
@@ -210,13 +216,13 @@ export function Shell({ apps: initialApps, workspaceRoot, version, minimal = fal
|
|
|
210
216
|
?.trim()
|
|
211
217
|
.toLowerCase()
|
|
212
218
|
.replaceAll(/[^\d\-a-z]/g, '');
|
|
213
|
-
if (!clean || clean === baseEnvironment(rawProject.devProperties))
|
|
214
|
-
return;
|
|
215
219
|
const targetRoot = workspaceRoot ?? rawProject.root;
|
|
216
220
|
const base = (workspaceRoot
|
|
217
221
|
? readWorkspaceDevProperties(workspaceRoot)
|
|
218
222
|
: rawProject.devProperties);
|
|
219
|
-
|
|
223
|
+
// The base of the file being written: an app's package.json may
|
|
224
|
+
// name a different one, and a duplicate of the base is never listed.
|
|
225
|
+
if (!clean || !base || clean === baseEnvironment(base))
|
|
220
226
|
return;
|
|
221
227
|
writeDevProperties(targetRoot, { ...base, environments: { ...base.environments, [clean]: {} } }, { complete: !workspaceRoot });
|
|
222
228
|
reload();
|
|
@@ -416,6 +422,19 @@ export function Shell({ apps: initialApps, workspaceRoot, version, minimal = fal
|
|
|
416
422
|
confirm: message => new Promise(resolve => {
|
|
417
423
|
setOverlay({ kind: 'confirm', message, resolve });
|
|
418
424
|
}),
|
|
425
|
+
async choose(label, choices) {
|
|
426
|
+
const picked = await new Promise(resolve => {
|
|
427
|
+
setOverlay({
|
|
428
|
+
kind: 'choice',
|
|
429
|
+
label,
|
|
430
|
+
choices,
|
|
431
|
+
multi: false,
|
|
432
|
+
initial: [0],
|
|
433
|
+
resolve,
|
|
434
|
+
});
|
|
435
|
+
});
|
|
436
|
+
return picked?.[0] ?? null;
|
|
437
|
+
},
|
|
419
438
|
openHelp() {
|
|
420
439
|
setOverlay({ kind: 'help' });
|
|
421
440
|
},
|
|
@@ -591,9 +610,11 @@ export function Shell({ apps: initialApps, workspaceRoot, version, minimal = fal
|
|
|
591
610
|
return;
|
|
592
611
|
}
|
|
593
612
|
if (settings && focus === 'content') {
|
|
594
|
-
// Settings pane: the form owns everything but q, y and Tab/Esc above.
|
|
613
|
+
// Settings pane: the form owns everything but q, v, y and Tab/Esc above.
|
|
595
614
|
if (input === 'q')
|
|
596
615
|
quit();
|
|
616
|
+
else if (input === 'v')
|
|
617
|
+
context.cycleEnvironment();
|
|
597
618
|
else if (input === 'y') {
|
|
598
619
|
try {
|
|
599
620
|
if (syncDevPropertiesToPackageJson(workspaceRoot)) {
|
|
@@ -679,6 +700,7 @@ export function Shell({ apps: initialApps, workspaceRoot, version, minimal = fal
|
|
|
679
700
|
? h([
|
|
680
701
|
['↑↓', 'field'],
|
|
681
702
|
['Enter', 'edit'],
|
|
703
|
+
['v', 'env'],
|
|
682
704
|
['y', 'sync'],
|
|
683
705
|
['Esc', 'back'],
|
|
684
706
|
['q', 'quit'],
|
package/dist/shell/actions.js
CHANGED
|
@@ -144,21 +144,25 @@ const deployDetail = (p) => {
|
|
|
144
144
|
? `${env} · ${t('signed zip · confirms first')}`
|
|
145
145
|
: env;
|
|
146
146
|
};
|
|
147
|
-
/** Deploy to the active environment; production means signed
|
|
147
|
+
/** Deploy to the active environment; production means signed, and asks whether to activate. */
|
|
148
148
|
async function deployTo(ctx, force) {
|
|
149
|
-
|
|
150
|
-
|
|
149
|
+
let activate = false;
|
|
150
|
+
if (ctx.isProduction) {
|
|
151
|
+
const pick = await ctx.choose(t('Deploy the signed {id} to {env} (addon {addon})', {
|
|
151
152
|
id: ctx.project.manifest.id,
|
|
152
153
|
env: ctx.environment,
|
|
153
154
|
addon: ctx.project.devProperties?.addonName ?? '?',
|
|
154
|
-
}))))
|
|
155
|
-
|
|
155
|
+
}), [t('Deploy and activate'), t('Deploy only')]);
|
|
156
|
+
if (pick === null)
|
|
157
|
+
return;
|
|
158
|
+
activate = pick === 0;
|
|
156
159
|
}
|
|
157
160
|
const config = await resolveDeployConfig(ctx);
|
|
158
161
|
if (!config)
|
|
159
162
|
return;
|
|
160
163
|
startDeploy(ctx.project, config, {
|
|
161
|
-
|
|
164
|
+
force,
|
|
165
|
+
...(ctx.isProduction && { production: true, activate }),
|
|
162
166
|
onAddonMissing: askCreateAddon(ctx),
|
|
163
167
|
});
|
|
164
168
|
ctx.setTab('log');
|
|
@@ -166,10 +170,17 @@ async function deployTo(ctx, force) {
|
|
|
166
170
|
const hasSigning = (p) => Boolean(p.devProperties?.signingUsername);
|
|
167
171
|
async function startDevOrWatch(ctx, deploy) {
|
|
168
172
|
if (deploy && ctx.isProduction) {
|
|
169
|
-
ctx.
|
|
173
|
+
if (!hasSigning(ctx.project)) {
|
|
174
|
+
ctx.notify(t('Dev on {env} needs signing credentials: production only takes the signed zip. / sets them up.', { env: ctx.environment }), 'warn');
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
const go = await ctx.confirm(t('{env} is PRODUCTION. Dev will sign and deploy every build of {id} there (addon {addon}). Start it?', {
|
|
170
178
|
env: ctx.environment,
|
|
171
|
-
|
|
172
|
-
|
|
179
|
+
id: ctx.project.manifest.id,
|
|
180
|
+
addon: ctx.project.devProperties?.addonName ?? '?',
|
|
181
|
+
}));
|
|
182
|
+
if (!go)
|
|
183
|
+
return;
|
|
173
184
|
}
|
|
174
185
|
if (runningTasks(ctx.project.root).some(task => task.kind === 'dev' || task.kind === 'watch')) {
|
|
175
186
|
ctx.notify(t('A dev/watch task is already running for this app (K stops it).'), 'warn');
|
|
@@ -198,9 +209,14 @@ export const actions = [
|
|
|
198
209
|
key: 'd',
|
|
199
210
|
group: 'app',
|
|
200
211
|
label: 'Dev',
|
|
201
|
-
detail
|
|
202
|
-
|
|
203
|
-
|
|
212
|
+
detail(p) {
|
|
213
|
+
const base = hasSigning(p)
|
|
214
|
+
? t('build, sign and deploy on change')
|
|
215
|
+
: t('build and deploy on change');
|
|
216
|
+
return p.devProperties?.productionEnvironment
|
|
217
|
+
? `${base} · ${t('confirms first')}`
|
|
218
|
+
: base;
|
|
219
|
+
},
|
|
204
220
|
enabled: hasDev,
|
|
205
221
|
async run(ctx) {
|
|
206
222
|
await startDevOrWatch(ctx, true);
|
package/dist/utils/i18n.js
CHANGED
|
@@ -114,7 +114,7 @@ const sv = {
|
|
|
114
114
|
'Enter edits and saves a field, Esc cancels, ←→ or space cycles choices, Ctrl+O lists the addons on the site. y copies shared values into package.json for the team.': 'Enter redigerar och sparar ett fält, Esc avbryter, ←→ eller mellanslag bläddrar bland val, Ctrl+O listar webbplatsens tillägg. y kopierar delade värden till package.json för teamet.',
|
|
115
115
|
'Passwords and secrets go to the OS keychain, never to a file. Leave them empty to be asked on each run.': 'Lösenord och hemligheter sparas i nyckelringen, aldrig i en fil. Lämna dem tomma för att bli tillfrågad varje gång.',
|
|
116
116
|
"The versions uploaded to the addon on the active environment's site, the domain in the top bar. v switches environment.": 'Versionerna som laddats upp till tillägget på den aktiva miljöns webbplats, domänen i toppraden. v byter miljö.',
|
|
117
|
-
'↑↓ select, a activates the selected version, r refreshes.
|
|
117
|
+
'↑↓ select, a activates the selected version, r refreshes. A production deploy asks whether to activate.': '↑↓ väljer, a aktiverar vald version, r uppdaterar. En produktionsdriftsättning frågar om den ska aktivera.',
|
|
118
118
|
'Output from build, sign, deploy, dev and watch for the selected app. Dev and watch keep running while you switch apps; K stops them.': 'Utdata från build, sign, deploy, dev och watch för vald app. Dev och watch fortsätter köra medan du byter app; K stoppar dem.',
|
|
119
119
|
'↑↓ scroll, PgUp/PgDn page, f jumps to the end, x toggles line wrap.': '↑↓ scrollar, PgUp/PgDn bläddrar sida, f hoppar till slutet, x växlar radbrytning.',
|
|
120
120
|
"What's new": 'Nyheter',
|
|
@@ -129,8 +129,12 @@ const sv = {
|
|
|
129
129
|
'Addon {addon} does not exist on {domain}. Create it and deploy again?': 'Tillägget {addon} finns inte på {domain}. Skapa det och driftsätt igen?',
|
|
130
130
|
'e.g. test or prod, overriding domain and auth': 't.ex. test eller prod, med egen domän och auth',
|
|
131
131
|
'Environment name (e.g. test, prod)': 'Miljönamn (t.ex. test, prod)',
|
|
132
|
-
'Deploy the signed {id} to {env} (addon {addon})
|
|
133
|
-
'
|
|
132
|
+
'Deploy the signed {id} to {env} (addon {addon})': 'Driftsätt signerade {id} till {env} (addon {addon})',
|
|
133
|
+
'Deploy and activate': 'Driftsätt och aktivera',
|
|
134
|
+
'Deploy only': 'Bara driftsätt',
|
|
135
|
+
'Dev on {env} needs signing credentials: production only takes the signed zip. / sets them up.': 'Dev mot {env} kräver signeringsuppgifter: produktion tar bara den signerade zip-filen. / ställer in dem.',
|
|
136
|
+
'{env} is PRODUCTION. Dev will sign and deploy every build of {id} there (addon {addon}). Start it?': '{env} är PRODUKTION. Dev signerar och driftsätter varje bygge av {id} dit (addon {addon}). Starta?',
|
|
137
|
+
'confirms first': 'bekräftar först',
|
|
134
138
|
'switched to {env}': 'bytte till {env}',
|
|
135
139
|
'environment {env} added': 'miljön {env} tillagd',
|
|
136
140
|
environment: 'miljö',
|
|
@@ -245,7 +249,7 @@ const sv = {
|
|
|
245
249
|
'Environment name': 'Miljönamn',
|
|
246
250
|
Production: 'Produktion',
|
|
247
251
|
'What this base configuration is: dev, test, prod… Other environments are added on top of it with E or the palette and override only what differs.': 'Vad denna grundkonfiguration är: dev, test, prod… Andra miljöer läggs ovanpå med E eller paletten och skriver bara över det som skiljer.',
|
|
248
|
-
'Treat
|
|
252
|
+
'Treat this base environment as production: deploys use the signed zip, ask for confirmation and offer activation, and dev confirms before it starts. Off by default even when the name says prod.': 'Behandla grundmiljön som produktion: driftsättningar använder den signerade zip-filen, ber om bekräftelse och erbjuder aktivering, och dev bekräftar innan den startar. Av som standard även om namnet säger prod.',
|
|
249
253
|
'Saved {label}.': 'Sparade {label}.',
|
|
250
254
|
'Looking up OAuth2 endpoints…': 'Slår upp OAuth2-endpoints…',
|
|
251
255
|
'Endpoints filled from the site OpenID config.': 'Endpoints ifyllda från webbplatsens OpenID-konfig.',
|
|
@@ -3,10 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Handles all API interactions with Sitevision servers:
|
|
5
5
|
* - Signing apps via developer.sitevision.se
|
|
6
|
-
* - Deploying
|
|
7
|
-
* - Deploying to production environments
|
|
6
|
+
* - Deploying apps
|
|
8
7
|
* - Creating addons
|
|
9
|
-
* - Activating
|
|
8
|
+
* - Activating uploaded versions
|
|
10
9
|
*/
|
|
11
10
|
import fs from 'fs';
|
|
12
11
|
import path from 'path';
|
|
@@ -425,38 +424,6 @@ export async function deployApp(zipPath, config, appType, force = false) {
|
|
|
425
424
|
};
|
|
426
425
|
}
|
|
427
426
|
}
|
|
428
|
-
/**
|
|
429
|
-
* Deploy an app to production
|
|
430
|
-
*
|
|
431
|
-
* @param signedZipPath - Path to the SIGNED zip file (required for production)
|
|
432
|
-
* @param config - Production deployment configuration
|
|
433
|
-
* @param appType - The app type (web, widget, rest)
|
|
434
|
-
*/
|
|
435
|
-
export async function deployProduction(signedZipPath, config, appType) {
|
|
436
|
-
// Deploy the signed app
|
|
437
|
-
const deployResult = await deployApp(signedZipPath, config, appType, true);
|
|
438
|
-
if (!deployResult.success) {
|
|
439
|
-
return deployResult;
|
|
440
|
-
}
|
|
441
|
-
if (!config.activate)
|
|
442
|
-
return deployResult;
|
|
443
|
-
if (!deployResult.executableId) {
|
|
444
|
-
return {
|
|
445
|
-
...deployResult,
|
|
446
|
-
activated: false,
|
|
447
|
-
message: 'Deployed, but not activated: the server did not return an executable id.',
|
|
448
|
-
};
|
|
449
|
-
}
|
|
450
|
-
const activationResult = await activateApp(deployResult.executableId, config, appType);
|
|
451
|
-
return {
|
|
452
|
-
success: true,
|
|
453
|
-
executableId: deployResult.executableId,
|
|
454
|
-
activated: activationResult.success,
|
|
455
|
-
message: activationResult.success
|
|
456
|
-
? 'Deployed and activated successfully'
|
|
457
|
-
: `Deployed successfully but activation failed: ${activationResult.error}`,
|
|
458
|
-
};
|
|
459
|
-
}
|
|
460
427
|
// =============================================================================
|
|
461
428
|
// ADDON MANAGEMENT API
|
|
462
429
|
// =============================================================================
|
|
@@ -524,7 +491,7 @@ export async function createAddon(config, appType) {
|
|
|
524
491
|
}
|
|
525
492
|
}
|
|
526
493
|
/**
|
|
527
|
-
* Activate
|
|
494
|
+
* Activate an uploaded version
|
|
528
495
|
*
|
|
529
496
|
* @param executableId - The executable ID returned from deployment
|
|
530
497
|
* @param config - Deployment configuration
|
package/dist/utils/tasks.js
CHANGED
|
@@ -8,7 +8,7 @@ import { hasSitevisionScripts, runSitevisionScriptsBuild, getDelegatedZipPath, c
|
|
|
8
8
|
import { copyStaticToBuild, copySrcToBuild, cleanBuild, createBuildZip, formatFileSize, getZipSize, zipExists, } from './zip.js';
|
|
9
9
|
import { deleteSessionCookie } from './keychain.js';
|
|
10
10
|
import { isBundledApp, getAppType, getFullAppId, getZipPath, getSignedZipPath, getDeployZipPath, localizedText, } from './project-detection.js';
|
|
11
|
-
import { signApp, deployApp,
|
|
11
|
+
import { signApp, deployApp, activateApp, createAddon, listAddons, classifyAddon, } from './sitevision-api.js';
|
|
12
12
|
import { ProcessRunner } from './process-runner.js';
|
|
13
13
|
import { debug } from './debug.js';
|
|
14
14
|
const MAX_LINES = 2000;
|
|
@@ -170,10 +170,8 @@ async function signOnce(project, task, log, zipPath, credentials) {
|
|
|
170
170
|
async function deployOnce(project, task, log, zipPath, config, options) {
|
|
171
171
|
setPhase(task, 'deploying');
|
|
172
172
|
const appType = getAppType(project.manifest);
|
|
173
|
-
log('dep', `POST multipart →
|
|
174
|
-
const upload = async () => options.
|
|
175
|
-
? deployProduction(zipPath, { ...config, activate: options.activate }, appType)
|
|
176
|
-
: deployApp(zipPath, config, appType, options.force);
|
|
173
|
+
log('dep', `POST multipart → import · ${config.addonName} · ${path.basename(zipPath)}`);
|
|
174
|
+
const upload = async () => deployApp(zipPath, config, appType, options.force);
|
|
177
175
|
let result = await upload();
|
|
178
176
|
if (!result.success && result.contextNodeMissing) {
|
|
179
177
|
const addon = classifyAddon(await listAddons(config), config.addonName);
|
|
@@ -202,12 +200,23 @@ async function deployOnce(project, task, log, zipPath, config, options) {
|
|
|
202
200
|
}
|
|
203
201
|
if (!result.success)
|
|
204
202
|
throw new Error(result.error ?? 'Deployment failed');
|
|
205
|
-
if (options.production && options.activate && !result.activated) {
|
|
206
|
-
throw new Error(result.message ?? 'Deployed, but not activated');
|
|
207
|
-
}
|
|
208
203
|
log('dep', `${result.message ?? 'deployed'}${result.executableId ? ` · exec ${result.executableId}` : ''}`, 'ok');
|
|
204
|
+
if (options.activate) {
|
|
205
|
+
if (!result.executableId) {
|
|
206
|
+
throw new Error('Deployed, but not activated: the server did not return an executable id.');
|
|
207
|
+
}
|
|
208
|
+
await activateOnce(task, log, config, appType, result.executableId, `exec ${result.executableId}`);
|
|
209
|
+
}
|
|
209
210
|
return result.executableId;
|
|
210
211
|
}
|
|
212
|
+
async function activateOnce(task, log, config, appType, executableId, versionLabel) {
|
|
213
|
+
setPhase(task, 'activating');
|
|
214
|
+
log('act', `PUT activateCustomModuleExecutable · ${versionLabel}`);
|
|
215
|
+
const result = await activateApp(executableId, config, appType);
|
|
216
|
+
if (!result.success)
|
|
217
|
+
throw new Error(result.error ?? 'Activation failed');
|
|
218
|
+
log('act', `${versionLabel} is now active`, 'ok');
|
|
219
|
+
}
|
|
211
220
|
// ---------------------------------------------------------------------------
|
|
212
221
|
// Tasks
|
|
213
222
|
// ---------------------------------------------------------------------------
|
|
@@ -271,12 +280,7 @@ export function startActivate(project, config, executableId, versionLabel) {
|
|
|
271
280
|
const { task, log, finish } = createTask('activate', project, `activate ${versionLabel}`);
|
|
272
281
|
void (async () => {
|
|
273
282
|
try {
|
|
274
|
-
|
|
275
|
-
log('act', `PUT activateCustomModuleExecutable · ${versionLabel}`);
|
|
276
|
-
const result = await activateApp(executableId, config, getAppType(project.manifest));
|
|
277
|
-
if (!result.success)
|
|
278
|
-
throw new Error(result.error ?? 'Activation failed');
|
|
279
|
-
log('act', `${versionLabel} is now active`, 'ok');
|
|
283
|
+
await activateOnce(task, log, config, getAppType(project.manifest), executableId, versionLabel);
|
|
280
284
|
finish('success');
|
|
281
285
|
}
|
|
282
286
|
catch (error) {
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -13,7 +13,7 @@ MCPServer) from a full-screen terminal shell or as plain commands.
|
|
|
13
13
|
works with SSO), or a captured browser session for SAML-only sites.
|
|
14
14
|
- **No secrets on disk.** Passwords, tokens and cookies live in the OS keychain.
|
|
15
15
|
- **Environments.** dev, test and prod in one config; production deploys use
|
|
16
|
-
the signed zip, confirm and activate.
|
|
16
|
+
the signed zip, confirm, and activate only if you say so.
|
|
17
17
|
- **Shared config in git.** Site and auth settings for the whole team live in
|
|
18
18
|
`package.json`, once at the repo root; your username stays in a local
|
|
19
19
|
`.dev_properties.json`. Compatible with plain sitevision-scripts.
|
|
@@ -46,7 +46,7 @@ svc
|
|
|
46
46
|
every change and deploy. Output is in the **Log** tab (`4`).
|
|
47
47
|
|
|
48
48
|
For production: switch environment with `v`, press `b` to build, `s` to sign
|
|
49
|
-
and `p` to deploy
|
|
49
|
+
and `p` to deploy. It asks whether to activate the new version or just upload it.
|
|
50
50
|
|
|
51
51
|
## The shell
|
|
52
52
|
|
|
@@ -79,7 +79,7 @@ svc # interactive shell
|
|
|
79
79
|
svc build [--no-zip] # build to dist/<id>.zip
|
|
80
80
|
svc sign # sign to dist/<id>-signed.zip
|
|
81
81
|
svc deploy [--force] # deploy the zip
|
|
82
|
-
svc deploy --production [--activate] #
|
|
82
|
+
svc deploy [--production] [--activate] # signed zip only / activate after
|
|
83
83
|
svc dev [--signed] # build + deploy on change
|
|
84
84
|
svc watch [--signed] # build on change, no deploy
|
|
85
85
|
svc info # project information
|