Skip to content

Commit be6cf2e

Browse files
nphyattgiocalitri
andauthored
fix(Appflow): Fix issue with deploy add and deploy configure commands where sometimes necessary variables weren't correctly set. (#4634)
* fix(Appflow): Fix issue with deploy add and deploy configure commands where sometimes necessary variables weren't correctly set. Co-authored-by: Giovanni Di Milia <giovanni@ionic.io>
1 parent 62a4225 commit be6cf2e

File tree

3 files changed

+81
-13
lines changed

3 files changed

+81
-13
lines changed

packages/@ionic/cli/src/commands/deploy/add.ts

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { MetadataGroup } from '@ionic/cli-framework';
22

33
import { CommandInstanceInfo, CommandLineInputs, CommandLineOptions, CommandMetadata } from '../../definitions';
44
import { input } from '../../lib/color';
5-
import { FatalException } from '../../lib/errors';
65
import { runCommand } from '../../lib/executor';
76

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

9796
async preRun(inputs: CommandLineInputs, options: CommandLineOptions): Promise<void> {
98-
// check if it is already installed
99-
const alreadyAdded = await this.checkDeployInstalled();
100-
if (alreadyAdded) {
101-
throw new FatalException(
102-
`Appflow Deploy plugin is already installed.`
103-
);
104-
}
10597
// check if there are native integration installed
10698
await this.requireNativeIntegration();
10799
await this.preRunCheckInputs(options);
108100
}
109101

110-
async run(inputs: CommandLineInputs, options: CommandLineOptions, runinfo: CommandInstanceInfo): Promise<void> {
111-
const integration = await this.getAppIntegration();
102+
async addPlugin(options: CommandLineOptions, runinfo: CommandInstanceInfo, integration?: string) {
112103
if (integration === 'cordova') {
113104
let deployCommand = ['cordova', 'plugin', 'add', 'cordova-plugin-ionic'];
114105
const userOptions = this.buildCordovaDeployOptions(options);
@@ -125,6 +116,22 @@ For Cordova projects it just takes care of running the proper Cordova CLI comman
125116
);
126117
// install the plugin with npm
127118
await this.env.shell.run(installer, installerArgs, { stdio: 'inherit' });
119+
}
120+
121+
}
122+
123+
async run(inputs: CommandLineInputs, options: CommandLineOptions, runinfo: CommandInstanceInfo): Promise<void> {
124+
const integration = await this.getAppIntegration();
125+
126+
// check if it is already installed
127+
const alreadyAdded = await this.checkDeployInstalled();
128+
if (!alreadyAdded) {
129+
await this.addPlugin(options, runinfo, integration);
130+
} else {
131+
this.env.log.warn("Live Updates plugin already added. Reconfiguring only.");
132+
}
133+
134+
if (integration === 'capacitor') {
128135
// generate the manifest
129136
await runCommand(runinfo, ['deploy', 'manifest']);
130137
// run capacitor sync

packages/@ionic/cli/src/commands/deploy/configure.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { CommandInstanceInfo, CommandMetadata } from '../../definitions';
44
import { input } from '../../lib/color';
55
import { FatalException } from '../../lib/errors';
66

7+
78
import { DeployConfCommand } from './core';
89

910
export class ConfigureCommand extends DeployConfCommand {

packages/@ionic/cli/src/commands/deploy/core.ts

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export abstract class DeployCoreCommand extends Command {
3636

3737
export abstract class DeployConfCommand extends DeployCoreCommand {
3838

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

56+
protected readonly requiredOptionsDefaults: {[key: string]: string} = {
57+
'max-store': '2',
58+
'min-background-duration': '30',
59+
'update-api': 'https://api.ionicjs.com',
60+
}
61+
62+
protected readonly requiredOptionsFromPlistVal: {[key: string]: string} = {
63+
'IonMaxVersions': 'max-store',
64+
'IonMinBackgroundDuration': 'min-background-duration',
65+
'IonApi': 'update-api',
66+
}
67+
68+
protected readonly requiredOptionsFromXmlVal = {
69+
'ionic_max_versions': 'max-store',
70+
'ionic_min_background_duration': 'min-background-duration',
71+
'ionic_update_api': 'update-api',
72+
}
73+
5674
protected async getAppId(): Promise<string | undefined> {
5775
if (this.project) {
5876
return this.project.config.get('id');
@@ -132,7 +150,10 @@ export abstract class DeployConfCommand extends DeployCoreCommand {
132150
return false;
133151
}
134152
if (!plistPath) {
135-
this.env.log.info(`No Capacitor iOS project found.`);
153+
this.env.log.warn(
154+
`No ${strong('Capacitor iOS')} project found\n` +
155+
`You will need to rerun ${input('ionic deploy configure')} if you add it later.\n`
156+
);
136157
return false;
137158
}
138159
// try to load the plist file first
@@ -169,6 +190,7 @@ export abstract class DeployConfCommand extends DeployCoreCommand {
169190
}
170191
// check which options are set (configure might not have all of them set)
171192
const setOptions: { [key: string]: string } = {};
193+
172194
for (const [optionKey, plistKey] of Object.entries(this.optionsToPlistKeys)) {
173195
if (options[optionKey]) {
174196
setOptions[optionKey] = plistKey;
@@ -183,19 +205,39 @@ export abstract class DeployConfCommand extends DeployCoreCommand {
183205
const pdictChildren = pdict.getchildren();
184206
// there is no way to refer to a first right sibling in elementtree, so we use flags
185207
let removeNextStringTag = false;
208+
let existingRequiredKeys = [];
186209
for (const element of pdictChildren) {
210+
211+
// find required options and keep track of what is already existing
212+
if ((element.tag === 'key') && (element.text) && this.requiredOptionsFromPlistVal[element.text as string] != undefined) {
213+
existingRequiredKeys.push(this.requiredOptionsFromPlistVal[element.text as string])
214+
}
215+
187216
// we remove all the existing element if there
188217
if ((element.tag === 'key') && (element.text) && Object.values(setOptions).includes(element.text as string)) {
189218
pdict.remove(element);
190219
removeNextStringTag = true;
191220
continue;
192221
}
222+
193223
// and remove the first right sibling (this will happen at the next iteration of the loop
194224
if ((element.tag === 'string') && removeNextStringTag) {
195225
pdict.remove(element);
196226
removeNextStringTag = false;
197227
}
198228
}
229+
230+
// set any missing required keys to default
231+
for (const key of Object.keys(this.requiredOptionsDefaults)) {
232+
if (existingRequiredKeys.includes(key)) {
233+
continue;
234+
}
235+
setOptions[key] = this.optionsToPlistKeys[key];
236+
if (!options[key]) {
237+
options[key] = this.requiredOptionsDefaults[key];
238+
}
239+
}
240+
199241
// add again the new settings
200242
for (const [optionKey, plistKey] of Object.entries(setOptions)) {
201243
const plistValue = options[optionKey];
@@ -237,7 +279,9 @@ export abstract class DeployConfCommand extends DeployCoreCommand {
237279
return false;
238280
}
239281
if (!stringXmlPath) {
240-
this.env.log.info(`No Capacitor Android project found.`);
282+
this.env.log.warn(
283+
`No ${strong('Capacitor Android')} project found\n`+
284+
`You will need to rerun ${input('ionic deploy configure')} if you add it later.\n`);
241285
return false;
242286
}
243287
// try to load the plist file first
@@ -289,6 +333,22 @@ export abstract class DeployConfCommand extends DeployCoreCommand {
289333
element.text = options[optionKey] as string;
290334
}
291335
}
336+
337+
// make sure required keys are set
338+
for (const [stringKey, optionKey] of Object.entries(this.requiredOptionsFromXmlVal)) {
339+
let element = root.find(`./string[@name="${stringKey}"]`);
340+
// if the tag already exists, just update the content
341+
if (element) {
342+
continue;
343+
} else {
344+
// otherwise create the tag and set to default
345+
element = et.SubElement(root, 'string');
346+
element.set('name', stringKey);
347+
console.log(optionKey, 'opoitn key');
348+
element.text = this.requiredOptionsDefaults[optionKey];
349+
}
350+
}
351+
292352
// write back the modified plist
293353
const newXML = etree.write({
294354
encoding: 'utf-8',

0 commit comments

Comments
 (0)