Skip to content

Commit 4f84379

Browse files
author
Dimitar Tachev
authored
Merge pull request #4816 from NativeScript/tachev/improve-migration
Improve the `migrate` command based on the feedback
2 parents 1aab6a3 + f869e46 commit 4f84379

File tree

8 files changed

+167
-101
lines changed

8 files changed

+167
-101
lines changed

lib/controllers/migrate-controller.ts

+33-12
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export class MigrateController extends UpdateControllerBase implements IMigrateC
1212
protected $platformsDataService: IPlatformsDataService,
1313
protected $packageInstallationManager: IPackageInstallationManager,
1414
protected $packageManager: IPackageManager,
15+
private $androidResourcesMigrationService: IAndroidResourcesMigrationService,
1516
private $devicePlatformsConstants: Mobile.IDevicePlatformsConstants,
1617
private $logger: ILogger,
1718
private $errors: IErrors,
@@ -37,16 +38,15 @@ export class MigrateController extends UpdateControllerBase implements IMigrateC
3738
];
3839

3940
private migrationDependencies: IMigrationDependency[] = [
40-
{ packageName: constants.TNS_CORE_MODULES_NAME, verifiedVersion: "6.0.0-rc-2019-06-28-175837-02" },
41+
{ packageName: constants.TNS_CORE_MODULES_NAME, verifiedVersion: "6.0.0-rc-2019-07-08-111131-01" },
4142
{ packageName: constants.TNS_CORE_MODULES_WIDGETS_NAME, verifiedVersion: "6.0.0" },
4243
{ packageName: "tns-platform-declarations", isDev: true, verifiedVersion: "6.0.0-rc-2019-06-28-175837-02" },
4344
{ packageName: "node-sass", isDev: true, verifiedVersion: "4.12.0" },
4445
{ packageName: "typescript", isDev: true, verifiedVersion: "3.4.1" },
45-
{ packageName: "less", isDev: true, verifiedVersion: "3.9.0" },
4646
{ packageName: "nativescript-dev-sass", isDev: true, replaceWith: "node-sass" },
4747
{ packageName: "nativescript-dev-typescript", isDev: true, replaceWith: "typescript" },
48-
{ packageName: "nativescript-dev-less", isDev: true, replaceWith: "less" },
49-
{ packageName: constants.WEBPACK_PLUGIN_NAME, isDev: true, shouldAddIfMissing: true, verifiedVersion: "1.0.0-rc-2019-07-02-161545-02" },
48+
{ packageName: "nativescript-dev-less", isDev: true, shouldRemove: true, warning: "LESS CSS is not supported out of the box. In order to enable it, follow the steps in this feature request: https://github.com/NativeScript/nativescript-dev-webpack/issues/967" },
49+
{ packageName: constants.WEBPACK_PLUGIN_NAME, isDev: true, shouldAddIfMissing: true, verifiedVersion: "1.0.0-rc-2019-07-08-135456-03" },
5050
{ packageName: "nativescript-camera", verifiedVersion: "4.5.0" },
5151
{ packageName: "nativescript-geolocation", verifiedVersion: "5.1.0" },
5252
{ packageName: "nativescript-imagepicker", verifiedVersion: "6.2.0" },
@@ -68,7 +68,7 @@ export class MigrateController extends UpdateControllerBase implements IMigrateC
6868
{ packageName: "nativescript-permissions", verifiedVersion: "1.3.0" },
6969
{ packageName: "nativescript-cardview", verifiedVersion: "3.2.0" },
7070
{
71-
packageName: "nativescript-unit-test-runner", verifiedVersion: "0.6.3",
71+
packageName: "nativescript-unit-test-runner", verifiedVersion: "0.6.4",
7272
shouldMigrateAction: (projectData: IProjectData) => this.hasDependency({ packageName: "nativescript-unit-test-runner", isDev: false }, projectData),
7373
migrateAction: this.migrateUnitTestRunner.bind(this)
7474
}
@@ -103,6 +103,8 @@ export class MigrateController extends UpdateControllerBase implements IMigrateC
103103
this.$logger.trace(`Error during auto-generated files handling. ${(error && error.message) || error}`);
104104
}
105105

106+
await this.migrateOldAndroidAppResources(projectData);
107+
106108
try {
107109
await this.cleanUpProject(projectData);
108110
await this.migrateDependencies(projectData);
@@ -112,6 +114,14 @@ export class MigrateController extends UpdateControllerBase implements IMigrateC
112114
}
113115
}
114116

117+
private async migrateOldAndroidAppResources(projectData: IProjectData) {
118+
const appResourcesPath = projectData.getAppResourcesDirectoryPath();
119+
if (!this.$androidResourcesMigrationService.hasMigrated(appResourcesPath)) {
120+
this.$logger.info("Migrate old Android App_Resources structure.");
121+
await this.$androidResourcesMigrationService.migrate(appResourcesPath);
122+
}
123+
}
124+
115125
public async shouldMigrate({ projectDir }: IProjectDir): Promise<boolean> {
116126
const projectData = this.$projectDataService.getProjectData(projectDir);
117127

@@ -123,7 +133,7 @@ export class MigrateController extends UpdateControllerBase implements IMigrateC
123133
return true;
124134
}
125135

126-
if (hasDependency && dependency.replaceWith) {
136+
if (hasDependency && (dependency.replaceWith || dependency.shouldRemove)) {
127137
return true;
128138
}
129139

@@ -134,6 +144,10 @@ export class MigrateController extends UpdateControllerBase implements IMigrateC
134144
if (!hasDependency && dependency.shouldAddIfMissing) {
135145
return true;
136146
}
147+
148+
if (!this.$androidResourcesMigrationService.hasMigrated(projectData.getAppResourcesDirectoryPath())) {
149+
return true;
150+
}
137151
}
138152

139153
for (const platform in this.$devicePlatformsConstants) {
@@ -146,6 +160,7 @@ export class MigrateController extends UpdateControllerBase implements IMigrateC
146160

147161
private async cleanUpProject(projectData: IProjectData): Promise<void> {
148162
this.$logger.info("Clean old project artefacts.");
163+
this.$projectDataService.removeNSConfigProperty(projectData.projectDir, "useLegacyWorkflow");
149164
this.$fs.deleteDirectory(path.join(projectData.projectDir, constants.HOOKS_DIR_NAME));
150165
this.$fs.deleteDirectory(path.join(projectData.projectDir, constants.PLATFORMS_DIR_NAME));
151166
this.$fs.deleteDirectory(path.join(projectData.projectDir, constants.NODE_MODULES_FOLDER_NAME));
@@ -244,15 +259,21 @@ export class MigrateController extends UpdateControllerBase implements IMigrateC
244259

245260
private async migrateDependency(dependency: IMigrationDependency, projectData: IProjectData): Promise<void> {
246261
const hasDependency = this.hasDependency(dependency, projectData);
262+
if (dependency.warning) {
263+
this.$logger.warn(dependency.warning);
264+
}
247265

248-
if (hasDependency && dependency.replaceWith) {
266+
if (hasDependency && (dependency.replaceWith || dependency.shouldRemove)) {
249267
this.$pluginsService.removeFromPackageJson(dependency.packageName, projectData.projectDir);
250-
const replacementDep = _.find(this.migrationDependencies, migrationPackage => migrationPackage.packageName === dependency.replaceWith);
251-
if (!replacementDep) {
252-
this.$errors.failWithoutHelp("Failed to find replacement dependency.");
268+
if (dependency.replaceWith) {
269+
const replacementDep = _.find(this.migrationDependencies, migrationPackage => migrationPackage.packageName === dependency.replaceWith);
270+
if (!replacementDep) {
271+
this.$errors.failWithoutHelp("Failed to find replacement dependency.");
272+
}
273+
this.$logger.info(`Replacing '${dependency.packageName}' with '${replacementDep.packageName}'.`);
274+
this.$pluginsService.addToPackageJson(replacementDep.packageName, replacementDep.verifiedVersion, replacementDep.isDev, projectData.projectDir);
253275
}
254-
this.$logger.info(`Replacing '${dependency.packageName}' with '${replacementDep.packageName}'.`);
255-
this.$pluginsService.addToPackageJson(replacementDep.packageName, replacementDep.verifiedVersion, replacementDep.isDev, projectData.projectDir);
276+
256277
return;
257278
}
258279

lib/definitions/migrate.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ interface IDependency {
1111
interface IMigrationDependency extends IDependency {
1212
shouldRemove?: boolean;
1313
replaceWith?: string;
14+
warning?: string;
1415
verifiedVersion?: string;
1516
shouldAddIfMissing?: boolean;
1617
shouldMigrateAction?: (projectData: IProjectData) => boolean;

lib/definitions/project.d.ts

+15-13
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ interface INsConfig {
7474
appPath?: string;
7575
appResourcesPath?: string;
7676
shared?: boolean;
77-
useLegacyWorkflow?: boolean;
7877
previewAppSchema?: string;
7978
}
8079

@@ -101,11 +100,6 @@ interface IProjectData extends ICreateProjectData {
101100
*/
102101
isShared: boolean;
103102

104-
/**
105-
* Defines if the project has hmr enabled by default
106-
*/
107-
useLegacyWorkflow: boolean;
108-
109103
/**
110104
* Defines the schema for the preview app
111105
*/
@@ -150,6 +144,14 @@ interface IProjectDataService {
150144
*/
151145
removeNSProperty(projectDir: string, propertyName: string): void;
152146

147+
/**
148+
* Removes a property from `nsconfig.json`.
149+
* @param {string} projectDir The project directory - the place where the `nsconfig.json` is located.
150+
* @param {string} propertyName The name of the property to be removed.
151+
* @returns {void}
152+
*/
153+
removeNSConfigProperty(projectDir: string, propertyName: string): void;
154+
153155
/**
154156
* Removes dependency from package.json
155157
* @param {string} projectDir The project directory - the place where the root package.json is located.
@@ -192,12 +194,12 @@ interface IProjectDataService {
192194
*/
193195
getAppExecutableFiles(projectDir: string): string[];
194196

195-
/**
196-
* Returns a value from `nativescript` key in project's package.json.
197-
* @param {string} jsonData The project directory - the place where the root package.json is located.
198-
* @param {string} propertyName The name of the property to be checked in `nativescript` key.
199-
* @returns {any} The value of the property.
200-
*/
197+
/**
198+
* Returns a value from `nativescript` key in project's package.json.
199+
* @param {string} jsonData The project directory - the place where the root package.json is located.
200+
* @param {string} propertyName The name of the property to be checked in `nativescript` key.
201+
* @returns {any} The value of the property.
202+
*/
201203
getNSValueFromContent(jsonData: Object, propertyName: string): any;
202204
}
203205

@@ -496,7 +498,7 @@ interface IRemoveExtensionsOptions {
496498
pbxProjPath: string
497499
}
498500

499-
interface IRemoveWatchAppOptions extends IRemoveExtensionsOptions{}
501+
interface IRemoveWatchAppOptions extends IRemoveExtensionsOptions { }
500502

501503
interface IRubyFunction {
502504
functionName: string;

lib/project-data.ts

-2
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ export class ProjectData implements IProjectData {
6161
public buildXcconfigPath: string;
6262
public podfilePath: string;
6363
public isShared: boolean;
64-
public useLegacyWorkflow: boolean;
6564
public previewAppSchema: string;
6665

6766
constructor(private $fs: IFileSystem,
@@ -137,7 +136,6 @@ export class ProjectData implements IProjectData {
137136
this.buildXcconfigPath = path.join(this.appResourcesDirectoryPath, this.$devicePlatformsConstants.iOS, constants.BUILD_XCCONFIG_FILE_NAME);
138137
this.podfilePath = path.join(this.appResourcesDirectoryPath, this.$devicePlatformsConstants.iOS, constants.PODFILE_NAME);
139138
this.isShared = !!(this.nsConfig && this.nsConfig.shared);
140-
this.useLegacyWorkflow = this.nsConfig && this.nsConfig.useLegacyWorkflow;
141139
this.previewAppSchema = this.nsConfig && this.nsConfig.previewAppSchema;
142140
return;
143141
}

lib/services/project-data-service.ts

+46-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import * as path from "path";
22
import { ProjectData } from "../project-data";
3+
import * as constants from "../constants";
4+
import { parseJson } from "../common/helpers";
35
import { exported } from "../common/decorators";
46
import {
57
NATIVESCRIPT_PROPS_INTERNAL_DELIMITER,
@@ -125,6 +127,12 @@ export class ProjectDataService implements IProjectDataService {
125127
};
126128
}
127129

130+
public removeNSConfigProperty(projectDir: string, propertyName: string): void {
131+
this.$logger.trace(`Removing "${propertyName}" property from nsconfig.`);
132+
this.updateNsConfigValue(projectDir, null, [propertyName]);
133+
this.$logger.trace(`"${propertyName}" property successfully removed.`);
134+
}
135+
128136
@exported("projectDataService")
129137
public async getAndroidAssetsStructure(opts: IProjectDir): Promise<IAssetGroup> {
130138
// TODO: Use image-size package to get the width and height of an image.
@@ -180,6 +188,43 @@ export class ProjectDataService implements IProjectDataService {
180188

181189
return files;
182190
}
191+
private refreshProjectData(projectDir: string) {
192+
if (this.projectDataCache[projectDir]) {
193+
this.projectDataCache[projectDir].initializeProjectData(projectDir);
194+
}
195+
}
196+
197+
private updateNsConfigValue(projectDir: string, updateObject?: INsConfig, propertiesToRemove?: string[]): void {
198+
const nsConfigPath = path.join(projectDir, constants.CONFIG_NS_FILE_NAME);
199+
const currentNsConfig = this.getNsConfig(nsConfigPath);
200+
let newNsConfig = currentNsConfig;
201+
if (updateObject) {
202+
newNsConfig = _.assign(newNsConfig || this.getNsConfigDefaultObject(), updateObject);
203+
}
204+
205+
if (newNsConfig && propertiesToRemove && propertiesToRemove.length) {
206+
newNsConfig = _.omit(newNsConfig, propertiesToRemove);
207+
}
208+
209+
if (newNsConfig) {
210+
this.$fs.writeJson(nsConfigPath, newNsConfig);
211+
this.refreshProjectData(projectDir);
212+
}
213+
}
214+
215+
private getNsConfig(nsConfigPath: string): INsConfig {
216+
let result: INsConfig = null;
217+
if (this.$fs.exists(nsConfigPath)) {
218+
const nsConfigContent = this.$fs.readText(nsConfigPath);
219+
try {
220+
result = <INsConfig>parseJson(nsConfigContent);
221+
} catch (e) {
222+
this.$logger.trace("The `nsconfig` content is not a valid JSON. Parse error: ", e);
223+
}
224+
}
225+
226+
return result;
227+
}
183228

184229
private getImageDefinitions(): IImageDefinitionsStructure {
185230
const pathToImageDefinitions = path.join(__dirname, "..", "..", CLI_RESOURCES_DIR_NAME, AssetConstants.assets, AssetConstants.imageDefinitionsFileName);
@@ -334,7 +379,7 @@ export class ProjectDataService implements IProjectDataService {
334379
}
335380

336381
private getNsConfigDefaultObject(data?: Object): INsConfig {
337-
const config: INsConfig = { useLegacyWorkflow: false };
382+
const config: INsConfig = {};
338383
Object.assign(config, data);
339384

340385
return config;

test/options.ts

-67
Original file line numberDiff line numberDiff line change
@@ -263,73 +263,6 @@ describe("options", () => {
263263
});
264264

265265
describe("setupOptions", () => {
266-
const testCases = [
267-
{
268-
name: "no options are provided",
269-
args: [],
270-
data: [
271-
{ useLegacyWorkflow: undefined, expectedHmr: true, expectedBundle: true },
272-
{ useLegacyWorkflow: false, expectedHmr: true, expectedBundle: true },
273-
{ useLegacyWorkflow: true, expectedHmr: true, expectedBundle: true }
274-
]
275-
},
276-
{
277-
name: " --hmr is provided",
278-
args: ["--hmr"],
279-
data: [
280-
{ useLegacyWorkflow: undefined, expectedHmr: true, expectedBundle: true },
281-
{ useLegacyWorkflow: false, expectedHmr: true, expectedBundle: true },
282-
{ useLegacyWorkflow: true, expectedHmr: true, expectedBundle: true }
283-
]
284-
},
285-
{
286-
name: " --no-hmr is provided",
287-
args: ["--no-hmr"],
288-
data: [
289-
{ useLegacyWorkflow: undefined, expectedHmr: false, expectedBundle: true },
290-
{ useLegacyWorkflow: false, expectedHmr: false, expectedBundle: true },
291-
{ useLegacyWorkflow: true, expectedHmr: false, expectedBundle: true }
292-
]
293-
},
294-
{
295-
name: " --bundle is provided",
296-
args: ["--bundle"],
297-
data: [
298-
{ useLegacyWorkflow: undefined, expectedHmr: true, expectedBundle: true },
299-
{ useLegacyWorkflow: false, expectedHmr: true, expectedBundle: true },
300-
{ useLegacyWorkflow: true, expectedHmr: true, expectedBundle: true }
301-
]
302-
},
303-
{
304-
name: " --release is provided",
305-
args: ["--release"],
306-
data: [
307-
{ useLegacyWorkflow: undefined, expectedHmr: false, expectedBundle: true },
308-
{ useLegacyWorkflow: false, expectedHmr: false, expectedBundle: true },
309-
{ useLegacyWorkflow: true, expectedHmr: false, expectedBundle: true }
310-
]
311-
}
312-
];
313-
314-
_.each([undefined, false, true], useLegacyWorkflow => {
315-
_.each(testCases, testCase => {
316-
it(`should pass correctly when ${testCase.name} and useLegacyWorkflow is ${useLegacyWorkflow}`, () => {
317-
(testCase.args || []).forEach(arg => process.argv.push(arg));
318-
319-
const options: any = createOptions(testInjector);
320-
const projectData = <IProjectData>{ useLegacyWorkflow };
321-
options.setupOptions(projectData);
322-
323-
(testCase.args || []).forEach(arg => process.argv.pop());
324-
325-
const data = testCase.data.find(item => item.useLegacyWorkflow === useLegacyWorkflow);
326-
327-
assert.equal(!!options.argv.hmr, !!data.expectedHmr);
328-
assert.equal(!!options.argv.bundle, !!data.expectedBundle);
329-
});
330-
});
331-
});
332-
333266
const testCasesExpectingToThrow = [
334267
{
335268
name: "--release --hmr",

0 commit comments

Comments
 (0)