diff --git a/packages/@ionic/cli/src/commands/deploy/build.ts b/packages/@ionic/cli/src/commands/deploy/build.ts index acd28c194a..1f30154cb1 100644 --- a/packages/@ionic/cli/src/commands/deploy/build.ts +++ b/packages/@ionic/cli/src/commands/deploy/build.ts @@ -12,6 +12,7 @@ import { isSuperAgentError } from '../../guards'; import { input, strong, weak } from '../../lib/color'; import { Command } from '../../lib/command'; import { FatalException } from '../../lib/errors'; +import { fileUtils } from '../../lib/utils/file'; import { createRequest, download } from '../../lib/utils/http'; const debug = Debug('ionic:commands:deploy:build'); @@ -96,6 +97,12 @@ Customizing the build: spec: { value: 'name' }, default: false, }, + { + name: 'build-file-name', + summary: 'An optional name for the downloaded web artifacts.', + type: String, + spec: { value: 'name' }, + }, ], }; } @@ -144,7 +151,13 @@ Customizing the build: throw new Error('Missing URL in response'); } - const filename = await this.downloadBuild(url.url, build.artifact_name); + let buildFilename = build.artifact_name; + + if (options['build-file-name']) { + buildFilename = await this.sanitizeString(options['build-file-name']); + } + + const filename = await this.downloadBuild(url.url, buildFilename); this.env.log.ok(`Artifact downloaded: ${filename}`); } @@ -270,4 +283,17 @@ Customizing the build: return filename; } + async sanitizeString(value: string | string[] | boolean | null | undefined): Promise { + + if (!value || typeof (value) !== 'string') { + return ''; + } + + if (!fileUtils.isValidFileName(value)) { + throw new FatalException(`${strong(String(value))} is not a valid file name`); + } + + return String(value); + } + }