@swell/cli 2.9.7 → 2.9.9
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/app-command.d.ts +1 -0
- package/dist/app-command.js +14 -2
- package/dist/commands/app/pull.d.ts +1 -0
- package/dist/commands/app/pull.js +1 -0
- package/dist/commands/app/push.js +2 -1
- package/dist/commands/app/release.d.ts +0 -1
- package/dist/commands/app/release.js +16 -18
- package/dist/create-app-command.js +7 -10
- package/dist/lib/app-config.js +3 -0
- package/dist/lib/apps/index.d.ts +19 -1
- package/dist/lib/apps/index.js +4 -1
- package/dist/lib/apps/paths.d.ts +1 -0
- package/dist/lib/apps/paths.js +6 -2
- package/dist/push-app-command.d.ts +1 -1
- package/dist/push-app-command.js +13 -13
- package/dist/remote-app-command.d.ts +1 -1
- package/dist/remote-app-command.js +4 -1
- package/oclif.manifest.json +9 -3
- package/package.json +1 -1
package/dist/app-command.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export declare abstract class AppCommand extends SwellCommand {
|
|
|
14
14
|
static baseFlags: {
|
|
15
15
|
'app-path': import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
|
|
16
16
|
};
|
|
17
|
+
static requiresSwellConfig: boolean;
|
|
17
18
|
appPath: string;
|
|
18
19
|
swellConfig: LocalApp;
|
|
19
20
|
init(): Promise<void>;
|
package/dist/app-command.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Flags } from '@oclif/core';
|
|
2
2
|
import * as path from 'node:path';
|
|
3
|
-
import { default as swellConfig } from './lib/app-config.js';
|
|
3
|
+
import { default as swellConfig, swellConfigFileExists, } from './lib/app-config.js';
|
|
4
|
+
import style from './lib/style.js';
|
|
4
5
|
import { SwellCommand } from './swell-command.js';
|
|
5
6
|
/**
|
|
6
7
|
* A base class for Swell CLI commands that do not require an app to be saved
|
|
@@ -20,6 +21,8 @@ export class AppCommand extends SwellCommand {
|
|
|
20
21
|
description: 'Path to your app directory',
|
|
21
22
|
}),
|
|
22
23
|
};
|
|
24
|
+
// set to false for commands that may run before an app directory exists (pull)
|
|
25
|
+
static requiresSwellConfig = true;
|
|
23
26
|
// the local path to the app directory
|
|
24
27
|
appPath = '';
|
|
25
28
|
// local app configuration, what developers define
|
|
@@ -35,8 +38,17 @@ export class AppCommand extends SwellCommand {
|
|
|
35
38
|
// ensure the base flags are available
|
|
36
39
|
klass.flags = { ...klass.flags, ...AppCommand.baseFlags };
|
|
37
40
|
const { flags } = await this.parse(klass);
|
|
41
|
+
const targetDir = flags['app-path']
|
|
42
|
+
? path.resolve(flags['app-path'])
|
|
43
|
+
: process.cwd();
|
|
44
|
+
// swell.json is only ever looked up in this exact directory
|
|
45
|
+
// Searching parent directories (the previous behavior) can silently pick up an unrelated app's config
|
|
46
|
+
if (klass.requiresSwellConfig &&
|
|
47
|
+
!(await swellConfigFileExists(path.join(targetDir, 'swell.json')))) {
|
|
48
|
+
this.error(`No swell.json found in ${style.path(targetDir)}. Run this command from your app's root directory, or pass --app-path.`);
|
|
49
|
+
}
|
|
38
50
|
// if the user passed an app path, use it: reload the app config
|
|
39
|
-
this.swellConfig = await swellConfig(
|
|
51
|
+
this.swellConfig = await swellConfig(targetDir);
|
|
40
52
|
this.appPath = path.resolve(this.swellConfig.swDirPath);
|
|
41
53
|
}
|
|
42
54
|
}
|
|
@@ -4,6 +4,7 @@ export default class AppPull extends PushAppCommand {
|
|
|
4
4
|
appId: import("@oclif/core/lib/interfaces/parser.js").Arg<string, Record<string, unknown>>;
|
|
5
5
|
targetPath: import("@oclif/core/lib/interfaces/parser.js").Arg<string, Record<string, unknown>>;
|
|
6
6
|
};
|
|
7
|
+
static requiresSwellConfig: boolean;
|
|
7
8
|
static description: string;
|
|
8
9
|
static examples: string[];
|
|
9
10
|
static flags: {
|
|
@@ -11,6 +11,7 @@ export default class AppPull extends PushAppCommand {
|
|
|
11
11
|
description: 'path to download app files into',
|
|
12
12
|
}),
|
|
13
13
|
};
|
|
14
|
+
static requiresSwellConfig = false;
|
|
14
15
|
static description = `Pull all app files, a specific file, or a specific configuration
|
|
15
16
|
type from an app in your store's test environment to your local machine.
|
|
16
17
|
|
|
@@ -17,7 +17,8 @@ type to an app in your store's test environment.
|
|
|
17
17
|
If the app does not exist, it will be created and its global ID saved to a .swellrc file.
|
|
18
18
|
|
|
19
19
|
- If no file is specified, all configuration files will be pushed to the store.
|
|
20
|
-
This includes the app icon (assets/icon.png)
|
|
20
|
+
This includes the app icon (assets/icon.png), cover image (assets/image.png),
|
|
21
|
+
and swell.json.
|
|
21
22
|
- If a file is specified, only that file will be pushed to the store.
|
|
22
23
|
- If a directory is specified, only files in that directory will be pushed.
|
|
23
24
|
|
|
@@ -53,7 +53,7 @@ The app must be connected to a partner account with access to publish.`;
|
|
|
53
53
|
}),
|
|
54
54
|
yes: Flags.boolean({
|
|
55
55
|
char: 'y',
|
|
56
|
-
description: 'skip confirmation
|
|
56
|
+
description: 'skip confirmation prompts, including unstaging another staged version',
|
|
57
57
|
}),
|
|
58
58
|
};
|
|
59
59
|
static orientation = {
|
|
@@ -82,6 +82,20 @@ The app must be connected to a partner account with access to publish.`;
|
|
|
82
82
|
if (appVersion.released && !amend) {
|
|
83
83
|
throw new Error(`Version ${appVersion.version} has already been released. Use --amend to update version details.`);
|
|
84
84
|
}
|
|
85
|
+
const stagedVersion = this.app.staged_props?.version;
|
|
86
|
+
const hasOtherStagedVersion = !amend && stagedVersion && stagedVersion !== appVersion.version;
|
|
87
|
+
if (hasOtherStagedVersion) {
|
|
88
|
+
this.log(style.funcWarn(`Version ${stagedVersion} is currently staged. Releasing version ${appVersion.version} will unstage it.`));
|
|
89
|
+
if (!yes) {
|
|
90
|
+
const continueUnstage = await confirm({
|
|
91
|
+
default: false,
|
|
92
|
+
message: `Continue?`,
|
|
93
|
+
});
|
|
94
|
+
if (!continueUnstage) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
85
99
|
const releaseData = {
|
|
86
100
|
description: message || appVersion.description,
|
|
87
101
|
release_notes: releaseNotesFile ? releaseNotes : appVersion.release_notes,
|
|
@@ -108,22 +122,6 @@ The app must be connected to a partner account with access to publish.`;
|
|
|
108
122
|
}, spinner);
|
|
109
123
|
spinner.succeed(`${style.appConfigValue(this.app.name)} release ${appVersion.version} ${amend ? 'updated' : 'released'}.`);
|
|
110
124
|
}
|
|
111
|
-
validateReleaseDetails() {
|
|
112
|
-
if (!this.app.description) {
|
|
113
|
-
throw new Error('App must have a description');
|
|
114
|
-
}
|
|
115
|
-
const requiresPreviewImages = this.app.type === 'storefront' &&
|
|
116
|
-
(!this.app.kind || this.app.kind === 'shop') &&
|
|
117
|
-
this.app.storefront?.theme.provider !== 'app';
|
|
118
|
-
if (requiresPreviewImages) {
|
|
119
|
-
if (!this.app.preview_image) {
|
|
120
|
-
throw new Error('Storefront app must have a preview image to release');
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
else if (this.app.type !== 'theme' && !this.app.logo_icon) {
|
|
124
|
-
throw new Error('App must have a logo icon to release');
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
125
|
async validateCreateVersion(inputVersion, flags) {
|
|
128
126
|
let version = inputVersion;
|
|
129
127
|
if (!version) {
|
|
@@ -132,7 +130,7 @@ The app must be connected to a partner account with access to publish.`;
|
|
|
132
130
|
throw new Error('No version specified');
|
|
133
131
|
}
|
|
134
132
|
}
|
|
135
|
-
|
|
133
|
+
// Mandatory app details are validated server-side when the version is released.
|
|
136
134
|
let appVersion = await this.getVersion(version);
|
|
137
135
|
if (!appVersion) {
|
|
138
136
|
if (flags.amend) {
|
|
@@ -209,12 +209,11 @@ export class CreateAppCommand extends SwellCommand {
|
|
|
209
209
|
await fs.writeFile(configFilePath, content, 'utf8');
|
|
210
210
|
}
|
|
211
211
|
async createAppConfigFolders(swellConfig) {
|
|
212
|
+
const configPath = path.dirname(swellConfig.path);
|
|
212
213
|
for (const type of getAllConfigPaths(swellConfig.get('type'))) {
|
|
213
214
|
// Create a config folder
|
|
214
215
|
// eslint-disable-next-line no-await-in-loop
|
|
215
|
-
await
|
|
216
|
-
cwd: path.dirname(swellConfig.path),
|
|
217
|
-
});
|
|
216
|
+
await fs.mkdir(path.join(configPath, type), { recursive: true });
|
|
218
217
|
}
|
|
219
218
|
}
|
|
220
219
|
async createFrontendApp(swellConfig, flags, directCreate, kind) {
|
|
@@ -300,8 +299,8 @@ export class CreateAppCommand extends SwellCommand {
|
|
|
300
299
|
}
|
|
301
300
|
spinner.start(`Creating ${projectType?.name} frontend app (this may take a while)...`);
|
|
302
301
|
try {
|
|
303
|
-
await
|
|
304
|
-
|
|
302
|
+
await fs.mkdir(path.join(configPath, 'frontend'), {
|
|
303
|
+
recursive: true,
|
|
305
304
|
});
|
|
306
305
|
// SWELL_LOCAL_TEMPLATE_PATH overrides the scaffold for local dev — copies
|
|
307
306
|
// the directory at the path into frontend/ instead of running the install
|
|
@@ -417,16 +416,14 @@ export class CreateAppCommand extends SwellCommand {
|
|
|
417
416
|
this.log();
|
|
418
417
|
spinner.start(`Creating theme template...`);
|
|
419
418
|
try {
|
|
420
|
-
await
|
|
421
|
-
cwd: configPath,
|
|
422
|
-
});
|
|
419
|
+
await fs.mkdir(path.join(configPath, 'theme'), { recursive: true });
|
|
423
420
|
for (const themeConfig of defaultThemeConfigs.results) {
|
|
424
421
|
const filePath = themeConfig.file_path.replace(/^frontend\/theme-template\//, '');
|
|
425
422
|
const fileContent = themeConfig.file_data;
|
|
426
423
|
const isJson = filePath.endsWith('.json');
|
|
427
424
|
// eslint-disable-next-line no-await-in-loop
|
|
428
|
-
await
|
|
429
|
-
|
|
425
|
+
await fs.mkdir(path.join(configPath, path.dirname(filePath)), {
|
|
426
|
+
recursive: true,
|
|
430
427
|
});
|
|
431
428
|
// eslint-disable-next-line no-await-in-loop
|
|
432
429
|
await (isJson
|
package/dist/lib/app-config.js
CHANGED
|
@@ -12,6 +12,9 @@ const schema = {
|
|
|
12
12
|
integrations: { type: 'array' },
|
|
13
13
|
name: { type: 'string' },
|
|
14
14
|
permissions: { type: 'array' },
|
|
15
|
+
price: { type: 'number', minimum: 0 },
|
|
16
|
+
price_external: { type: 'boolean' },
|
|
17
|
+
price_interval: { type: 'string', enum: ['once', 'monthly'] },
|
|
15
18
|
storefront: { type: 'object' },
|
|
16
19
|
theme: { type: 'object' },
|
|
17
20
|
type: { type: 'string' },
|
package/dist/lib/apps/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/// <reference types="node" resolution-mode="require"/>
|
|
3
3
|
import { AppConfig } from './app-config.js';
|
|
4
4
|
export { AppConfig, FunctionProcessingError, IgnoringFileError, } from './app-config.js';
|
|
5
|
-
export { allBaseFilesInDir, allConfigDirsPaths, allConfigFilesInDir, allConfigFilesPaths, allConfigFilesPathsByType, getAllConfigPaths, globAllFilesByPath, isPathDirectory, } from './paths.js';
|
|
5
|
+
export { allBaseFilesInDir, allConfigDirsPaths, allConfigFilesInDir, allConfigFilesPaths, allConfigFilesPathsByType, getAllConfigPaths, globAllFilesByPath, isPathDirectory, toPosixPath, } from './paths.js';
|
|
6
6
|
export declare const PUSH_CONCURRENCY = 3;
|
|
7
7
|
/**
|
|
8
8
|
* An app as defined by the Swell API. This is different than an app
|
|
@@ -16,9 +16,12 @@ export interface App {
|
|
|
16
16
|
[key: string]: string;
|
|
17
17
|
};
|
|
18
18
|
configs?: AppConfig[];
|
|
19
|
+
cover_image?: unknown;
|
|
19
20
|
date_created?: string;
|
|
20
21
|
date_updated?: string;
|
|
22
|
+
demo_url?: string;
|
|
21
23
|
description?: string;
|
|
24
|
+
documentation_url?: string;
|
|
22
25
|
extensions?: any[];
|
|
23
26
|
features?: string[];
|
|
24
27
|
frontend?: {
|
|
@@ -29,6 +32,7 @@ export interface App {
|
|
|
29
32
|
service?: string;
|
|
30
33
|
url?: string;
|
|
31
34
|
};
|
|
35
|
+
full_description?: string;
|
|
32
36
|
highlights?: Array<{
|
|
33
37
|
id: string;
|
|
34
38
|
image_src?: unknown;
|
|
@@ -45,10 +49,19 @@ export interface App {
|
|
|
45
49
|
owned?: boolean;
|
|
46
50
|
preview_image?: unknown;
|
|
47
51
|
preview_mobile_image?: unknown;
|
|
52
|
+
price?: number;
|
|
53
|
+
price_external?: boolean;
|
|
54
|
+
price_interval?: 'once' | 'monthly';
|
|
55
|
+
preview_video_url?: string;
|
|
48
56
|
private_id?: string;
|
|
49
57
|
public_id?: string;
|
|
50
58
|
published?: boolean;
|
|
51
59
|
purchase_options?: string[];
|
|
60
|
+
repository_url?: string;
|
|
61
|
+
staged_props?: {
|
|
62
|
+
[key: string]: any;
|
|
63
|
+
version?: string;
|
|
64
|
+
};
|
|
52
65
|
storefront?: {
|
|
53
66
|
[key: string]: any;
|
|
54
67
|
};
|
|
@@ -60,6 +73,8 @@ export interface App {
|
|
|
60
73
|
preview_image?: unknown;
|
|
61
74
|
preview_mobile_image?: unknown;
|
|
62
75
|
}>;
|
|
76
|
+
support_email?: string;
|
|
77
|
+
support_url?: string;
|
|
63
78
|
theme?: {
|
|
64
79
|
[key: string]: any;
|
|
65
80
|
};
|
|
@@ -74,6 +89,9 @@ export declare enum SwellJsonFields {
|
|
|
74
89
|
KIND = "kind",
|
|
75
90
|
NAME = "name",
|
|
76
91
|
PERMISSIONS = "permissions",
|
|
92
|
+
PRICE = "price",
|
|
93
|
+
PRICE_EXTERNAL = "price_external",
|
|
94
|
+
PRICE_INTERVAL = "price_interval",
|
|
77
95
|
STOREFRONT = "storefront",
|
|
78
96
|
THEME = "theme",
|
|
79
97
|
TYPE = "type",
|
package/dist/lib/apps/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import * as path from 'node:path';
|
|
|
5
5
|
import { detectPackageManager, transformCommand } from '../package-manager.js';
|
|
6
6
|
import { AppConfig } from './app-config.js';
|
|
7
7
|
export { AppConfig, FunctionProcessingError, IgnoringFileError, } from './app-config.js';
|
|
8
|
-
export { allBaseFilesInDir, allConfigDirsPaths, allConfigFilesInDir, allConfigFilesPaths, allConfigFilesPathsByType, getAllConfigPaths, globAllFilesByPath, isPathDirectory, } from './paths.js';
|
|
8
|
+
export { allBaseFilesInDir, allConfigDirsPaths, allConfigFilesInDir, allConfigFilesPaths, allConfigFilesPathsByType, getAllConfigPaths, globAllFilesByPath, isPathDirectory, toPosixPath, } from './paths.js';
|
|
9
9
|
export const PUSH_CONCURRENCY = 3;
|
|
10
10
|
export var SwellJsonFields;
|
|
11
11
|
(function (SwellJsonFields) {
|
|
@@ -15,6 +15,9 @@ export var SwellJsonFields;
|
|
|
15
15
|
SwellJsonFields["KIND"] = "kind";
|
|
16
16
|
SwellJsonFields["NAME"] = "name";
|
|
17
17
|
SwellJsonFields["PERMISSIONS"] = "permissions";
|
|
18
|
+
SwellJsonFields["PRICE"] = "price";
|
|
19
|
+
SwellJsonFields["PRICE_EXTERNAL"] = "price_external";
|
|
20
|
+
SwellJsonFields["PRICE_INTERVAL"] = "price_interval";
|
|
18
21
|
SwellJsonFields["STOREFRONT"] = "storefront";
|
|
19
22
|
SwellJsonFields["THEME"] = "theme";
|
|
20
23
|
SwellJsonFields["TYPE"] = "type";
|
package/dist/lib/apps/paths.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type GlobbyFilterFunction } from 'globby';
|
|
2
2
|
import { ConfigType } from './index.js';
|
|
3
|
+
export declare function toPosixPath(inputPath: string): string;
|
|
3
4
|
export declare function globAllFilesByPath(appPath: string, dirPath?: string): Promise<string[]>;
|
|
4
5
|
export declare function getGlobIgnorePathsChecker(appPath: string): Promise<GlobbyFilterFunction>;
|
|
5
6
|
export declare function allConfigDirsPaths(appPath: string): Generator<{
|
package/dist/lib/apps/paths.js
CHANGED
|
@@ -27,11 +27,15 @@ function globOptions(appPath, options) {
|
|
|
27
27
|
],
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
|
+
// use forward slashes to support Windows
|
|
31
|
+
export function toPosixPath(inputPath) {
|
|
32
|
+
return inputPath.split(path.sep).join('/');
|
|
33
|
+
}
|
|
30
34
|
function globFilesSync(pattern, appPath, dirPath = '.', options = {}) {
|
|
31
|
-
return globbySync(`${dirPath}
|
|
35
|
+
return globbySync(`${toPosixPath(dirPath)}/${pattern}`, globOptions(appPath, options));
|
|
32
36
|
}
|
|
33
37
|
function globFiles(pattern, appPath, dirPath = '.', options = {}) {
|
|
34
|
-
return globby(`${dirPath}
|
|
38
|
+
return globby(`${toPosixPath(dirPath)}/${pattern}`, globOptions(appPath, options));
|
|
35
39
|
}
|
|
36
40
|
export function globAllFilesByPath(appPath, dirPath) {
|
|
37
41
|
return globFiles('**', appPath, dirPath);
|
|
@@ -26,7 +26,7 @@ export declare abstract class PushAppCommand extends RemoteAppCommand {
|
|
|
26
26
|
createAppStorefront(hasOtherStorefronts?: boolean, nonInteractive?: boolean): Promise<any>;
|
|
27
27
|
deployAppFrontend(force?: boolean, log?: boolean): Promise<void>;
|
|
28
28
|
deployFrontend(projectType: FrontendProjectType): Promise<string>;
|
|
29
|
-
ensureAppExists(file?: string, shouldCreate?: boolean): Promise<boolean>;
|
|
29
|
+
ensureAppExists(file?: string, shouldCreate?: boolean, force?: boolean): Promise<boolean>;
|
|
30
30
|
ensureLoggedIn(): Promise<void>;
|
|
31
31
|
exec(command: string, cwd?: string, onOutput?: (string: string) => any | false): Promise<void>;
|
|
32
32
|
execFrontend(command: string, onOutput?: (string: string) => any | false): Promise<void>;
|
package/dist/push-app-command.js
CHANGED
|
@@ -6,7 +6,7 @@ import * as path from 'node:path';
|
|
|
6
6
|
import Stream from 'node:stream';
|
|
7
7
|
import ora from 'ora';
|
|
8
8
|
import { default as swellConfig } from './lib/app-config.js';
|
|
9
|
-
import { ConfigType, getFrontendProjectValidValues, allConfigFilesInDir, CUSTOM_FRAMEWORK_SLUG, appConfigFromFile, filePathExistsAsync, findAppConfig, getConfigTypeFromPath, getConfigTypeKeyFromValue, getFrontendProjectType, getProjectCommands, globAllFilesByPath, hashString, isPathDirectory, } from './lib/apps/index.js';
|
|
9
|
+
import { ConfigType, getFrontendProjectValidValues, allConfigFilesInDir, CUSTOM_FRAMEWORK_SLUG, appConfigFromFile, filePathExistsAsync, findAppConfig, getConfigTypeFromPath, getConfigTypeKeyFromValue, getFrontendProjectType, getProjectCommands, globAllFilesByPath, hashString, isPathDirectory, toPosixPath, } from './lib/apps/index.js';
|
|
10
10
|
import { getGlobIgnorePathsChecker } from './lib/apps/paths.js';
|
|
11
11
|
import { slugFromApp } from './lib/apps/slug.js';
|
|
12
12
|
import { default as localConfig } from './lib/config.js';
|
|
@@ -32,14 +32,12 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
32
32
|
if (!filename) {
|
|
33
33
|
return;
|
|
34
34
|
}
|
|
35
|
-
|
|
35
|
+
const configFile = toPosixPath(filename);
|
|
36
|
+
if (this.watchingIgnoreFilter && this.watchingIgnoreFilter(configFile)) {
|
|
36
37
|
return;
|
|
37
38
|
}
|
|
38
|
-
const configFile = filename;
|
|
39
|
-
const pathParsed = path.parse(configFile);
|
|
40
|
-
const fileDirs = pathParsed.dir.split(path.sep);
|
|
41
39
|
// only the first directory is relevant for us
|
|
42
|
-
const configDir =
|
|
40
|
+
const configDir = configFile.split('/')[0];
|
|
43
41
|
// we only want to watch files in the root of the app directory
|
|
44
42
|
// and ignore build files etc
|
|
45
43
|
// TODO: renaming a folder doesn't seem to work
|
|
@@ -284,7 +282,7 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
284
282
|
this.error(`Error deploying frontend: ${error.message}`);
|
|
285
283
|
}
|
|
286
284
|
}
|
|
287
|
-
async ensureAppExists(file, shouldCreate = true) {
|
|
285
|
+
async ensureAppExists(file, shouldCreate = true, force = false) {
|
|
288
286
|
const klass = this.ctor;
|
|
289
287
|
const currentStore = localConfig.getDefaultStore();
|
|
290
288
|
await this.ensureLoggedIn();
|
|
@@ -313,14 +311,14 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
313
311
|
// If app exists but owned by another client, create a new instance
|
|
314
312
|
if (app?.client_id && app.client_id !== currentStore) {
|
|
315
313
|
// Create a new app
|
|
316
|
-
this.app = await this.getCreateUpdateApp();
|
|
314
|
+
this.app = await this.getCreateUpdateApp(undefined, force);
|
|
317
315
|
if (!this.app) {
|
|
318
316
|
return false;
|
|
319
317
|
}
|
|
320
318
|
}
|
|
321
319
|
else if (!file) {
|
|
322
320
|
// Update existing app if not targeting a file
|
|
323
|
-
this.app = await this.getCreateUpdateApp(app);
|
|
321
|
+
this.app = await this.getCreateUpdateApp(app, force);
|
|
324
322
|
}
|
|
325
323
|
return true;
|
|
326
324
|
}
|
|
@@ -433,7 +431,7 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
433
431
|
async getFrontendDeploymentHash() {
|
|
434
432
|
const localConfigs = await this.getLocalAppConfigs();
|
|
435
433
|
let frontendHashes = localConfigs
|
|
436
|
-
.filter((config) => config.filePath?.startsWith(
|
|
434
|
+
.filter((config) => config.filePath?.startsWith('frontend/'))
|
|
437
435
|
.map((config) => config.hash)
|
|
438
436
|
.sort()
|
|
439
437
|
.join('|');
|
|
@@ -675,16 +673,18 @@ export class PushAppCommand extends RemoteAppCommand {
|
|
|
675
673
|
this.log(`View your storefront at ${style.link(this.storefrontFrontendUrl(currentStore, storefront, branchId))}.`);
|
|
676
674
|
}
|
|
677
675
|
async pushFile(relativePath) {
|
|
678
|
-
const
|
|
676
|
+
const relativePathPosix = toPosixPath(relativePath);
|
|
677
|
+
const basePath = relativePathPosix.split('/')[0];
|
|
679
678
|
const configType = getConfigTypeFromPath(basePath) || ConfigType.FILE;
|
|
680
|
-
const config = await appConfigFromFile(
|
|
679
|
+
const config = await appConfigFromFile(relativePathPosix, configType, this.appPath);
|
|
681
680
|
await this.pushRemoteFile(config);
|
|
682
681
|
}
|
|
683
682
|
async pushFilePath(relativePath, force) {
|
|
684
683
|
const topDir = relativePath.split(path.sep)[0];
|
|
685
684
|
const configType = getConfigTypeFromPath(topDir) || ConfigType.FILE;
|
|
686
685
|
const configTypeKey = getConfigTypeKeyFromValue(configType) || ConfigType.FILE;
|
|
687
|
-
const
|
|
686
|
+
const relativePathPosix = toPosixPath(relativePath);
|
|
687
|
+
const exAppConfigs = (this.app?.configs || []).filter((config) => config.filePath?.startsWith(`${relativePathPosix}/`));
|
|
688
688
|
const promises = [];
|
|
689
689
|
for (const { configFile } of allConfigFilesInDir(this.appPath, relativePath, configTypeKey)) {
|
|
690
690
|
promises.push(appConfigFromFile(configFile, configType, this.appPath));
|
|
@@ -24,7 +24,7 @@ export declare abstract class RemoteAppCommand extends AppCommand {
|
|
|
24
24
|
protected getApp(id?: string): Promise<App>;
|
|
25
25
|
protected getAppWithConfig(id?: string): Promise<App>;
|
|
26
26
|
getConfigData(configId: string): Promise<any>;
|
|
27
|
-
protected getCreateUpdateApp(updateApp?: App | null): Promise<App>;
|
|
27
|
+
protected getCreateUpdateApp(updateApp?: App | null, force?: boolean): Promise<App>;
|
|
28
28
|
protected getInstalledApp(): Promise<any>;
|
|
29
29
|
protected getLocalAppConfigs(): Promise<AppConfig[]>;
|
|
30
30
|
protected getVersion(version?: null | string | undefined): Promise<AppVersion>;
|
|
@@ -172,7 +172,7 @@ export class RemoteAppCommand extends AppCommand {
|
|
|
172
172
|
adminPath: `/apps/${this.app.id}/configs/${configId}/data`,
|
|
173
173
|
}, { query: { ...(themeId ? { theme_id: themeId } : undefined) } });
|
|
174
174
|
}
|
|
175
|
-
async getCreateUpdateApp(updateApp) {
|
|
175
|
+
async getCreateUpdateApp(updateApp, force = false) {
|
|
176
176
|
const spinner = ora();
|
|
177
177
|
let sourceApp;
|
|
178
178
|
try {
|
|
@@ -195,6 +195,9 @@ export class RemoteAppCommand extends AppCommand {
|
|
|
195
195
|
? { private_id: this.swellConfig.store.id }
|
|
196
196
|
: undefined),
|
|
197
197
|
...(sourceApp?.id ? { source_id: sourceApp.id } : undefined),
|
|
198
|
+
// Overwrite name/description/logo_icon on the server
|
|
199
|
+
// instead of only filling them in when empty
|
|
200
|
+
...(force ? { $force_meta: true } : undefined),
|
|
198
201
|
};
|
|
199
202
|
const appLabel = this.app.type === 'theme' ? 'theme' : 'app';
|
|
200
203
|
let app = updateApp || {};
|
package/oclif.manifest.json
CHANGED
|
@@ -708,6 +708,7 @@
|
|
|
708
708
|
"pluginType": "core",
|
|
709
709
|
"strict": true,
|
|
710
710
|
"enableJsonFlag": false,
|
|
711
|
+
"requiresSwellConfig": true,
|
|
711
712
|
"delayOrientation": false,
|
|
712
713
|
"orientation": {
|
|
713
714
|
"env": "test"
|
|
@@ -851,6 +852,7 @@
|
|
|
851
852
|
"strict": true,
|
|
852
853
|
"summary": "Show information about your Swell app.",
|
|
853
854
|
"enableJsonFlag": false,
|
|
855
|
+
"requiresSwellConfig": true,
|
|
854
856
|
"delayOrientation": false,
|
|
855
857
|
"isESM": true,
|
|
856
858
|
"relativePath": [
|
|
@@ -1101,6 +1103,7 @@
|
|
|
1101
1103
|
"strict": true,
|
|
1102
1104
|
"summary": "Install an existing app in another store environment.",
|
|
1103
1105
|
"enableJsonFlag": false,
|
|
1106
|
+
"requiresSwellConfig": true,
|
|
1104
1107
|
"delayOrientation": false,
|
|
1105
1108
|
"orientation": {
|
|
1106
1109
|
"env": "test"
|
|
@@ -1157,6 +1160,7 @@
|
|
|
1157
1160
|
"pluginType": "core",
|
|
1158
1161
|
"strict": true,
|
|
1159
1162
|
"summary": "Pull app files from Swell to your local machine.",
|
|
1163
|
+
"requiresSwellConfig": false,
|
|
1160
1164
|
"orientation": {
|
|
1161
1165
|
"env": "test"
|
|
1162
1166
|
},
|
|
@@ -1176,7 +1180,7 @@
|
|
|
1176
1180
|
"name": "file"
|
|
1177
1181
|
}
|
|
1178
1182
|
},
|
|
1179
|
-
"description": "Push all app files, a specific file, or a specific configuration\ntype to an app in your store's test environment.\n\nIf the app does not exist, it will be created and its global ID saved to a .swellrc file.\n\n- If no file is specified, all configuration files will be pushed to the store.\n This includes the app icon (assets/icon.png) and swell.json.\n- If a file is specified, only that file will be pushed to the store.\n- If a directory is specified, only files in that directory will be pushed.\n\nApp file directories:\nassets/\ncontent/\nfrontend/\ncomponents/\nfunctions/\nmodels/\nnotifications/\nsettings/\ntheme/\nwebhooks/",
|
|
1183
|
+
"description": "Push all app files, a specific file, or a specific configuration\ntype to an app in your store's test environment.\n\nIf the app does not exist, it will be created and its global ID saved to a .swellrc file.\n\n- If no file is specified, all configuration files will be pushed to the store.\n This includes the app icon (assets/icon.png), cover image (assets/image.png),\n and swell.json.\n- If a file is specified, only that file will be pushed to the store.\n- If a directory is specified, only files in that directory will be pushed.\n\nApp file directories:\nassets/\ncontent/\nfrontend/\ncomponents/\nfunctions/\nmodels/\nnotifications/\nsettings/\ntheme/\nwebhooks/",
|
|
1180
1184
|
"examples": [
|
|
1181
1185
|
"swell app push",
|
|
1182
1186
|
"swell app push content",
|
|
@@ -1281,7 +1285,7 @@
|
|
|
1281
1285
|
},
|
|
1282
1286
|
"yes": {
|
|
1283
1287
|
"char": "y",
|
|
1284
|
-
"description": "skip confirmation
|
|
1288
|
+
"description": "skip confirmation prompts, including unstaging another staged version",
|
|
1285
1289
|
"name": "yes",
|
|
1286
1290
|
"allowNo": false,
|
|
1287
1291
|
"type": "boolean"
|
|
@@ -2298,6 +2302,7 @@
|
|
|
2298
2302
|
"strict": true,
|
|
2299
2303
|
"summary": "Create tests scaffolding for your Swell app.",
|
|
2300
2304
|
"enableJsonFlag": false,
|
|
2305
|
+
"requiresSwellConfig": true,
|
|
2301
2306
|
"helpMeta": {
|
|
2302
2307
|
"usageDirect": "[-y]"
|
|
2303
2308
|
},
|
|
@@ -3326,6 +3331,7 @@
|
|
|
3326
3331
|
"pluginName": "@swell/cli",
|
|
3327
3332
|
"pluginType": "core",
|
|
3328
3333
|
"summary": "Pull theme files from Swell to your local machine.",
|
|
3334
|
+
"requiresSwellConfig": false,
|
|
3329
3335
|
"orientation": {
|
|
3330
3336
|
"env": "test"
|
|
3331
3337
|
},
|
|
@@ -3588,5 +3594,5 @@
|
|
|
3588
3594
|
]
|
|
3589
3595
|
}
|
|
3590
3596
|
},
|
|
3591
|
-
"version": "2.9.
|
|
3597
|
+
"version": "2.9.9"
|
|
3592
3598
|
}
|