@swell/cli 2.9.14 → 2.9.15
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/dist/commands/app/release.js +13 -5
- package/dist/commands/app/version.d.ts +1 -0
- package/dist/commands/app/version.js +23 -7
- package/dist/lib/api.d.ts +1 -1
- package/dist/lib/api.js +9 -4
- package/dist/push-app-command.d.ts +1 -0
- package/dist/push-app-command.js +8 -0
- package/oclif.manifest.json +8 -1
- package/package.json +1 -1
|
@@ -115,10 +115,17 @@ The app must be connected to a partner account with access to publish.`;
|
|
|
115
115
|
const spinner = ora();
|
|
116
116
|
this.log();
|
|
117
117
|
spinner.start(`${amend ? 'Updating release' : 'Releasing'} version ${style.appConfigValue(appVersion.version)}`);
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
118
|
+
try {
|
|
119
|
+
await this.updateVersion(appVersion.version, {
|
|
120
|
+
...releaseData,
|
|
121
|
+
released: true,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
spinner.fail(error.message);
|
|
126
|
+
this.logReleaseDetailsHint(error);
|
|
127
|
+
return this.exit(1);
|
|
128
|
+
}
|
|
122
129
|
spinner.succeed(`${style.appConfigValue(this.app.name)} release ${appVersion.version} ${amend ? 'updated' : 'released'}.`);
|
|
123
130
|
}
|
|
124
131
|
async validateCreateVersion(inputVersion, flags) {
|
|
@@ -138,7 +145,8 @@ The app must be connected to a partner account with access to publish.`;
|
|
|
138
145
|
else {
|
|
139
146
|
await this.config.runCommand('app:version', [
|
|
140
147
|
version,
|
|
141
|
-
|
|
148
|
+
'--validate-release',
|
|
149
|
+
...(flags.message ? ['-m', flags.message] : []),
|
|
142
150
|
...(flags['no-git-tag'] ? ['--no-git-tag'] : []),
|
|
143
151
|
...(flags.yes ? ['-y'] : []),
|
|
144
152
|
]);
|
|
@@ -10,6 +10,7 @@ export default class AppVersion extends PushAppCommand {
|
|
|
10
10
|
'force-create-files': import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
11
11
|
message: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
12
12
|
'no-git-tag': import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
13
|
+
'validate-release': import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
13
14
|
yes: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
|
|
14
15
|
};
|
|
15
16
|
static orientation: {
|
|
@@ -64,6 +64,10 @@ behavior by using the --no-git-tag option.`;
|
|
|
64
64
|
'no-git-tag': Flags.boolean({
|
|
65
65
|
description: 'do not create a git tag for this version',
|
|
66
66
|
}),
|
|
67
|
+
'validate-release': Flags.boolean({
|
|
68
|
+
description: 'validate the app has all details required to release before creating the version',
|
|
69
|
+
hidden: true,
|
|
70
|
+
}),
|
|
67
71
|
yes: Flags.boolean({
|
|
68
72
|
char: 'y',
|
|
69
73
|
description: 'skip confirmation prompt',
|
|
@@ -75,7 +79,7 @@ behavior by using the --no-git-tag option.`;
|
|
|
75
79
|
static summary = 'Increment the version of your Swell app.';
|
|
76
80
|
async run() {
|
|
77
81
|
const { args, flags } = await this.parse(AppVersion);
|
|
78
|
-
const { amend, 'no-git-tag': noGitTag, yes, 'force-create-files': forceCreateFiles = false, } = flags;
|
|
82
|
+
const { amend, 'no-git-tag': noGitTag, yes, 'force-create-files': forceCreateFiles = false, 'validate-release': validateRelease = false, } = flags;
|
|
79
83
|
let { message } = flags;
|
|
80
84
|
let { nextVersion } = args;
|
|
81
85
|
if (!(await this.ensureAppExists(undefined, false))) {
|
|
@@ -116,7 +120,7 @@ behavior by using the --no-git-tag option.`;
|
|
|
116
120
|
}
|
|
117
121
|
return;
|
|
118
122
|
}
|
|
119
|
-
nextVersion = this.validateAndComputeVersion(nextVersion, localVersion);
|
|
123
|
+
nextVersion = await this.validateAndComputeVersion(nextVersion, localVersion);
|
|
120
124
|
await this.pushAppConfigs();
|
|
121
125
|
await this.deployAppFrontend(false, false);
|
|
122
126
|
if (!message) {
|
|
@@ -139,11 +143,15 @@ behavior by using the --no-git-tag option.`;
|
|
|
139
143
|
const spinner = ora();
|
|
140
144
|
spinner.start('Creating version');
|
|
141
145
|
try {
|
|
142
|
-
await this.createRemoteVersion(nextVersion, message, spinner,
|
|
146
|
+
await this.createRemoteVersion(nextVersion, message, spinner, {
|
|
147
|
+
forceCreateFiles,
|
|
148
|
+
validateRelease,
|
|
149
|
+
});
|
|
143
150
|
}
|
|
144
151
|
catch (error) {
|
|
145
152
|
spinner.fail(error.stderr || error.message);
|
|
146
|
-
|
|
153
|
+
this.logReleaseDetailsHint(error);
|
|
154
|
+
return this.exit(1);
|
|
147
155
|
}
|
|
148
156
|
spinner.succeed(`${style.appConfigValue(this.app.name)} version ${nextVersion} created.`);
|
|
149
157
|
// git is optional: commit and tag only when the app is inside a repository
|
|
@@ -161,7 +169,7 @@ behavior by using the --no-git-tag option.`;
|
|
|
161
169
|
this.log(style.dim('Not a git repository, skipping git commit and tag.'));
|
|
162
170
|
}
|
|
163
171
|
}
|
|
164
|
-
async createRemoteVersion(nextVersion, message, spinner, forceCreateFiles = false) {
|
|
172
|
+
async createRemoteVersion(nextVersion, message, spinner, { forceCreateFiles = false, validateRelease = false } = {}) {
|
|
165
173
|
const body = {
|
|
166
174
|
description: message,
|
|
167
175
|
version: nextVersion,
|
|
@@ -169,6 +177,9 @@ behavior by using the --no-git-tag option.`;
|
|
|
169
177
|
if (forceCreateFiles) {
|
|
170
178
|
body.$force_create_files = true;
|
|
171
179
|
}
|
|
180
|
+
if (validateRelease) {
|
|
181
|
+
body.$validate_release = true;
|
|
182
|
+
}
|
|
172
183
|
// update the version on the remote
|
|
173
184
|
const versionResponse = await this.api.post({ adminPath: `/apps/${this.app.id}/versions` }, {
|
|
174
185
|
body,
|
|
@@ -203,16 +214,21 @@ behavior by using the --no-git-tag option.`;
|
|
|
203
214
|
// tag the version in git
|
|
204
215
|
await git.spawn(['tag', tag], { cwd: this.appPath });
|
|
205
216
|
}
|
|
206
|
-
validateAndComputeVersion(nextVersion, localVersion) {
|
|
217
|
+
async validateAndComputeVersion(nextVersion, localVersion) {
|
|
207
218
|
let version = nextVersion;
|
|
208
219
|
// compute the value of the next version and check if it's valid
|
|
209
220
|
if (RELEASE_TYPES.includes(nextVersion)) {
|
|
210
221
|
// increment the version
|
|
211
222
|
version = semver.inc(localVersion, version);
|
|
212
223
|
}
|
|
213
|
-
if (semver.
|
|
224
|
+
if (semver.lt(version, localVersion)) {
|
|
214
225
|
this.error(`Version ${version} must be greater than the current version ${localVersion}.`);
|
|
215
226
|
}
|
|
227
|
+
// swell.json may declare a version that has not been created yet,
|
|
228
|
+
// e.g. the first version of a new app. Only reject it if it already exists.
|
|
229
|
+
if (semver.eq(version, localVersion) && (await this.getVersion(version))) {
|
|
230
|
+
this.error(`Version ${version} already exists.`);
|
|
231
|
+
}
|
|
216
232
|
return version;
|
|
217
233
|
}
|
|
218
234
|
}
|
package/dist/lib/api.d.ts
CHANGED
|
@@ -21,7 +21,7 @@ export default class Api {
|
|
|
21
21
|
put(pathOpts: Api.Paths, options?: Api.RequestOptions): Promise<any>;
|
|
22
22
|
delete(pathOpts: Api.Paths, options?: Api.RequestOptions): Promise<any>;
|
|
23
23
|
isTestEnvEnabled(): Promise<boolean>;
|
|
24
|
-
setEnv(envId: string): Promise<void>;
|
|
24
|
+
setEnv(envId: string, storeId?: string): Promise<void>;
|
|
25
25
|
setStoreEnv(storeId: string, envId?: string): Promise<void>;
|
|
26
26
|
setPublicKey(publicKey?: string): Promise<void>;
|
|
27
27
|
private isFrontend;
|
package/dist/lib/api.js
CHANGED
|
@@ -2,7 +2,7 @@ import fetch from 'node-fetch';
|
|
|
2
2
|
import { stringify } from 'qs';
|
|
3
3
|
import { getCurrentAppSlugId, hasAppContext } from './apps/index.js';
|
|
4
4
|
import config from './config.js';
|
|
5
|
-
import { API_BASE_URL, getAdminApiBaseUrl, getFrontendApiBaseUrl, } from './constants.js';
|
|
5
|
+
import { API_BASE_URL, getAdminApiBaseUrl, getFrontendApiBaseUrl, getLoginHost, } from './constants.js';
|
|
6
6
|
import style from './style.js';
|
|
7
7
|
export var HttpMethod;
|
|
8
8
|
(function (HttpMethod) {
|
|
@@ -190,16 +190,21 @@ export default class Api {
|
|
|
190
190
|
});
|
|
191
191
|
return clientRecord.test_enabled !== false;
|
|
192
192
|
}
|
|
193
|
-
async setEnv(envId) {
|
|
193
|
+
async setEnv(envId, storeId) {
|
|
194
194
|
const hasTestEnv = await this.isTestEnvEnabled();
|
|
195
195
|
if (!hasTestEnv) {
|
|
196
|
-
|
|
196
|
+
const targetStoreId = storeId || this.storeId || config.getDefaultStore();
|
|
197
|
+
const settingsUrl = `${getLoginHost(targetStoreId)}/admin/settings/general`;
|
|
198
|
+
throw new Error(`Test environment is not enabled for this store.
|
|
199
|
+
|
|
200
|
+
Enable it in the dashboard under Settings > General > Test environment:
|
|
201
|
+
${settingsUrl}`);
|
|
197
202
|
}
|
|
198
203
|
this.envId = envId;
|
|
199
204
|
}
|
|
200
205
|
async setStoreEnv(storeId, envId) {
|
|
201
206
|
if (envId) {
|
|
202
|
-
await this.setEnv(envId);
|
|
207
|
+
await this.setEnv(envId, storeId);
|
|
203
208
|
}
|
|
204
209
|
this.storeId = storeId;
|
|
205
210
|
this.envId = envId;
|
|
@@ -76,6 +76,7 @@ export declare abstract class PushAppCommand extends RemoteAppCommand {
|
|
|
76
76
|
}): void;
|
|
77
77
|
logStorefrontConnected(): void;
|
|
78
78
|
logStorefrontFrontendUrl(storefront?: any, branchId?: string): void;
|
|
79
|
+
logReleaseDetailsHint(error: any): void;
|
|
79
80
|
pushFile(relativePath: string): Promise<void>;
|
|
80
81
|
pushFilePath(relativePath: string, force?: boolean): Promise<void>;
|
|
81
82
|
resolveAppPath(appId?: string, targetPath?: string): Promise<string>;
|
package/dist/push-app-command.js
CHANGED
|
@@ -672,6 +672,14 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
672
672
|
const currentStore = localConfig.getDefaultStore();
|
|
673
673
|
this.log(`View your storefront at ${style.link(this.storefrontFrontendUrl(currentStore, storefront, branchId))}.`);
|
|
674
674
|
}
|
|
675
|
+
// Tell the user how to recover when the server rejects a release
|
|
676
|
+
// because app details are missing
|
|
677
|
+
logReleaseDetailsHint(error) {
|
|
678
|
+
if (!String(error?.message).includes('to release')) {
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
681
|
+
this.log(style.dim(`Update swell.json and assets as needed, run ${style.command('swell app push')}, then run ${style.command('swell app release')} again.`));
|
|
682
|
+
}
|
|
675
683
|
async pushFile(relativePath) {
|
|
676
684
|
const relativePathPosix = toPosixPath(relativePath);
|
|
677
685
|
const basePath = relativePathPosix.split('/')[0];
|
package/oclif.manifest.json
CHANGED
|
@@ -1359,6 +1359,13 @@
|
|
|
1359
1359
|
"allowNo": false,
|
|
1360
1360
|
"type": "boolean"
|
|
1361
1361
|
},
|
|
1362
|
+
"validate-release": {
|
|
1363
|
+
"description": "validate the app has all details required to release before creating the version",
|
|
1364
|
+
"hidden": true,
|
|
1365
|
+
"name": "validate-release",
|
|
1366
|
+
"allowNo": false,
|
|
1367
|
+
"type": "boolean"
|
|
1368
|
+
},
|
|
1362
1369
|
"yes": {
|
|
1363
1370
|
"char": "y",
|
|
1364
1371
|
"description": "skip confirmation prompt",
|
|
@@ -3594,5 +3601,5 @@
|
|
|
3594
3601
|
]
|
|
3595
3602
|
}
|
|
3596
3603
|
},
|
|
3597
|
-
"version": "2.9.
|
|
3604
|
+
"version": "2.9.15"
|
|
3598
3605
|
}
|