diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..d0a9746f65 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: +- package-ecosystem: npm + directory: "/" + schedule: + interval: daily diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 1f0a9de4cd..b5e632d515 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -32,3 +32,20 @@ jobs: GIT_AUTHOR_EMAIL: hi@ionicframework.com GIT_COMMITTER_NAME: Ionitron GIT_COMMITTER_EMAIL: hi@ionicframework.com + - name: Sleep while npm takes its time + run: sleep 20 + - name: GitHub Container Registry Login + run: echo ${GH_TOKEN} | docker login ghcr.io -u ionitron --password-stdin + env: + GH_TOKEN: ${{ secrets.GH_TOKEN }} + - name: Build Container + run: | + docker build \ + --build-arg IONIC_CLI_VERSION=$(npm info @ionic/cli dist-tags.latest) \ + --tag ghcr.io/${{ github.repository }}:latest \ + --tag ghcr.io/${{ github.repository}}:$(npm info @ionic/cli dist-tags.latest) \ + . + - name: Push Container as latest + run: docker push ghcr.io/${{ github.repository }}:latest + - name: Push Container as version + run: docker push ghcr.io/${{ github.repository }}:$(npm info @ionic/cli dist-tags.latest) diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml new file mode 100644 index 0000000000..3ee0d8533c --- /dev/null +++ b/.github/workflows/docker-image.yml @@ -0,0 +1,31 @@ +name: BuildDockerImage + +on: workflow_dispatch + +jobs: + build-docker-container: + name: Build and Deploy Docker Container with latest CLI + runs-on: ubuntu-latest + steps: + - uses: actions/setup-node@v1 + with: + node-version: 14.x + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: GitHub Container Registry Login + run: echo ${GH_TOKEN} | docker login ghcr.io -u ionitron --password-stdin + env: + GH_TOKEN: ${{ secrets.GH_TOKEN }} + + - name: Build Container + run: | + docker build \ + --build-arg IONIC_CLI_VERSION=$(npm info @ionic/cli dist-tags.latest) \ + --tag ghcr.io/${{ github.repository }}:latest \ + --tag ghcr.io/${{ github.repository}}:$(npm info @ionic/cli dist-tags.latest) \ + . + - name: Push Container as latest + run: docker push ghcr.io/${{ github.repository }}:latest + - name: Push Container as version + run: docker push ghcr.io/${{ github.repository }}:$(npm info @ionic/cli dist-tags.latest) \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..2a73e5c8dc --- /dev/null +++ b/Dockerfile @@ -0,0 +1,14 @@ +FROM node:lts + +# Set CI to true & LANG +ENV CI=1 +ENV LANG en_US.UTF-8 + +# Install the desired version of @ionic/cli +ARG IONIC_CLI_VERSION + +RUN npm i -g @ionic/cli@${IONIC_CLI_VERSION} && \ + ionic --no-interactive config set -g daemon.updates false && \ + ionic --no-interactive config set -g telemetry false + +WORKDIR /usr/src/app \ No newline at end of file diff --git a/packages/@ionic/cli-framework/CHANGELOG.md b/packages/@ionic/cli-framework/CHANGELOG.md index 7baf489a2f..2310c3412c 100644 --- a/packages/@ionic/cli-framework/CHANGELOG.md +++ b/packages/@ionic/cli-framework/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.1.0](https://github.com/ionic-team/ionic-cli/compare/@ionic/cli-framework@5.0.6...@ionic/cli-framework@5.1.0) (2020-12-10) + + +### Features + +* **config:** add spaces option when writing JSON config ([#4612](https://github.com/ionic-team/ionic-cli/issues/4612)) ([fdd9bb2](https://github.com/ionic-team/ionic-cli/commit/fdd9bb26098441238adc56ea7a67b385a3b9a964)) + + + + + ## [5.0.6](https://github.com/ionic-team/ionic-cli/compare/@ionic/cli-framework@5.0.5...@ionic/cli-framework@5.0.6) (2020-09-29) **Note:** Version bump only for package @ionic/cli-framework diff --git a/packages/@ionic/cli-framework/package.json b/packages/@ionic/cli-framework/package.json index 5ebb8981cd..6babda09be 100644 --- a/packages/@ionic/cli-framework/package.json +++ b/packages/@ionic/cli-framework/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/cli-framework", - "version": "5.0.6", + "version": "5.1.0", "description": "The foundation framework of the Ionic CLI", "homepage": "https://ionicframework.com/", "author": "Ionic Team (https://ionicframework.com) ", diff --git a/packages/@ionic/cli-framework/src/lib/config.ts b/packages/@ionic/cli-framework/src/lib/config.ts index 80832cf27e..e8a79824db 100644 --- a/packages/@ionic/cli-framework/src/lib/config.ts +++ b/packages/@ionic/cli-framework/src/lib/config.ts @@ -5,6 +5,11 @@ import * as path from 'path'; import * as writeFileAtomic from 'write-file-atomic'; export interface BaseConfigOptions { + /** + * The number of spaces to use when writing the JSON file. + */ + spaces?: string | number; + /** * If specified, the class will operate on a nested object within the config * file navigated to by this path prefix, an array of object path keys. @@ -16,9 +21,11 @@ export interface BaseConfigOptions { } export abstract class BaseConfig { + protected readonly spaces: string | number; protected readonly pathPrefix: readonly string[]; - constructor(readonly p: string, { pathPrefix = [] }: BaseConfigOptions = {}) { + constructor(readonly p: string, { spaces = 2, pathPrefix = [] }: BaseConfigOptions = {}) { + this.spaces = spaces; this.pathPrefix = pathPrefix; } @@ -87,6 +94,6 @@ export abstract class BaseConfig { private _setFile(value: any): void { mkdirpSync(path.dirname(this.p)); - writeFileAtomic.sync(this.p, JSON.stringify(value, undefined, 2) + '\n'); + writeFileAtomic.sync(this.p, JSON.stringify(value, undefined, this.spaces) + '\n'); } } diff --git a/packages/@ionic/cli/CHANGELOG.md b/packages/@ionic/cli/CHANGELOG.md index 3b8232d031..5f11f4dbfb 100644 --- a/packages/@ionic/cli/CHANGELOG.md +++ b/packages/@ionic/cli/CHANGELOG.md @@ -3,6 +3,73 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [6.12.3](https://github.com/ionic-team/ionic-cli/compare/@ionic/cli@6.12.2...@ionic/cli@6.12.3) (2020-12-10) + + +### Bug Fixes + +* **appflow:** allow download of packages built from branches with in the name. CT-434 ([#4622](https://github.com/ionic-team/ionic-cli/issues/4622)) ([0054fd5](https://github.com/ionic-team/ionic-cli/commit/0054fd51706c071ffad98bf04ee053266bc780d1)) + + + + + +## [6.12.2](https://github.com/ionic-team/ionic-cli/compare/@ionic/cli@6.12.1...@ionic/cli@6.12.2) (2020-11-17) + + +### Bug Fixes + +* **react:** fix stdin to unblock react-scripts>3.4.0 ([#4609](https://github.com/ionic-team/ionic-cli/issues/4609)) ([47631f5](https://github.com/ionic-team/ionic-cli/commit/47631f5a9331f3bc428933da68c82176221746c6)) + + + + + +## [6.12.1](https://github.com/ionic-team/ionic-cli/compare/@ionic/cli@6.12.0...@ionic/cli@6.12.1) (2020-10-29) + + +### Bug Fixes + +* **Appflow:** fixes bug when a build that gets cancelled on the dashboard is not recognized as a final state in the CLI ([#4598](https://github.com/ionic-team/ionic-cli/issues/4598)) ([51eab00](https://github.com/ionic-team/ionic-cli/commit/51eab00105a7616df869cd82eea54f1a55b7ab44)) + + + + + +# [6.12.0](https://github.com/ionic-team/ionic-cli/compare/@ionic/cli@6.11.12...@ionic/cli@6.12.0) (2020-10-15) + + +### Features + +* support vue projects ([#4515](https://github.com/ionic-team/ionic-cli/issues/4515)) ([ad6c483](https://github.com/ionic-team/ionic-cli/commit/ad6c483bd59b4f5e70acac22f456b0b062f4d39c)) + + + + + +## [6.11.12](https://github.com/ionic-team/ionic-cli/compare/@ionic/cli@6.11.11...@ionic/cli@6.11.12) (2020-10-12) + + +### Bug Fixes + +* **capacitor:** use correct root when checking platforms ([e243357](https://github.com/ionic-team/ionic-cli/commit/e2433573bae66210d7ef29d6a2c170faa8abe408)) +* **cordova:** load config.xml after serve/build hooks ([9867ada](https://github.com/ionic-team/ionic-cli/commit/9867adafbdd200712a35b38d39c54af6f809c987)) + + + + + +## [6.11.11](https://github.com/ionic-team/ionic-cli/compare/@ionic/cli@6.11.10...@ionic/cli@6.11.11) (2020-10-05) + + +### Bug Fixes + +* **Appflow:** fix bug where appflow build would fail to copy IPA/APK if tmp dir was mounted on a different filesystem ([#4578](https://github.com/ionic-team/ionic-cli/issues/4578)) ([65c740d](https://github.com/ionic-team/ionic-cli/commit/65c740d8ef3195e63d026ac229b7fe8bf1187da6)) + + + + + ## [6.11.10](https://github.com/ionic-team/ionic-cli/compare/@ionic/cli@6.11.9...@ionic/cli@6.11.10) (2020-09-29) **Note:** Version bump only for package @ionic/cli diff --git a/packages/@ionic/cli/package.json b/packages/@ionic/cli/package.json index cea01c8fb8..68dd5c18be 100644 --- a/packages/@ionic/cli/package.json +++ b/packages/@ionic/cli/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/cli", - "version": "6.11.10", + "version": "6.12.3", "description": "A tool for creating and developing Ionic Framework mobile apps.", "homepage": "https://ionicframework.com", "author": "Ionic Team (https://ionicframework.com) ", @@ -40,7 +40,7 @@ }, "license": "MIT", "dependencies": { - "@ionic/cli-framework": "5.0.6", + "@ionic/cli-framework": "5.1.0", "@ionic/cli-framework-output": "2.2.2", "@ionic/cli-framework-prompts": "2.1.8", "@ionic/utils-array": "2.1.5", diff --git a/packages/@ionic/cli/src/commands/capacitor/base.ts b/packages/@ionic/cli/src/commands/capacitor/base.ts index 43c4fdfb21..67cd26a82e 100644 --- a/packages/@ionic/cli/src/commands/capacitor/base.ts +++ b/packages/@ionic/cli/src/commands/capacitor/base.ts @@ -117,7 +117,13 @@ export abstract class CapacitorCommand extends Command { } if (platform) { - const integrationRoot = this.project.directory; + const capacitor = this.project.getIntegration('capacitor'); + + if (!capacitor) { + throw new FatalException('Cannot check platform installations--Capacitor not yet integrated.'); + } + + const integrationRoot = capacitor.root; const platformsToCheck = ['android', 'ios', 'electron']; const platforms = (await Promise.all(platformsToCheck.map(async (p): Promise<[string, boolean]> => [p, await pathExists(path.resolve(integrationRoot, p))]))) .filter(([, e]) => e) diff --git a/packages/@ionic/cli/src/commands/cordova/run.ts b/packages/@ionic/cli/src/commands/cordova/run.ts index 69548adc75..403bac6497 100644 --- a/packages/@ionic/cli/src/commands/cordova/run.ts +++ b/packages/@ionic/cli/src/commands/cordova/run.ts @@ -255,7 +255,6 @@ Just like with ${input('ionic cordova build')}, you can pass additional options protected async runServeDeploy(inputs: CommandLineInputs, options: CommandLineOptions): Promise { const { loadCordovaConfig } = await import('../../lib/integrations/cordova/config'); - const conf = await loadCordovaConfig(this.integration); const metadata = await this.getMetadata(); if (!this.project) { @@ -283,6 +282,8 @@ Just like with ${input('ionic cordova build')}, you can pass additional options serverUrl = `${details.protocol || 'http'}://${details.externalAddress}:${details.port}`; } + const conf = await loadCordovaConfig(this.integration); + onBeforeExit(async () => { conf.resetContentSrc(); await conf.save(); @@ -313,7 +314,6 @@ Just like with ${input('ionic cordova build')}, you can pass additional options protected async runBuildDeploy(inputs: CommandLineInputs, options: CommandLineOptions): Promise { const { loadCordovaConfig } = await import('../../lib/integrations/cordova/config'); - const conf = await loadCordovaConfig(this.integration); const metadata = await this.getMetadata(); if (!this.project) { @@ -335,6 +335,7 @@ Just like with ${input('ionic cordova build')}, you can pass additional options } if (options['native-run']) { + const conf = await loadCordovaConfig(this.integration); const [ platform ] = inputs; await this.runCordova(filterArgumentsForCordova({ ...metadata, name: 'build' }, options), { stdio: 'inherit' }); diff --git a/packages/@ionic/cli/src/commands/deploy/build.ts b/packages/@ionic/cli/src/commands/deploy/build.ts index c772c808ae..78e720be8c 100644 --- a/packages/@ionic/cli/src/commands/deploy/build.ts +++ b/packages/@ionic/cli/src/commands/deploy/build.ts @@ -115,7 +115,7 @@ Apart from ${input('--commit')}, every option can be specified using the full na build = await this.tailBuildLog(appflowId, buildId, token); if (build.state !== 'success') { - throw new Error('Build failed'); + throw new Error(`Build ${build.state}`); } } @@ -161,7 +161,7 @@ Apart from ${input('--commit')}, every option can be specified using the full na let isCreatedMessage = false; let errorsEncountered = 0; - while (!(build && (build.state === 'success' || build.state === 'failed'))) { + while (!(build && ['success', 'failed', 'canceled'].includes(build.state))) { try { await sleep(5000); build = await this.getDeployBuild(appflowId, buildId, token); diff --git a/packages/@ionic/cli/src/commands/package/build.ts b/packages/@ionic/cli/src/commands/package/build.ts index 6e40dfa333..83d801266b 100644 --- a/packages/@ionic/cli/src/commands/package/build.ts +++ b/packages/@ionic/cli/src/commands/package/build.ts @@ -65,11 +65,11 @@ This command creates a package build on Ionic Appflow. While the build is runnin Apart from ${input('--commit')}, every option can be specified using the full name setup within the Dashboard[^dashboard]. -The ${input('--security-profile')} option is mandatory for any iOS build but not for Android debug builds. +The ${input('--signing-certificate')} option is mandatory for any iOS build but not for Android debug builds. Customizing the build: - The ${input('--environment')} and ${input('--native-config')} options can be used to customize the groups of values exposed to the build. -- Override the preferred platform with ${input('--target-platform')}. This is useful for building older iOS apps. +- Override the preferred platform with ${input('--build-stack')}. This is useful for building older iOS apps. Deploying the build to an App Store: - The ${input('--destination')} option can be used to deliver the app created by the build to the configured App Store. \ @@ -83,13 +83,13 @@ This can be used only together with build type ${input('release')} for Android a ], exampleCommands: [ 'android debug', - 'ios development --security-profile="iOS Signing Certificate Name"', + 'ios development --signing-certificate="iOS Signing Certificate Name"', 'android debug --environment="My Custom Environment Name"', 'android debug --native-config="My Custom Native Config Name"', 'android debug --commit=2345cd3305a1cf94de34e93b73a932f25baac77c', - 'ios development --security-profile="iOS Signing Certificate Name" --target-platform="iOS - Xcode 9"', - 'ios development --security-profile="iOS Signing Certificate Name" --build-file-name=my_custom_file_name.ipa', - 'ios app-store --security-profile="iOS Signing Certificate Name" --destination="Apple App Store Destination"', + 'ios development --signing-certificate="iOS Signing Certificate Name" --build-stack="iOS - Xcode 9"', + 'ios development --signing-certificate="iOS Signing Certificate Name" --build-file-name=my_custom_file_name.ipa', + 'ios app-store --signing-certificate="iOS Signing Certificate Name" --destination="Apple App Store Destination"', ], inputs: [ { @@ -105,8 +105,8 @@ This can be used only together with build type ${input('release')} for Android a ], options: [ { - name: 'security-profile', - summary: 'Security profile', + name: 'signing-certificate', + summary: 'Signing certificate', type: String, spec: { value: 'name' }, }, @@ -136,7 +136,7 @@ This can be used only together with build type ${input('release')} for Android a spec: { value: 'sha1' }, }, { - name: 'target-platform', + name: 'build-stack', summary: `Target platform (${TARGET_PLATFORM.map(v => input(`"${v}"`)).join(', ')})`, type: String, groups: [MetadataGroup.ADVANCED], @@ -188,20 +188,30 @@ This can be used only together with build type ${input('release')} for Android a inputs[1] = typeInput; } - // the security profile is mandatory for iOS packages, so prompting if it is missing - if (inputs[0] === 'ios' && !options['security-profile']) { + if (options['target-platform']) { + this.env.log.warn(`The ${input('--target-platform')} option has been deprecated. Please use ${input('--build-stack')}.`); + options['build-stack'] = options['target-platform']; + } + + if (options['security-profile']) { + this.env.log.warn(`The ${input('--security-profile')} option has been deprecated. Please use ${input('--signing-certificate')}.`); + options['signing-certificate'] = options['security-profile']; + } + + // the signing certificate is mandatory for iOS packages, so prompting if it is missing + if (inputs[0] === 'ios' && !options['signing-certificate']) { if (this.env.flags.interactive) { this.env.log.nl(); - this.env.log.warn(`A security profile is mandatory to build an iOS package`); + this.env.log.warn(`A signing certificate is mandatory to build an iOS package`); } const securityProfileOption = await this.env.prompt({ type: 'input', - name: 'security-profile', - message: `Security Profile Name:`, + name: 'signing-certificate', + message: `Signing Certificate Name:`, }); - options['security-profile'] = securityProfileOption; + options['signing-certificate'] = securityProfileOption; } // if destination is present, validate that a proper build type has been been specified @@ -254,7 +264,7 @@ This can be used only together with build type ${input('release')} for Android a build = await this.tailBuildLog(appflowId, buildId, token); if (build.state !== 'success') { - throw new Error('Build failed'); + throw new Error(`Build ${build.state}`); } const url = await this.getDownloadUrl(appflowId, buildId, token); @@ -272,8 +282,8 @@ This can be used only together with build type ${input('release')} for Android a platform, build_type: buildType, commit_sha: options.commit, - stack_name: options['target-platform'], - profile_name: options['security-profile'], + stack_name: options['build-stack'], + profile_name: options['signing-certificate'], environment_name: options.environment, native_config_name: options['native-config'], distribution_credential_name: options.destination, @@ -342,7 +352,7 @@ This can be used only together with build type ${input('release')} for Android a let isCreatedMessage = false; let errorsEncountered = 0; - while (!(build && (build.state === 'success' || build.state === 'failed'))) { + while (!(build && ['success', 'failed', 'canceled'].includes(build.state))) { try { await sleep(5000); build = await this.getPackageBuild(appflowId, buildId, token); @@ -377,15 +387,15 @@ This can be used only together with build type ${input('release')} for Android a if (!filename) { req.on('response', res => { const contentDisposition = res.header['content-disposition']; - filename = contentDisposition ? contentDisposition.split('=')[1] : 'output.bin'; + filename = contentDisposition ? contentDisposition.split('=')[1].replace(/([/?<>*|\"])/g, '_') : 'output.bin'; }); } const tmpFile = tmpfilepath('ionic-package-build'); const ws = fs.createWriteStream(tmpFile); await download(req, ws, {}); - fs.renameSync(tmpFile, filename); - + fs.copyFileSync(tmpFile, filename); + fs.unlinkSync(tmpFile); return filename; } } diff --git a/packages/@ionic/cli/src/commands/start.ts b/packages/@ionic/cli/src/commands/start.ts index 1362a2bdca..1944cda42c 100644 --- a/packages/@ionic/cli/src/commands/start.ts +++ b/packages/@ionic/cli/src/commands/start.ts @@ -539,9 +539,11 @@ Use the ${input('--type')} option to start projects using older versions of Ioni this.env.shell.alterPath = p => prependNodeModulesBinToPath(projectDir, p); if (!this.schema.cloned) { - if (this.schema.type === 'react') { - options['capacitor'] = true; - } + // Default to capacitor always + if (this.schema.type === 'react' || this.schema.type === 'vue') { + options['capacitor'] = true; + } + if (options['cordova']) { const { confirmCordovaUsage } = await import('../lib/integrations/cordova/utils'); diff --git a/packages/@ionic/cli/src/definitions.ts b/packages/@ionic/cli/src/definitions.ts index 1636c78e2c..69ed628554 100644 --- a/packages/@ionic/cli/src/definitions.ts +++ b/packages/@ionic/cli/src/definitions.ts @@ -644,7 +644,6 @@ export interface ReactBuildOptions extends BuildOptions<'react'> { export interface VueBuildOptions extends BuildOptions<'vue'> { configuration?: string; sourcemaps?: boolean; - cordovaAssets?: boolean; } export interface IonicCapacitorOptions { @@ -723,7 +722,8 @@ export interface ReactServeOptions extends ServeOptions { } export interface VueServeOptions extends ServeOptions { - ssl?: boolean; + https: boolean; + mode: string; configuration?: string; sourcemaps?: boolean; } diff --git a/packages/@ionic/cli/src/lib/project/vue/build.ts b/packages/@ionic/cli/src/lib/project/vue/build.ts index 56eede35c9..2437e0dfb2 100644 --- a/packages/@ionic/cli/src/lib/project/vue/build.ts +++ b/packages/@ionic/cli/src/lib/project/vue/build.ts @@ -1,11 +1,13 @@ -import * as chalk from 'chalk'; - import { CommandLineInputs, CommandLineOptions, CommandMetadata, VueBuildOptions } from '../../../definitions'; -import { BuildRunner, BuildRunnerDeps } from '../../build'; -import { RunnerException } from '../../errors'; +import { BUILD_SCRIPT, BuildCLI, BuildRunner, BuildRunnerDeps } from '../../build'; + +import { VueProject } from './'; +export interface VueBuildRunnerDeps extends BuildRunnerDeps { + readonly project: VueProject; +} export class VueBuildRunner extends BuildRunner { - constructor(protected readonly e: BuildRunnerDeps) { + constructor(protected readonly e: VueBuildRunnerDeps) { super(); } @@ -23,15 +25,31 @@ export class VueBuildRunner extends BuildRunner { } async buildProject(options: VueBuildOptions): Promise { - const cli = this.getPkgManagerBuildCLI(); + const vueScripts = new VueBuildCLI(this.e); + await vueScripts.build(options); + } +} - if (!await cli.resolveScript()) { - throw new RunnerException( - `Cannot perform build.\n` + - `Since you're using the ${chalk.bold('Vue')} project type, you must provide the ${chalk.green(cli.script)} npm script so the Ionic CLI can build your project.` - ); +export class VueBuildCLI extends BuildCLI { + readonly name = 'Vue CLI Service'; + readonly pkg = '@vue/cli-service'; + readonly program = 'vue-cli-service'; + readonly prefix = 'vue-cli-service'; + readonly script = BUILD_SCRIPT; + + protected async buildArgs(options: VueBuildOptions): Promise { + const { pkgManagerArgs } = await import('../../utils/npm'); + + if (this.resolvedProgram === this.program) { + return ['build']; + } else { + const [ , ...pkgArgs ] = await pkgManagerArgs(this.e.config.get('npmClient'), { command: 'run', script: this.script }); + return pkgArgs; } + } - await cli.build(options); + protected async buildEnvVars(options: VueBuildOptions): Promise { + const env: NodeJS.ProcessEnv = {}; + return { ...await super.buildEnvVars(options), ...env }; } } diff --git a/packages/@ionic/cli/src/lib/project/vue/index.ts b/packages/@ionic/cli/src/lib/project/vue/index.ts index 4a8847039b..d1eea5c605 100644 --- a/packages/@ionic/cli/src/lib/project/vue/index.ts +++ b/packages/@ionic/cli/src/lib/project/vue/index.ts @@ -1,6 +1,7 @@ import * as chalk from 'chalk'; import * as Debug from 'debug'; import * as lodash from 'lodash'; +import * as path from 'path'; import { Project } from '../'; import { InfoItem } from '../../../definitions'; @@ -13,7 +14,7 @@ export class VueProject extends Project { async getInfo(): Promise { const [ - [ ionicVuePkg, ionicVuePkgPath ], + [ionicVuePkg, ionicVuePkgPath], ] = await Promise.all([ this.getPackageJson('@ionic/vue'), ]); @@ -71,4 +72,9 @@ export class VueProject extends Project { `Since you're using the ${chalk.bold('Vue')} project type, this command won't work. The Ionic CLI doesn't know how to generate framework components for Vue projects.` ); } + + setPrimaryTheme(themeColor: string): Promise { + const themePath = path.join(this.directory, 'src', 'theme', 'variables.css'); + return this.writeThemeColor(themePath, themeColor); + } } diff --git a/packages/@ionic/cli/src/lib/project/vue/serve.ts b/packages/@ionic/cli/src/lib/project/vue/serve.ts index 34d96d99d4..fd0947c412 100644 --- a/packages/@ionic/cli/src/lib/project/vue/serve.ts +++ b/packages/@ionic/cli/src/lib/project/vue/serve.ts @@ -1,9 +1,9 @@ +import { stripAnsi } from '@ionic/cli-framework-output'; import { findClosestOpenPort } from '@ionic/utils-network'; -import * as chalk from 'chalk'; import { CommandMetadata, ServeDetails, VueServeOptions } from '../../../definitions'; -import { RunnerException } from '../../errors'; -import { BIND_ALL_ADDRESS, LOCAL_ADDRESSES, ServeRunner, ServeRunnerDeps } from '../../serve'; +import { strong } from '../../color'; +import { BIND_ALL_ADDRESS, DEFAULT_ADDRESS, LOCAL_ADDRESSES, SERVE_SCRIPT, ServeCLI, ServeRunner, ServeRunnerDeps } from '../../serve'; export class VueServeRunner extends ServeRunner { constructor(protected readonly e: ServeRunnerDeps) { @@ -14,29 +14,21 @@ export class VueServeRunner extends ServeRunner { return {}; } - modifyOpenUrl(url: string, options: VueServeOptions): string { + modifyOpenUrl(url: string, _options: VueServeOptions): string { return url; } async serveProject(options: VueServeOptions): Promise { - const cli = this.getPkgManagerServeCLI(); - - if (!await cli.resolveScript()) { - throw new RunnerException( - `Cannot perform serve.\n` + - `Since you're using the ${chalk.bold('Vue')} project type, you must provide the ${chalk.green(cli.script)} npm script so the Ionic CLI can serve your project.` - ); - } - - const [ externalIP, availableInterfaces ] = await this.selectExternalIP(options); + const [externalIP, availableInterfaces] = await this.selectExternalIP(options); const port = options.port = await findClosestOpenPort(options.port); - await cli.serve(options); + const vueScripts = new VueServeCLI(this.e); + await vueScripts.serve(options); return { - custom: false, - protocol: 'http', + custom: vueScripts.resolvedProgram !== vueScripts.program, + protocol: options.https ? 'https' : 'http', localAddress: 'localhost', externalAddress: externalIP, externalNetworkInterfaces: availableInterfaces, @@ -44,4 +36,90 @@ export class VueServeRunner extends ServeRunner { externallyAccessible: ![BIND_ALL_ADDRESS, ...LOCAL_ADDRESSES].includes(externalIP), }; } + +} + +export class VueServeCLI extends ServeCLI { + readonly name = 'Vue CLI Service'; + readonly pkg = '@vue/cli-service'; + readonly program = 'vue-cli-service'; + readonly prefix = 'vue-cli-service'; + readonly script = SERVE_SCRIPT; + protected chunks = 0; + + async serve(options: VueServeOptions): Promise { + this.on('compile', chunks => { + if (chunks > 0) { + this.e.log.info(`... and ${strong(chunks.toString())} additional chunks`); + } + }); + + return super.serve(options); + } + + protected stdoutFilter(line: string): boolean { + if (this.resolvedProgram !== this.program) { + return super.stdoutFilter(line); + } + + const strippedLine = stripAnsi(line); + const compileMsgs = ['Compiled successfully', 'Compiled with warnings', 'Failed to compile']; + if (compileMsgs.some(msg => strippedLine.includes(msg))) { + this.emit('ready'); + return false; + } + + if (strippedLine.match(/.*chunk\s{\d+}.+/)) { + this.chunks++; + return false; + } + + if (strippedLine.includes('Compiled successfully')) { + this.emit('compile', this.chunks); + this.chunks = 0; + } + + // const endBannerMsgs = ['development build', 'production build'] + // if (endBannerMsgs.some(msg => strippedLine.includes(msg))) { + // return false; + // } + return true; + } + protected stderrFilter(line: string): boolean { + if (this.resolvedProgram !== this.program) { + return super.stderrFilter(line); + } + const strippedLine = stripAnsi(line); + if (strippedLine.includes('webpack.Progress')) { + return false; + } + + return true; + + } + + protected async buildArgs(_options: VueServeOptions): Promise { + const { pkgManagerArgs } = await import('../../utils/npm'); + + if (this.resolvedProgram === this.program) { + return ['serve']; + } else { + const [, ...pkgArgs] = await pkgManagerArgs(this.e.config.get('npmClient'), { command: 'run', script: this.script }); + return pkgArgs; + } + } + + protected async buildEnvVars(options: VueServeOptions): Promise { + const env: NodeJS.ProcessEnv = {}; + // // Vue CLI binds to `localhost` by default, but if specified it prints a + // // warning, so don't set `HOST` if the host is set to `localhost`. + if (options.host !== DEFAULT_ADDRESS) { + env.HOST = options.host; + } + + env.PORT = String(options.port); + env.HTTPS = options.https ? 'true' : 'false'; + + return { ...await super.buildEnvVars(options), ...env }; + } } diff --git a/packages/@ionic/cli/src/lib/serve.ts b/packages/@ionic/cli/src/lib/serve.ts index bd7c91e468..0027a043cc 100644 --- a/packages/@ionic/cli/src/lib/serve.ts +++ b/packages/@ionic/cli/src/lib/serve.ts @@ -493,7 +493,7 @@ export abstract class ServeCLI extends EventEmitter { protected async spawn(options: T): Promise { const args = await this.buildArgs(options); const env = await this.buildEnvVars(options); - const p = await this.e.shell.spawn(this.resolvedProgram, args, { stdio: 'pipe', cwd: this.e.project.directory, env: createProcessEnv(env) }); + const p = await this.e.shell.spawn(this.resolvedProgram, args, { stdio: ['inherit', 'pipe', 'pipe'], cwd: this.e.project.directory, env: createProcessEnv(env) }); return new Promise((resolve, reject) => { const errorHandler = (err: NodeJS.ErrnoException) => { diff --git a/packages/@ionic/cli/src/lib/session.ts b/packages/@ionic/cli/src/lib/session.ts index 83d3c16bf4..bcf28da595 100644 --- a/packages/@ionic/cli/src/lib/session.ts +++ b/packages/@ionic/cli/src/lib/session.ts @@ -15,6 +15,16 @@ export class BaseSession { constructor(readonly e: SessionDeps) {} async logout(): Promise { + const activeToken = this.e.config.get('tokens.user'); + if (activeToken) { + // invalidate the token + const { req } = await this.e.client.make('POST', '/logout'); + req.set('Authorization', `Bearer ${activeToken}`) + .send({}); + try { + await this.e.client.do(req); + } catch (e) {} + } this.e.config.unset('org.id'); this.e.config.unset('user.id'); this.e.config.unset('user.email'); diff --git a/packages/@ionic/cli/src/lib/start.ts b/packages/@ionic/cli/src/lib/start.ts index 72edaa3c9f..a6b4c18c6d 100644 --- a/packages/@ionic/cli/src/lib/start.ts +++ b/packages/@ionic/cli/src/lib/start.ts @@ -199,9 +199,42 @@ export const SUPPORTED_FRAMEWORKS: readonly SupportedFramework[] = [ type: 'react', description: 'https://reactjs.org', }, + { + name: 'Vue', + type: 'vue', + description: 'https://vuejs.org', + }, ]; export const STARTER_TEMPLATES: StarterTemplate[] = [ + { + name: 'tabs', + projectType: 'vue', + type: 'managed', + description: 'A starting project with a simple tabbed interface', + id: 'vue-official-tabs', + }, + { + name: 'sidemenu', + projectType: 'vue', + type: 'managed', + description: 'A starting project with a side menu with navigation in the content area', + id: 'vue-official-sidemenu', + }, + { + name: 'blank', + projectType: 'vue', + type: 'managed', + description: 'A blank starter project', + id: 'vue-official-blank', + }, + { + name: 'list', + projectType: 'vue', + type: 'managed', + description: 'A starting project with a list', + id: 'vue-official-list', + }, { name: 'tabs', projectType: 'angular', diff --git a/packages/@ionic/lab/CHANGELOG.md b/packages/@ionic/lab/CHANGELOG.md index 44de8b41fd..abd9b1f917 100644 --- a/packages/@ionic/lab/CHANGELOG.md +++ b/packages/@ionic/lab/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.2.10](https://github.com/ionic-team/ionic-cli/compare/@ionic/lab@3.2.9...@ionic/lab@3.2.10) (2020-12-10) + +**Note:** Version bump only for package @ionic/lab + + + + + ## [3.2.9](https://github.com/ionic-team/ionic-cli/compare/@ionic/lab@3.2.8...@ionic/lab@3.2.9) (2020-09-29) **Note:** Version bump only for package @ionic/lab diff --git a/packages/@ionic/lab/package.json b/packages/@ionic/lab/package.json index 8e9a5c2f3a..8a0ad2ca0c 100644 --- a/packages/@ionic/lab/package.json +++ b/packages/@ionic/lab/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/lab", - "version": "3.2.9", + "version": "3.2.10", "description": "Ionic Lab utility for developing Ionic apps, used by Ionic CLI", "bin": { "ionic-lab": "./bin/ionic-lab" @@ -41,7 +41,7 @@ "prepublishOnly": "npm run build" }, "dependencies": { - "@ionic/cli-framework": "5.0.6", + "@ionic/cli-framework": "5.1.0", "@ionic/utils-fs": "3.1.5", "chalk": "^4.0.0", "express": "^4.16.2", diff --git a/packages/@ionic/v1-toolkit/CHANGELOG.md b/packages/@ionic/v1-toolkit/CHANGELOG.md index dd29c6aec8..bd2a066bf4 100644 --- a/packages/@ionic/v1-toolkit/CHANGELOG.md +++ b/packages/@ionic/v1-toolkit/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [3.2.15](https://github.com/ionic-team/ionic-cli/compare/@ionic/v1-toolkit@3.2.14...@ionic/v1-toolkit@3.2.15) (2020-12-10) + +**Note:** Version bump only for package @ionic/v1-toolkit + + + + + ## [3.2.14](https://github.com/ionic-team/ionic-cli/compare/@ionic/v1-toolkit@3.2.13...@ionic/v1-toolkit@3.2.14) (2020-09-29) **Note:** Version bump only for package @ionic/v1-toolkit diff --git a/packages/@ionic/v1-toolkit/package.json b/packages/@ionic/v1-toolkit/package.json index 2fc98a3b21..6d27207467 100644 --- a/packages/@ionic/v1-toolkit/package.json +++ b/packages/@ionic/v1-toolkit/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/v1-toolkit", - "version": "3.2.14", + "version": "3.2.15", "description": "Utility CLI for Ionic 1.x apps, used by Ionic CLI", "bin": { "ionic-v1": "./bin/ionic-v1" @@ -36,7 +36,7 @@ "prepublishOnly": "npm run build" }, "dependencies": { - "@ionic/cli-framework": "5.0.6", + "@ionic/cli-framework": "5.1.0", "@ionic/utils-fs": "3.1.5", "@ionic/utils-terminal": "2.3.1", "chalk": "^4.0.0", diff --git a/packages/cli-scripts/CHANGELOG.md b/packages/cli-scripts/CHANGELOG.md index 3b002043f9..f3b461c5d5 100644 --- a/packages/cli-scripts/CHANGELOG.md +++ b/packages/cli-scripts/CHANGELOG.md @@ -3,6 +3,54 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [2.1.36](https://github.com/ionic-team/ionic-cli/compare/cli-scripts@2.1.35...cli-scripts@2.1.36) (2020-12-10) + +**Note:** Version bump only for package cli-scripts + + + + + +## [2.1.35](https://github.com/ionic-team/ionic-cli/compare/cli-scripts@2.1.34...cli-scripts@2.1.35) (2020-11-17) + +**Note:** Version bump only for package cli-scripts + + + + + +## [2.1.34](https://github.com/ionic-team/ionic-cli/compare/cli-scripts@2.1.33...cli-scripts@2.1.34) (2020-10-29) + +**Note:** Version bump only for package cli-scripts + + + + + +## [2.1.33](https://github.com/ionic-team/ionic-cli/compare/cli-scripts@2.1.32...cli-scripts@2.1.33) (2020-10-15) + +**Note:** Version bump only for package cli-scripts + + + + + +## [2.1.32](https://github.com/ionic-team/ionic-cli/compare/cli-scripts@2.1.31...cli-scripts@2.1.32) (2020-10-12) + +**Note:** Version bump only for package cli-scripts + + + + + +## [2.1.31](https://github.com/ionic-team/ionic-cli/compare/cli-scripts@2.1.30...cli-scripts@2.1.31) (2020-10-05) + +**Note:** Version bump only for package cli-scripts + + + + + ## [2.1.30](https://github.com/ionic-team/ionic-cli/compare/cli-scripts@2.1.29...cli-scripts@2.1.30) (2020-09-29) **Note:** Version bump only for package cli-scripts diff --git a/packages/cli-scripts/package.json b/packages/cli-scripts/package.json index 7cb5665b81..c8a625ebc1 100644 --- a/packages/cli-scripts/package.json +++ b/packages/cli-scripts/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "cli-scripts", - "version": "2.1.30", + "version": "2.1.36", "bin": { "ionic-cli-scripts": "./bin/ionic-cli-scripts" }, @@ -16,8 +16,8 @@ "main": "./dist/index.js", "types": "./dist/index.d.ts", "dependencies": { - "@ionic/cli": "6.11.10", - "@ionic/cli-framework": "5.0.6", + "@ionic/cli": "6.12.3", + "@ionic/cli-framework": "5.1.0", "@ionic/utils-fs": "3.1.5", "ansi-styles": "^4.0.0", "chalk": "^4.0.0",