diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c5bfccb76..72ae976862 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,11 +7,12 @@ NativeScript CLI Changelog ### New * [Implemented #5205](https://github.com/NativeScript/nativescript-cli/issues/5205): Support build hooks -* [Implemented #5210](https://github.com/NativeScript/nativescript-cli/issues/5210): Support environment check hooks +* [Implemented #5210](https://github.com/NativeScript/nativescript-cli/issues/5210): Support environment check hooks ### Fixed * [Fixed #3818](https://github.com/NativeScript/nativescript-cli/issues/3818): Cannot set property 'socket' of null +* [Fixed #5072](https://github.com/NativeScript/nativescript-cli/issues/5072):`tns update next` doesn't work with CLI 6+ 6.3.2 (2020, January 9) diff --git a/lib/controllers/update-controller.ts b/lib/controllers/update-controller.ts index f1d1f7d527..26789f581e 100644 --- a/lib/controllers/update-controller.ts +++ b/lib/controllers/update-controller.ts @@ -6,6 +6,7 @@ import { UpdateControllerBase } from "./update-controller-base"; interface IPackage { name: string; alias?: string; + isDev?: boolean; } export class UpdateController extends UpdateControllerBase implements IUpdateController { @@ -13,7 +14,7 @@ export class UpdateController extends UpdateControllerBase implements IUpdateCon { name: constants.SCOPED_TNS_CORE_MODULES, alias: constants.TNS_CORE_MODULES_NAME }, { name: constants.TNS_CORE_MODULES_NAME }, { name: constants.TNS_CORE_MODULES_WIDGETS_NAME }, - { name: constants.WEBPACK_PLUGIN_NAME }]; + { name: constants.WEBPACK_PLUGIN_NAME, isDev: true }]; static readonly folders: string[] = [ constants.LIB_DIR_NAME, constants.HOOKS_DIR_NAME, @@ -60,11 +61,16 @@ export class UpdateController extends UpdateControllerBase implements IUpdateCon await this.updateProject(projectData, updateOptions.version); } catch (error) { this.restoreBackup(UpdateController.folders, backupDir, projectData.projectDir); - this.$logger.error(UpdateController.updateFailMessage); + this.$logger.error(`${UpdateController.updateFailMessage} Reason is: ${error.message}`); } } public async shouldUpdate({ projectDir, version }: { projectDir: string, version?: string }): Promise { + if (version && !semver.valid(version) && !semver.validRange(version)) { + // probably npm tag here + return true; + } + const projectData = this.$projectDataService.getProjectData(projectDir); const templateManifest = await this.getTemplateManifest(projectData, version); const dependencies = this.getUpdatableDependencies(templateManifest.dependencies); @@ -103,7 +109,14 @@ export class UpdateController extends UpdateControllerBase implements IUpdateCon } private async updateProject(projectData: IProjectData, version: string): Promise { - const templateManifest = await this.getTemplateManifest(projectData, version); + let templateManifest: any = {}; + + if (!version || semver.valid(version) || semver.validRange(version)) { + templateManifest = await this.getTemplateManifest(projectData, version); + } else { + templateManifest = await this.constructTemplateManifestForTag(version); + } + const dependencies = this.getUpdatableDependencies(templateManifest.dependencies); const devDependencies = this.getUpdatableDependencies(templateManifest.devDependencies); @@ -127,6 +140,49 @@ export class UpdateController extends UpdateControllerBase implements IUpdateCon }); } + private async constructTemplateManifestForTag(tag: string): Promise { + this.$logger.trace(`Will construct manually template manifest for tag ${tag}`); + + const templateManifest: any = {}; + templateManifest.dependencies = {}; + templateManifest.devDependencies = {}; + for (const updatableDependency of UpdateController.updatableDependencies) { + const version = await this.getVersionFromTag(updatableDependency.name, tag); + if (!version) { + this.$errors.fail(`Unable to execute update as package '${updatableDependency.name}' does not have version or tag '${tag}'`); + } + + const dictionaryToModify = updatableDependency.isDev ? templateManifest.devDependencies : templateManifest.dependencies; + dictionaryToModify[updatableDependency.name] = version; + if (updatableDependency.alias) { + const aliasVersion = await this.getVersionFromTag(updatableDependency.name, tag); + dictionaryToModify[updatableDependency.alias] = aliasVersion; + } + } + + templateManifest.nativescript = { + [constants.TNS_ANDROID_RUNTIME_NAME]: { + version: await this.getVersionFromTag(constants.TNS_ANDROID_RUNTIME_NAME, tag) + }, + [constants.TNS_IOS_RUNTIME_NAME]: { + version: await this.$packageManager.getTagVersion(constants.TNS_IOS_RUNTIME_NAME, tag) + } + }; + + this.$logger.trace(`Manually constructed template manifest for tag ${tag}. Content is: ${JSON.stringify(templateManifest, null, 2)}`); + + return templateManifest; + } + + private async getVersionFromTag(packageName: string, tag: string): Promise { + const version = await this.$packageManager.getTagVersion(packageName, tag); + if (!version) { + this.$errors.fail(`Unable to execute update as package ${packageName} does not have version/tag ${tag}. Please enter valid version or npm tag.`); + } + + return version; + } + private async updateDependencies({ dependencies, areDev, projectData }: { dependencies: IDictionary, areDev: boolean, projectData: IProjectData }) { for (const dependency in dependencies) { const templateVersion = dependencies[dependency];