diff --git a/lib/bootstrap.ts b/lib/bootstrap.ts index c66924ab9f..00cbc57b25 100644 --- a/lib/bootstrap.ts +++ b/lib/bootstrap.ts @@ -144,7 +144,6 @@ $injector.require("devicePathProvider", "./device-path-provider"); $injector.requireCommand("platform|clean", "./commands/platform-clean"); -$injector.require("bundleValidatorHelper", "./helpers/bundle-validator-helper"); $injector.require("androidBundleValidatorHelper", "./helpers/android-bundle-validator-helper"); $injector.require("liveSyncCommandHelper", "./helpers/livesync-command-helper"); $injector.require("deployCommandHelper", "./helpers/deploy-command-helper"); diff --git a/lib/commands/build.ts b/lib/commands/build.ts index c665231967..b7f45f4843 100644 --- a/lib/commands/build.ts +++ b/lib/commands/build.ts @@ -63,7 +63,8 @@ export class BuildIosCommand extends BuildCommandBase implements ICommand { $buildController: IBuildController, $platformValidationService: IPlatformValidationService, $logger: ILogger, - $buildDataService: IBuildDataService) { + $buildDataService: IBuildDataService, + private $migrateController: IMigrateController) { super($options, $errors, $projectData, $platformsDataService, $devicePlatformsConstants, $buildController, $platformValidationService, $buildDataService, $logger); } @@ -72,6 +73,7 @@ export class BuildIosCommand extends BuildCommandBase implements ICommand { } public async canExecute(args: string[]): Promise { + await this.$migrateController.validate({ projectDir: this.$projectData.projectDir }); const platform = this.$devicePlatformsConstants.iOS; super.validatePlatform(platform); @@ -99,7 +101,8 @@ export class BuildAndroidCommand extends BuildCommandBase implements ICommand { $platformValidationService: IPlatformValidationService, protected $androidBundleValidatorHelper: IAndroidBundleValidatorHelper, $buildDataService: IBuildDataService, - protected $logger: ILogger) { + protected $logger: ILogger, + private $migrateController: IMigrateController) { super($options, $errors, $projectData, platformsDataService, $devicePlatformsConstants, $buildController, $platformValidationService, $buildDataService, $logger); } @@ -116,6 +119,7 @@ export class BuildAndroidCommand extends BuildCommandBase implements ICommand { } public async canExecute(args: string[]): Promise { + await this.$migrateController.validate({ projectDir: this.$projectData.projectDir }); const platform = this.$devicePlatformsConstants.Android; this.$androidBundleValidatorHelper.validateRuntimeVersion(this.$projectData); let result = await super.canExecuteCommandBase(platform, { notConfiguredEnvOptions: { hideSyncToPreviewAppOption: true } }); diff --git a/lib/commands/debug.ts b/lib/commands/debug.ts index f606d9b418..16a3753000 100644 --- a/lib/commands/debug.ts +++ b/lib/commands/debug.ts @@ -16,7 +16,8 @@ export class DebugPlatformCommand extends ValidatePlatformCommandBase implements private $debugDataService: IDebugDataService, private $debugController: IDebugController, private $liveSyncCommandHelper: ILiveSyncCommandHelper, - private $androidBundleValidatorHelper: IAndroidBundleValidatorHelper) { + private $androidBundleValidatorHelper: IAndroidBundleValidatorHelper, + private $migrateController: IMigrateController) { super($options, $platformsDataService, $platformValidationService, $projectData); $cleanupService.setShouldDispose(false); } @@ -52,6 +53,8 @@ export class DebugPlatformCommand extends ValidatePlatformCommandBase implements } public async canExecute(args: string[]): Promise { + await this.$migrateController.validate({ projectDir: this.$projectData.projectDir }); + this.$androidBundleValidatorHelper.validateNoAab(); if (!this.$platformValidationService.isPlatformSupportedForOS(this.platform, this.$projectData)) { diff --git a/lib/commands/migrate.ts b/lib/commands/migrate.ts index e9cdf19cac..d8bb4b6a54 100644 --- a/lib/commands/migrate.ts +++ b/lib/commands/migrate.ts @@ -9,11 +9,13 @@ export class MigrateCommand implements ICommand { } public async execute(args: string[]): Promise { - await this.$migrateController.migrate({projectDir: this.$projectData.projectDir}); + await this.$migrateController.migrate({ projectDir: this.$projectData.projectDir }); } public async canExecute(args: string[]): Promise { - if (!await this.$migrateController.shouldMigrate({ projectDir: this.$projectData.projectDir })) { + const shouldMigrateResult = await this.$migrateController.shouldMigrate({ projectDir: this.$projectData.projectDir }); + + if (!shouldMigrateResult) { this.$errors.failWithoutHelp('Project is compatible with NativeScript "v6.0.0". To get the latest NativesScript packages execute "tns update".'); } diff --git a/lib/commands/prepare.ts b/lib/commands/prepare.ts index 71f6e6fdd3..3b8298d599 100644 --- a/lib/commands/prepare.ts +++ b/lib/commands/prepare.ts @@ -16,7 +16,8 @@ export class PrepareCommand extends ValidatePlatformCommandBase implements IComm $projectData: IProjectData, private $platformCommandParameter: ICommandParameter, $platformsDataService: IPlatformsDataService, - private $prepareDataService: PrepareDataService) { + private $prepareDataService: PrepareDataService, + private $migrateController: IMigrateController) { super($options, $platformsDataService, $platformValidationService, $projectData); this.$projectData.initializeProjectData(); } @@ -29,6 +30,7 @@ export class PrepareCommand extends ValidatePlatformCommandBase implements IComm } public async canExecute(args: string[]): Promise { + await this.$migrateController.validate({ projectDir: this.$projectData.projectDir }); const platform = args[0]; const result = await this.$platformCommandParameter.validate(platform) && await this.$platformValidationService.validateOptions(this.$options.provision, this.$options.teamId, this.$projectData, platform); diff --git a/lib/commands/preview.ts b/lib/commands/preview.ts index f891b5fca9..f84de1f516 100644 --- a/lib/commands/preview.ts +++ b/lib/commands/preview.ts @@ -4,9 +4,9 @@ export class PreviewCommand implements ICommand { public allowedParameters: ICommandParameter[] = []; constructor(private $analyticsService: IAnalyticsService, - private $bundleValidatorHelper: IBundleValidatorHelper, private $errors: IErrors, private $logger: ILogger, + private $migrateController: IMigrateController, private $previewAppController: IPreviewAppController, private $networkConnectivityValidator: INetworkConnectivityValidator, private $projectData: IProjectData, @@ -41,8 +41,9 @@ export class PreviewCommand implements ICommand { this.$errors.fail(`The arguments '${args.join(" ")}' are not valid for the preview command.`); } + await this.$migrateController.validate({ projectDir: this.$projectData.projectDir }); + await this.$networkConnectivityValidator.validate(); - this.$bundleValidatorHelper.validate(this.$projectData, "1.0.0"); return true; } } diff --git a/lib/commands/run.ts b/lib/commands/run.ts index e8fcda7cdc..0a308a2f4a 100644 --- a/lib/commands/run.ts +++ b/lib/commands/run.ts @@ -13,6 +13,7 @@ export class RunCommandBase implements ICommand { private $errors: IErrors, private $hostInfo: IHostInfo, private $liveSyncCommandHelper: ILiveSyncCommandHelper, + private $migrateController: IMigrateController, private $projectData: IProjectData ) { } @@ -27,6 +28,8 @@ export class RunCommandBase implements ICommand { this.$errors.fail(ERROR_NO_VALID_SUBCOMMAND_FORMAT, "run"); } + await this.$migrateController.validate({ projectDir: this.$projectData.projectDir }); + this.$androidBundleValidatorHelper.validateNoAab(); this.$projectData.initializeProjectData(); diff --git a/lib/commands/test.ts b/lib/commands/test.ts index 1641227d28..a7459796ed 100644 --- a/lib/commands/test.ts +++ b/lib/commands/test.ts @@ -10,6 +10,7 @@ abstract class TestCommandBase { protected abstract $cleanupService: ICleanupService; protected abstract $liveSyncCommandHelper: ILiveSyncCommandHelper; protected abstract $devicesService: Mobile.IDevicesService; + protected abstract $migrateController: IMigrateController; async execute(args: string[]): Promise { let devices = []; @@ -48,6 +49,8 @@ abstract class TestCommandBase { } async canExecute(args: string[]): Promise { + await this.$migrateController.validate({ projectDir: this.$projectData.projectDir }); + this.$projectData.initializeProjectData(); this.$analyticsService.setShouldDispose(this.$options.justlaunch || !this.$options.watch); this.$cleanupService.setShouldDispose(this.$options.justlaunch || !this.$options.watch); @@ -86,7 +89,8 @@ class TestAndroidCommand extends TestCommandBase implements ICommand { protected $errors: IErrors, protected $cleanupService: ICleanupService, protected $liveSyncCommandHelper: ILiveSyncCommandHelper, - protected $devicesService: Mobile.IDevicesService) { + protected $devicesService: Mobile.IDevicesService, + protected $migrateController: IMigrateController) { super(); } } @@ -102,7 +106,8 @@ class TestIosCommand extends TestCommandBase implements ICommand { protected $errors: IErrors, protected $cleanupService: ICleanupService, protected $liveSyncCommandHelper: ILiveSyncCommandHelper, - protected $devicesService: Mobile.IDevicesService) { + protected $devicesService: Mobile.IDevicesService, + protected $migrateController: IMigrateController) { super(); } diff --git a/lib/controllers/migrate-controller.ts b/lib/controllers/migrate-controller.ts index b5fe07f463..621506ca6f 100644 --- a/lib/controllers/migrate-controller.ts +++ b/lib/controllers/migrate-controller.ts @@ -6,6 +6,13 @@ import { UpdateControllerBase } from "./update-controller-base"; import { fromWindowsRelativePathToUnix } from "../common/helpers"; export class MigrateController extends UpdateControllerBase implements IMigrateController { + // TODO: Update the links to blog post when it is available + private static COMMON_MIGRATE_MESSAGE = "not affect the codebase of the application and you might need to do additional changes manually – for more information, refer to the instructions in the following blog post: ."; + private static UNABLE_TO_MIGRATE_APP_ERROR = `The current application is not compatible with NativeScript CLI 6.0. +Use the \`tns migrate\` command to migrate the app dependencies to a form compatible with NativeScript 6.0. +Running this command will ${MigrateController.COMMON_MIGRATE_MESSAGE}`; + private static MIGRATE_FINISH_MESSAGE = `The \`tns migrate\` command does ${MigrateController.COMMON_MIGRATE_MESSAGE}`; + constructor( protected $fs: IFileSystem, protected $platformCommandHelper: IPlatformCommandHelper, @@ -68,10 +75,17 @@ export class MigrateController extends UpdateControllerBase implements IMigrateC { packageName: "nativescript-cardview", verifiedVersion: "3.2.0" }, { packageName: "nativescript-unit-test-runner", verifiedVersion: "0.6.4", - shouldMigrateAction: (projectData: IProjectData) => this.hasDependency({ packageName: "nativescript-unit-test-runner", isDev: false }, projectData), + shouldMigrateAction: async (projectData: IProjectData) => { + const dependency = { packageName: "nativescript-unit-test-runner", verifiedVersion: "0.6.4", isDev: false }; + const result = this.hasDependency(dependency, projectData) && await this.shouldMigrateDependencyVersion(dependency, projectData); + return result; + }, migrateAction: this.migrateUnitTestRunner.bind(this) }, - { packageName: MigrateController.typescriptPackageName, isDev: true, getVerifiedVersion: this.getAngularTypeScriptVersion.bind(this) } + { packageName: MigrateController.typescriptPackageName, isDev: true, getVerifiedVersion: this.getAngularTypeScriptVersion.bind(this) }, + { packageName: "nativescript-localize", verifiedVersion: "4.2.0" }, + { packageName: "nativescript-dev-babel", verifiedVersion: "0.2.1" }, + { packageName: "nativescript-nfc", verifiedVersion: "4.0.1" } ]; get verifiedPlatformVersions(): IDictionary { @@ -112,6 +126,8 @@ export class MigrateController extends UpdateControllerBase implements IMigrateC this.restoreBackup(MigrateController.folders, backupDir, projectData.projectDir); this.$errors.failWithoutHelp(`${MigrateController.migrateFailMessage} The error is: ${error}`); } + + this.$logger.info(MigrateController.MIGRATE_FINISH_MESSAGE); } public async shouldMigrate({ projectDir }: IProjectDir): Promise { @@ -121,7 +137,7 @@ export class MigrateController extends UpdateControllerBase implements IMigrateC const dependency = this.migrationDependencies[i]; const hasDependency = this.hasDependency(dependency, projectData); - if (hasDependency && dependency.shouldMigrateAction && dependency.shouldMigrateAction(projectData)) { + if (hasDependency && dependency.shouldMigrateAction && await dependency.shouldMigrateAction(projectData)) { return true; } @@ -136,20 +152,27 @@ export class MigrateController extends UpdateControllerBase implements IMigrateC if (!hasDependency && dependency.shouldAddIfMissing) { return true; } + } - if (!this.$androidResourcesMigrationService.hasMigrated(projectData.getAppResourcesDirectoryPath())) { - return true; - } + if (!this.$androidResourcesMigrationService.hasMigrated(projectData.getAppResourcesDirectoryPath())) { + return true; } for (const platform in this.$devicePlatformsConstants) { const hasRuntimeDependency = this.hasRuntimeDependency({ platform, projectData }); - if (!hasRuntimeDependency || await this.shouldUpdateRuntimeVersion({ targetVersion: this.verifiedPlatformVersions[platform.toLowerCase()], platform, projectData })) { + if (hasRuntimeDependency && await this.shouldUpdateRuntimeVersion({ targetVersion: this.verifiedPlatformVersions[platform.toLowerCase()], platform, projectData })) { return true; } } } + public async validate({ projectDir }: IProjectDir): Promise { + const shouldMigrate = await this.shouldMigrate({ projectDir }); + if (shouldMigrate) { + this.$errors.failWithoutHelp(MigrateController.UNABLE_TO_MIGRATE_APP_ERROR); + } + } + private async getAngularTypeScriptVersion(projectData: IProjectData): Promise { let verifiedVersion = "3.4.1"; try { @@ -254,7 +277,7 @@ export class MigrateController extends UpdateControllerBase implements IMigrateC const dependency = this.migrationDependencies[i]; const hasDependency = this.hasDependency(dependency, projectData); - if (hasDependency && dependency.migrateAction && dependency.shouldMigrateAction(projectData)) { + if (hasDependency && dependency.migrateAction && await dependency.shouldMigrateAction(projectData)) { const newDependencies = await dependency.migrateAction(projectData, path.join(projectData.projectDir, MigrateController.backupFolder)); for (const newDependency of newDependencies) { await this.migrateDependency(newDependency, projectData); @@ -267,7 +290,7 @@ export class MigrateController extends UpdateControllerBase implements IMigrateC for (const platform in this.$devicePlatformsConstants) { const lowercasePlatform = platform.toLowerCase(); const hasRuntimeDependency = this.hasRuntimeDependency({ platform, projectData }); - if (!hasRuntimeDependency || await this.shouldUpdateRuntimeVersion({ targetVersion: this.verifiedPlatformVersions[lowercasePlatform], platform, projectData })) { + if (hasRuntimeDependency && await this.shouldUpdateRuntimeVersion({ targetVersion: this.verifiedPlatformVersions[lowercasePlatform], platform, projectData })) { const verifiedPlatformVersion = this.verifiedPlatformVersions[lowercasePlatform]; const platformData = this.$platformsDataService.getPlatformData(lowercasePlatform, projectData); this.$logger.info(`Updating ${platform} platform to version '${verifiedPlatformVersion}'.`); diff --git a/lib/controllers/prepare-controller.ts b/lib/controllers/prepare-controller.ts index c201b2beef..86c871027d 100644 --- a/lib/controllers/prepare-controller.ts +++ b/lib/controllers/prepare-controller.ts @@ -16,7 +16,6 @@ export class PrepareController extends EventEmitter { private persistedData: IFilesChangeEventData[] = []; constructor( - private $bundleValidatorHelper: IBundleValidatorHelper, private $platformController: IPlatformController, public $hooksService: IHooksService, private $logger: ILogger, @@ -55,8 +54,6 @@ export class PrepareController extends EventEmitter { @performanceLog() @hook("prepare") private async prepareCore(prepareData: IPrepareData, projectData: IProjectData): Promise { - this.$bundleValidatorHelper.validate(projectData, "1.0.0"); - await this.$platformController.addPlatformIfNeeded(prepareData); this.$logger.info("Preparing project..."); diff --git a/lib/definitions/migrate.d.ts b/lib/definitions/migrate.d.ts index e7e434693d..2db417be92 100644 --- a/lib/definitions/migrate.d.ts +++ b/lib/definitions/migrate.d.ts @@ -1,6 +1,7 @@ interface IMigrateController { migrate(migrateData: IProjectDir): Promise; shouldMigrate(data: IProjectDir): Promise; + validate(data: IProjectDir): Promise; } interface IDependency { @@ -15,6 +16,6 @@ interface IMigrationDependency extends IDependency { verifiedVersion?: string; getVerifiedVersion?: (projectData: IProjectData) => Promise; shouldAddIfMissing?: boolean; - shouldMigrateAction?: (projectData: IProjectData) => boolean; + shouldMigrateAction?: (projectData: IProjectData) => Promise; migrateAction?: (projectData: IProjectData, migrationBackupDirPath: string) => Promise; } \ No newline at end of file diff --git a/lib/helpers/bundle-validator-helper.ts b/lib/helpers/bundle-validator-helper.ts deleted file mode 100644 index 485424f30a..0000000000 --- a/lib/helpers/bundle-validator-helper.ts +++ /dev/null @@ -1,40 +0,0 @@ -import * as util from "util"; -import { BundleValidatorMessages } from "../constants"; -import { VersionValidatorHelper } from "./version-validator-helper"; -import { WEBPACK_PLUGIN_NAME } from "../constants"; - -export class BundleValidatorHelper extends VersionValidatorHelper implements IBundleValidatorHelper { - private bundlersMap: IStringDictionary = { - webpack: WEBPACK_PLUGIN_NAME - }; - - constructor(protected $errors: IErrors, - protected $options: IOptions) { - super(); - } - - public validate(projectData: IProjectData, minSupportedVersion?: string): void { - const currentVersion = this.getBundlerDependencyVersion(projectData); - if (!currentVersion) { - this.$errors.failWithoutHelp(BundleValidatorMessages.MissingBundlePlugin); - } - - const shouldThrowError = minSupportedVersion && this.isValidVersion(currentVersion) && this.isVersionLowerThan(currentVersion, minSupportedVersion); - if (shouldThrowError) { - this.$errors.failWithoutHelp(util.format(BundleValidatorMessages.NotSupportedVersion, minSupportedVersion)); - } - } - - public getBundlerDependencyVersion(projectData: IProjectData, bundlerName?: string): string { - let dependencyVersion = null; - const bundlePluginName = bundlerName || this.bundlersMap[this.$options.bundle]; - const bundlerVersionInDependencies = projectData.dependencies && projectData.dependencies[bundlePluginName]; - const bundlerVersionInDevDependencies = projectData.devDependencies && projectData.devDependencies[bundlePluginName]; - dependencyVersion = bundlerVersionInDependencies || bundlerVersionInDevDependencies; - - return dependencyVersion; - - } -} - -$injector.register("bundleValidatorHelper", BundleValidatorHelper); diff --git a/test/controllers/prepare-controller.ts b/test/controllers/prepare-controller.ts index 78b4af2d43..ef0b4a0fd0 100644 --- a/test/controllers/prepare-controller.ts +++ b/test/controllers/prepare-controller.ts @@ -54,10 +54,6 @@ function createTestInjector(data: { hasNativeChanges: boolean }): IInjector { isFileInIgnoreList: () => false }); - injector.register("bundleValidatorHelper", { - validate: () => ({}) - }); - const prepareController: PrepareController = injector.resolve("prepareController"); prepareController.emit = (eventName: string, eventData: any) => { emittedEventNames.push(eventName); diff --git a/test/helpers/bundle-validator-helper.ts b/test/helpers/bundle-validator-helper.ts deleted file mode 100644 index 3feee9c4c2..0000000000 --- a/test/helpers/bundle-validator-helper.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { Yok } from "../../lib/common/yok"; -import { BundleValidatorHelper } from "../../lib/helpers/bundle-validator-helper"; -import { assert } from "chai"; -import { format } from "util"; -import { BundleValidatorMessages } from "../../lib/constants"; - -interface ITestCase { - name: string; - isDependency?: boolean; - currentWebpackVersion?: string; - minSupportedWebpackVersion?: string; - expectedError?: string; -} - -let error: string = null; - -function createTestInjector(options: { dependencies?: IStringDictionary, devDependencies?: IStringDictionary }) { - const testInjector = new Yok(); - testInjector.register("projectData", { - initializeProjectData: () => ({}), - dependencies: options.dependencies, - devDependencies: options.devDependencies - }); - testInjector.register("errors", { - fail: (err: string) => error = err, - failWithoutHelp: (err: string) => error = err - }); - testInjector.register("options", ({ bundle: "webpack" })); - testInjector.register("bundleValidatorHelper", BundleValidatorHelper); - - return testInjector; -} - -describe("BundleValidatorHelper", () => { - beforeEach(() => error = null); - - let testCases: ITestCase[] = [ - { - name: "should throw an error when no webpack plugin is installed", - expectedError: BundleValidatorMessages.MissingBundlePlugin - } - ]; - - ["dependencies", "devDependencies"] - .forEach(key => { - const isDependency = key === "dependencies"; - - testCases = testCases.concat([ - { - name: `should not throw an error when webpack is added as ${key}`, - isDependency, - currentWebpackVersion: "0.12.0", - expectedError: null - }, - { - name: `should not throw an error when webpack's version is greater than minSupportedVersion when webpack is installed as ${key}`, - isDependency, - currentWebpackVersion: "0.13.1", - minSupportedWebpackVersion: "0.13.0", - expectedError: null - }, - { - name: `should not throw an error when webpack's version is equal to minSupportedVersion when webpack is installed as ${key}`, - isDependency, - currentWebpackVersion: "0.10.0", - minSupportedWebpackVersion: "0.10.0", - expectedError: null - }, - { - name: `should throw an error when webpack's version is lower than minSupportedVersion when webpack is installed as ${key}`, - isDependency, - currentWebpackVersion: "0.17.0", - minSupportedWebpackVersion: "0.18.0", - expectedError: format(BundleValidatorMessages.NotSupportedVersion, "0.18.0") - }, - { - name: `should not throw an error when prerelease version of webpack is installed as ${key}`, - isDependency, - currentWebpackVersion: "0.17.0-2018-09-28-173604-01", - minSupportedWebpackVersion: "0.17.0", - expectedError: null - }, - { - name: `should not throw an error when next version of webpack is installed as ${key}`, - isDependency, - currentWebpackVersion: "next", - minSupportedWebpackVersion: "0.17.0", - expectedError: null - } - ]); - }); - - _.each(testCases, (testCase: any) => { - const deps = { - "nativescript-dev-webpack": testCase.currentWebpackVersion - }; - - it(`${testCase.name}`, async () => { - const injector = createTestInjector({ dependencies: testCase.isDependency ? deps : null, devDependencies: !testCase.isDependency ? deps : null }); - const bundleValidatorHelper = injector.resolve("bundleValidatorHelper"); - const projectData = injector.resolve("projectData"); - bundleValidatorHelper.validate(projectData, testCase.minSupportedWebpackVersion); - - assert.deepEqual(error, testCase.expectedError); - }); - }); -});