Skip to content

fix: tns update command should work with npm tags #5213

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 13, 2020
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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
62 changes: 59 additions & 3 deletions lib/controllers/update-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ import { UpdateControllerBase } from "./update-controller-base";
interface IPackage {
name: string;
alias?: string;
isDev?: boolean;
}

export class UpdateController extends UpdateControllerBase implements IUpdateController {
static readonly updatableDependencies: IPackage[] = [
{ 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,
Expand Down Expand Up @@ -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<boolean> {
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);
Expand Down Expand Up @@ -103,7 +109,14 @@ export class UpdateController extends UpdateControllerBase implements IUpdateCon
}

private async updateProject(projectData: IProjectData, version: string): Promise<void> {
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);

Expand All @@ -127,6 +140,49 @@ export class UpdateController extends UpdateControllerBase implements IUpdateCon
});
}

private async constructTemplateManifestForTag(tag: string): Promise<any> {
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<string> {
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<string>, areDev: boolean, projectData: IProjectData }) {
for (const dependency in dependencies) {
const templateVersion = dependencies[dependency];
Expand Down