@swell/cli
Version:
Swell's command line interface/utility
99 lines (95 loc) • 3.85 kB
JavaScript
import { Args, Flags } from '@oclif/core';
import * as path from 'node:path';
import { AllConfigPaths, filePathExists, isPathDirectory, } from '../../lib/apps/index.js';
import style from '../../lib/style.js';
import { PushAppCommand } from '../../push-app-command.js';
export default class AppPush extends PushAppCommand {
static args = {
file: Args.string({
char: 'f',
description: 'relative path to a configuration file or directory to push',
}),
};
static delayOrientation = true;
static description = `Push all app files, a specific file, or a specific configuration
type to an app in your store's test environment.
If the app does not exist, it will be created and its global ID saved to a .swellrc file.
- If no file is specified, all configuration files will be pushed to the store.
This includes the app icon (assets/icon.png) and swell.json.
- If a file is specified, only that file will be pushed to the store.
- If a directory is specified, only files in that directory will be pushed.
App file directories:
${Object.values(AllConfigPaths)
.map((dir) => style.path(`${dir}/`))
.join('\n')}`;
static examples = [
'swell app push',
'swell app push content',
'swell app push models/products.json',
];
static flags = {
force: Flags.boolean({
default: false,
description: 'force push all configurations',
}),
'no-deploy': Flags.boolean({
description: 'skip deploying app frontend',
}),
};
static orientation = {
env: 'test',
};
static summary = 'Push local files to your Swell app.';
resolvePushPaths(file, appPathFlag) {
// If --app-path was explicitly provided, resolve FILE relative to appPath
// Otherwise, resolve relative to cwd for better UX (tab completion)
const baseDir = appPathFlag ? this.appPath : process.cwd();
const filePath = path.resolve(baseDir, file);
// Check if filePath is outside of appPath
const relativePath = path.relative(this.appPath, filePath);
if (relativePath.startsWith('..') || path.isAbsolute(relativePath)) {
this.error(`Path ${style.path(file)} is outside of the current app directory.`);
}
return { filePath, relativePath };
}
async run() {
const { args, flags } = await this.parse(AppPush);
const { file } = args;
const { force } = flags;
const noDeploy = flags['no-deploy'];
if (this.swellConfig.store?.type === 'theme') {
await this.config.runCommand('theme:push', [
...(file ? [file] : []),
...(force ? ['--force'] : []),
'--sync-app',
]);
return;
}
await this.logOrientation();
if (!(await this.ensureAppExists(file))) {
return;
}
if (file) {
const { filePath, relativePath } = this.resolvePushPaths(file, flags['app-path']);
// Push individual files if not referring to the whole app path
if (filePath !== this.appPath) {
if (!filePathExists(filePath)) {
this.error(`Path ${style.path(file)} does not exist.`);
}
// Targeting a directory
await (isPathDirectory(filePath)
? this.pushFilePath(relativePath, force)
: this.pushFile(relativePath));
this.log();
this.logDashboardUrl(flags);
return;
}
}
await this.pushAppConfigs(force);
if (!noDeploy) {
await this.deployAppFrontend(force);
this.log();
}
this.logDashboardUrl(flags);
}
}