Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 17 additions & 10 deletions packages/@ionic/cli/src/commands/deploy/add.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { MetadataGroup } from '@ionic/cli-framework';

import { CommandInstanceInfo, CommandLineInputs, CommandLineOptions, CommandMetadata } from '../../definitions';
import { input } from '../../lib/color';
import { FatalException } from '../../lib/errors';
import { runCommand } from '../../lib/executor';

import { DeployConfCommand } from './core';
Expand Down Expand Up @@ -95,20 +94,12 @@ For Cordova projects it just takes care of running the proper Cordova CLI comman
}

async preRun(inputs: CommandLineInputs, options: CommandLineOptions): Promise<void> {
// check if it is already installed
const alreadyAdded = await this.checkDeployInstalled();
if (alreadyAdded) {
throw new FatalException(
`Appflow Deploy plugin is already installed.`
);
}
// check if there are native integration installed
await this.requireNativeIntegration();
await this.preRunCheckInputs(options);
}

async run(inputs: CommandLineInputs, options: CommandLineOptions, runinfo: CommandInstanceInfo): Promise<void> {
const integration = await this.getAppIntegration();
async addPlugin(options: CommandLineOptions, runinfo: CommandInstanceInfo, integration?: string) {
if (integration === 'cordova') {
let deployCommand = ['cordova', 'plugin', 'add', 'cordova-plugin-ionic'];
const userOptions = this.buildCordovaDeployOptions(options);
Expand All @@ -125,6 +116,22 @@ For Cordova projects it just takes care of running the proper Cordova CLI comman
);
// install the plugin with npm
await this.env.shell.run(installer, installerArgs, { stdio: 'inherit' });
}

}

async run(inputs: CommandLineInputs, options: CommandLineOptions, runinfo: CommandInstanceInfo): Promise<void> {
const integration = await this.getAppIntegration();

// check if it is already installed
const alreadyAdded = await this.checkDeployInstalled();
if (!alreadyAdded) {
await this.addPlugin(options, runinfo, integration);
} else {
this.env.log.warn("Live Updates plugin already added. Reconfiguring only.");
}

if (integration === 'capacitor') {
// generate the manifest
await runCommand(runinfo, ['deploy', 'manifest']);
// run capacitor sync
Expand Down
1 change: 1 addition & 0 deletions packages/@ionic/cli/src/commands/deploy/configure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { CommandInstanceInfo, CommandMetadata } from '../../definitions';
import { input } from '../../lib/color';
import { FatalException } from '../../lib/errors';


import { DeployConfCommand } from './core';

export class ConfigureCommand extends DeployConfCommand {
Expand Down
66 changes: 63 additions & 3 deletions packages/@ionic/cli/src/commands/deploy/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export abstract class DeployCoreCommand extends Command {

export abstract class DeployConfCommand extends DeployCoreCommand {

protected readonly optionsToPlistKeys = {
protected readonly optionsToPlistKeys: {[key: string]: string} = {
'app-id': 'IonAppId',
'channel-name': 'IonChannelName',
'update-method': 'IonUpdateMethod',
Expand All @@ -53,6 +53,24 @@ export abstract class DeployConfCommand extends DeployCoreCommand {
'update-api': 'ionic_update_api',
};

protected readonly requiredOptionsDefaults: {[key: string]: string} = {
'max-store': '2',
'min-background-duration': '30',
'update-api': 'https://api.ionicjs.com',
}

protected readonly requiredOptionsFromPlistVal: {[key: string]: string} = {
'IonMaxVersions': 'max-store',
'IonMinBackgroundDuration': 'min-background-duration',
'IonApi': 'update-api',
}

protected readonly requiredOptionsFromXmlVal = {
'ionic_max_versions': 'max-store',
'ionic_min_background_duration': 'min-background-duration',
'ionic_update_api': 'update-api',
}

protected async getAppId(): Promise<string | undefined> {
if (this.project) {
return this.project.config.get('id');
Expand Down Expand Up @@ -132,7 +150,10 @@ export abstract class DeployConfCommand extends DeployCoreCommand {
return false;
}
if (!plistPath) {
this.env.log.info(`No Capacitor iOS project found.`);
this.env.log.warn(
`No ${strong('Capacitor iOS')} project found\n` +
`You will need to rerun ${input('ionic deploy configure')} if you add it later.\n`
);
return false;
}
// try to load the plist file first
Expand Down Expand Up @@ -169,6 +190,7 @@ export abstract class DeployConfCommand extends DeployCoreCommand {
}
// check which options are set (configure might not have all of them set)
const setOptions: { [key: string]: string } = {};

for (const [optionKey, plistKey] of Object.entries(this.optionsToPlistKeys)) {
if (options[optionKey]) {
setOptions[optionKey] = plistKey;
Expand All @@ -183,19 +205,39 @@ export abstract class DeployConfCommand extends DeployCoreCommand {
const pdictChildren = pdict.getchildren();
// there is no way to refer to a first right sibling in elementtree, so we use flags
let removeNextStringTag = false;
let existingRequiredKeys = [];
for (const element of pdictChildren) {

// find required options and keep track of what is already existing
if ((element.tag === 'key') && (element.text) && this.requiredOptionsFromPlistVal[element.text as string] != undefined) {
existingRequiredKeys.push(this.requiredOptionsFromPlistVal[element.text as string])
}

// we remove all the existing element if there
if ((element.tag === 'key') && (element.text) && Object.values(setOptions).includes(element.text as string)) {
pdict.remove(element);
removeNextStringTag = true;
continue;
}

// and remove the first right sibling (this will happen at the next iteration of the loop
if ((element.tag === 'string') && removeNextStringTag) {
pdict.remove(element);
removeNextStringTag = false;
}
}

// set any missing required keys to default
for (const key of Object.keys(this.requiredOptionsDefaults)) {
if (existingRequiredKeys.includes(key)) {
continue;
}
setOptions[key] = this.optionsToPlistKeys[key];
if (!options[key]) {
options[key] = this.requiredOptionsDefaults[key];
}
}

// add again the new settings
for (const [optionKey, plistKey] of Object.entries(setOptions)) {
const plistValue = options[optionKey];
Expand Down Expand Up @@ -237,7 +279,9 @@ export abstract class DeployConfCommand extends DeployCoreCommand {
return false;
}
if (!stringXmlPath) {
this.env.log.info(`No Capacitor Android project found.`);
this.env.log.warn(
`No ${strong('Capacitor Android')} project found\n`+
`You will need to rerun ${input('ionic deploy configure')} if you add it later.\n`);
return false;
}
// try to load the plist file first
Expand Down Expand Up @@ -289,6 +333,22 @@ export abstract class DeployConfCommand extends DeployCoreCommand {
element.text = options[optionKey] as string;
}
}

// make sure required keys are set
for (const [stringKey, optionKey] of Object.entries(this.requiredOptionsFromXmlVal)) {
let element = root.find(`./string[@name="${stringKey}"]`);
// if the tag already exists, just update the content
if (element) {
continue;
} else {
// otherwise create the tag and set to default
element = et.SubElement(root, 'string');
element.set('name', stringKey);
console.log(optionKey, 'opoitn key');
element.text = this.requiredOptionsDefaults[optionKey];
}
}

// write back the modified plist
const newXML = etree.write({
encoding: 'utf-8',
Expand Down