UNPKG

@swell/cli

Version:

Swell's command line interface/utility

158 lines (153 loc) 6.25 kB
import { confirm } from '@inquirer/prompts'; import { Args, Flags } from '@oclif/core'; import { CLIError } from '@oclif/errors'; import * as fs from 'node:fs'; import ora from 'ora'; import * as semver from 'semver'; import style from '../../lib/style.js'; import { PushAppCommand } from '../../push-app-command.js'; export default class AppRelease extends PushAppCommand { static args = { version: Args.string({ description: 'semver version to release', async parse(input) { const parsedInput = semver.valid(input); if (parsedInput) { return parsedInput; } throw new CLIError(`Invalid version: ${input}`); }, }), }; static description = `App released are reviewed by the Swell team for quality and functionality before publishing. If the version does not exist, you will be prompted to create it. Use the --amend flag to update the description or release notes of an existing release version. Use the --supported=false flag to indicate the version is not officially supported by the developer. The app must be connected to a partner account with access to publish.`; static examples = [ 'swell app release', 'swell app release 2.0.0', 'swell app release 2.0.0 --amend --release-notes ./releases/v2.0.0.md', 'swell app release 2.0.0 -y', ]; static flags = { amend: Flags.boolean({ description: 'amend the description or release notes of an existing release', }), message: Flags.string({ char: 'm', description: 'description of the changes in this version for internal use', }), 'no-git-tag': Flags.boolean({ description: 'if the version is being created, do not create a git tag', }), 'not-supported': Flags.boolean({ description: 'indicates the version is not officially supported by the developer', }), 'release-notes': Flags.string({ description: 'relative path to a file containing release notes', }), yes: Flags.boolean({ char: 'y', description: 'skip confirmation prompt', }), }; static summary = 'Release a new version of your an app for publishing to the App Store.'; static orientation = { env: 'test', }; async run() { const { args, flags } = await this.parse(AppRelease); const { amend, message, 'not-supported': notSupported, 'release-notes': releaseNotesFile, yes, } = flags; if (!(await this.ensureAppExists(undefined, false))) { return; } let releaseNotes; if (releaseNotesFile) { try { releaseNotes = fs.readFileSync(releaseNotesFile, 'utf8'); } catch { this.error(`Release notes could not be loaded from \`${releaseNotesFile}\``); } } const appVersion = await this.validateCreateVersion(args.version, flags); if (!appVersion) { return; } if (appVersion.released && !amend) { throw new Error(`Version ${appVersion.version} has already been released. Use --amend to update version details.`); } const releaseData = { description: message || appVersion.description, release_notes: releaseNotesFile ? releaseNotes : appVersion.release_notes, supported: notSupported ? false : appVersion.supported === undefined ? true : appVersion.supported, }; if (!amend && !yes) { const continueVersion = await confirm({ message: `Release ${style.appConfigValue(this.app.name)} version ${appVersion.version}?`, }); if (!continueVersion) { return; } } const spinner = ora(); this.log(); spinner.start(`${amend ? 'Updating release' : 'Releasing'} version ${style.appConfigValue(appVersion.version)}`); await this.updateVersion(appVersion.version, { ...releaseData, released: true, }, spinner); spinner.succeed(`${style.appConfigValue(this.app.name)} release ${appVersion.version} ${amend ? 'updated' : 'released'}.`); } validateReleaseDetails() { if (!this.app.description) { throw new Error('App must have a description'); } const requiresPreviewImages = this.app.type === 'storefront' && (!this.app.kind || this.app.kind === 'shop') && this.app.storefront?.theme.provider !== 'app'; if (requiresPreviewImages) { if (!this.app.preview_image) { throw new Error('Storefront app must have a preview image to release'); } } else if (this.app.type !== 'theme' && !this.app.logo_icon) { throw new Error('App must have a logo icon to release'); } } async validateCreateVersion(inputVersion, flags) { let version = inputVersion; if (!version) { version = this.app.version; if (!version) { throw new Error('No version specified'); } } this.validateReleaseDetails(); let appVersion = await this.getVersion(version); if (!appVersion) { if (flags.amend) { throw new Error(`Version ${version} does not exist.`); } else { await this.config.runCommand('app:version', [ version, ...(flags.message ? [`-m ${JSON.stringify(flags.message)}`] : []), ...(flags['no-git-tag'] ? ['--no-git-tag'] : []), ...(flags.yes ? ['-y'] : []), ]); this.log(); appVersion = await this.getVersion(version); if (!appVersion) { throw new Error(`An error occurred while creating version ${version}.`); } } } return appVersion; } }