From 4e4fb5057433c2a2a04b9685aa28ca5db2a98c8b Mon Sep 17 00:00:00 2001 From: fatme Date: Wed, 21 Mar 2018 09:17:28 +0200 Subject: [PATCH 01/32] Do not create empty .entitlements file Fixes https://github.com/NativeScript/nativescript-cli/issues/3481 --- lib/services/ios-entitlements-service.ts | 9 +++++---- lib/services/ios-project-service.ts | 2 +- test/ios-entitlements-service.ts | 10 ++-------- test/ios-project-service.ts | 10 ++++++++++ 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/lib/services/ios-entitlements-service.ts b/lib/services/ios-entitlements-service.ts index 71d2cde947..29012eb9b1 100644 --- a/lib/services/ios-entitlements-service.ts +++ b/lib/services/ios-entitlements-service.ts @@ -56,10 +56,11 @@ export class IOSEntitlementsService { makePatch(appEntitlementsPath); } - const plistContent = session.build(); - this.$logger.trace("App.entitlements: Write to: " + this.getPlatformsEntitlementsPath(projectData)); - this.$fs.writeFile(this.getPlatformsEntitlementsPath(projectData), plistContent); - return; + if ((session).patches && (session).patches.length > 0) { + const plistContent = session.build(); + this.$logger.trace("App.entitlements: Write to: " + this.getPlatformsEntitlementsPath(projectData)); + this.$fs.writeFile(this.getPlatformsEntitlementsPath(projectData), plistContent); + } } private getAllInstalledPlugins(projectData: IProjectData): Promise { diff --git a/lib/services/ios-project-service.ts b/lib/services/ios-project-service.ts index 365aa08448..b82849f808 100644 --- a/lib/services/ios-project-service.ts +++ b/lib/services/ios-project-service.ts @@ -1241,7 +1241,7 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f // Set Entitlements Property to point to default file if not set explicitly by the user. const entitlementsPropertyValue = this.$xCConfigService.readPropertyValue(pluginsXcconfigFilePath, constants.CODE_SIGN_ENTITLEMENTS); - if (entitlementsPropertyValue === null) { + if (entitlementsPropertyValue === null && this.$fs.exists(this.$iOSEntitlementsService.getPlatformsEntitlementsPath(projectData))) { temp.track(); const tempEntitlementsDir = temp.mkdirSync("entitlements"); const tempEntitlementsFilePath = path.join(tempEntitlementsDir, "set-entitlements.xcconfig"); diff --git a/test/ios-entitlements-service.ts b/test/ios-entitlements-service.ts index 9d9f3fc6bf..18546ec311 100644 --- a/test/ios-entitlements-service.ts +++ b/test/ios-entitlements-service.ts @@ -76,11 +76,6 @@ describe("IOSEntitlements Service Tests", () => { }); describe("Merge", () => { - const defaultPlistContent = ` - - - -`; const defaultAppResourcesEntitlementsContent = ` @@ -123,13 +118,12 @@ describe("IOSEntitlements Service Tests", () => { assert.equal(strip(actual), strip(expected)); } - it("Merge creates a default entitlements file.", async () => { + it("Merge does not create a default entitlements file.", async () => { // act await iOSEntitlementsService.merge(projectData); // assert - const actual = fs.readText(destinationFilePath); - assertContent(actual, defaultPlistContent); + assert.isFalse(fs.exists(destinationFilePath)); }); it("Merge uses the entitlements from App_Resources folder", async () => { diff --git a/test/ios-project-service.ts b/test/ios-project-service.ts index 8e9a09626c..9babc1d5d4 100644 --- a/test/ios-project-service.ts +++ b/test/ios-project-service.ts @@ -839,6 +839,16 @@ describe("Merge Project XCConfig files", () => { it("Adds the entitlements property if not set by the user", async () => { for (const release in [true, false]) { + const realExistsFunction = testInjector.resolve("fs").exists; + + testInjector.resolve("fs").exists = (filePath: string) => { + if (iOSEntitlementsService.getPlatformsEntitlementsPath(projectData) === filePath) { + return true; + } + + return realExistsFunction(filePath); + }; + await (iOSProjectService).mergeProjectXcconfigFiles(release, projectData); const destinationFilePath = release ? (iOSProjectService).getPluginsReleaseXcconfigFilePath(projectData) From cbf2ca0c856cede615824c9371346477c07781bc Mon Sep 17 00:00:00 2001 From: fatme Date: Fri, 23 Mar 2018 08:46:32 +0200 Subject: [PATCH 02/32] Print warning when more than one package is produced from build In case when productFlavors or split option is used in .gradle file more than on .apk files are produced. Print warning that will be used the last one produced from build. --- lib/services/platform-service.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/services/platform-service.ts b/lib/services/platform-service.ts index 94cf094632..c6e5e2413c 100644 --- a/lib/services/platform-service.ts +++ b/lib/services/platform-service.ts @@ -788,9 +788,13 @@ export class PlatformService extends EventEmitter implements IPlatformService { private getLatestApplicationPackage(buildOutputPath: string, validBuildOutputData: IValidBuildOutputData): IApplicationPackage { let packages = this.getApplicationPackages(buildOutputPath, validBuildOutputData); + const packageExtName = path.extname(validBuildOutputData.packageNames[0]); if (packages.length === 0) { - const packageExtName = path.extname(validBuildOutputData.packageNames[0]); - this.$errors.fail("No %s found in %s directory", packageExtName, buildOutputPath); + this.$errors.fail(`No ${packageExtName} found in ${buildOutputPath} directory.`); + } + + if (packages.length > 1) { + this.$logger.warn(`More than one ${packageExtName} found in ${buildOutputPath} directory. Using the last one produced from build.`) } packages = _.sortBy(packages, pkg => pkg.time).reverse(); // We need to reverse because sortBy always sorts in ascending order From 66f5a34a11ceaa908e5249a1011ce86a1b04c715 Mon Sep 17 00:00:00 2001 From: Fatme Date: Fri, 23 Mar 2018 09:57:15 +0200 Subject: [PATCH 03/32] Fix lint error --- lib/services/platform-service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/services/platform-service.ts b/lib/services/platform-service.ts index c6e5e2413c..fa61489d05 100644 --- a/lib/services/platform-service.ts +++ b/lib/services/platform-service.ts @@ -794,7 +794,7 @@ export class PlatformService extends EventEmitter implements IPlatformService { } if (packages.length > 1) { - this.$logger.warn(`More than one ${packageExtName} found in ${buildOutputPath} directory. Using the last one produced from build.`) + this.$logger.warn(`More than one ${packageExtName} found in ${buildOutputPath} directory. Using the last one produced from build.`); } packages = _.sortBy(packages, pkg => pkg.time).reverse(); // We need to reverse because sortBy always sorts in ascending order From 4ae2bae079c7c7cd31c5591c4ab89caf272e206b Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Mon, 26 Mar 2018 11:38:10 +0300 Subject: [PATCH 04/32] chore: Update CHANGELOG for 4.0.0rc Update CHANGELOG for 4.0.0rc --- CHANGELOG.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e66fde4878..7f5c42f875 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,25 @@ NativeScript CLI Changelog ================ +4.0.0rc (2018, March 23) +== + +### New +* [Implemented #3243](https://github.com/NativeScript/nativescript-cli/issues/3243) 'Scss' file changes trigger app refresh instead reloading the view and apply generated 'css' +* [Implemented #3248](https://github.com/NativeScript/nativescript-cli/issues/3248) Support JDK_HOME and JAVA_HOME +* [Implemented #3257](https://github.com/NativeScript/nativescript-cli/issues/3257) Make {N} project structure configurable +* [Implemented #3317](https://github.com/NativeScript/nativescript-cli/issues/3317) Support livesync with webpack +* [Implemented #3449](https://github.com/NativeScript/nativescript-cli/pull/3449) Track Vue.js project type +* [Implemented #3496](https://github.com/NativeScript/nativescript-cli/issues/3496) Generate assets for the mobile application +* [Implemented #3497](https://github.com/NativeScript/nativescript-cli/issues/3497) Command to migrate Android resources to 4.0.0 structure + +### Fixed +* [Fixed #3151](https://github.com/NativeScript/nativescript-cli/issues/3151): Install fails if user setting file is not valid json +* [Fixed #3324](https://github.com/NativeScript/nativescript-cli/issues/3324): Error when iOS simulator's window is closed +* [Fixed #3442](https://github.com/NativeScript/nativescript-cli/issues/3442): Unnecessary second build upon `tns run android` +* [Fixed #3451](https://github.com/NativeScript/nativescript-cli/issues/3451): `tns plugin remove` fails with : Cannot convert undefined or null to object + + 3.4.3 (2018, March 02) == From 21cac172a4b2d86d1c90c4832595fb2a1e8f8477 Mon Sep 17 00:00:00 2001 From: fatme Date: Fri, 23 Mar 2018 12:46:40 +0200 Subject: [PATCH 05/32] Fix (publish): Remove binary-plist and use simple-plist instead In case when produced Info.plist is not a binary file, `tns publish ios` command fails because `bplist-parser` is not able to parse non-binary plist files. This PR replaces `bplist-parser` module with `sample-plist` that is able to parse binary and non-binary files. Fixes https://github.com/NativeScript/nativescript-cli/issues/3470 --- lib/common | 2 +- lib/definitions/simple-plist.d.ts | 4 ---- lib/services/ios-project-service.ts | 4 ++-- lib/services/itmstransporter-service.ts | 6 +++--- npm-shrinkwrap.json | 5 ----- package.json | 1 - test/ios-project-service.ts | 1 + 7 files changed, 7 insertions(+), 16 deletions(-) delete mode 100644 lib/definitions/simple-plist.d.ts diff --git a/lib/common b/lib/common index c222ae02ed..2b4ee454a1 160000 --- a/lib/common +++ b/lib/common @@ -1 +1 @@ -Subproject commit c222ae02edb122f40501bb3f17d18ca5aff7791d +Subproject commit 2b4ee454a17575d3a1bb028fa8df42d78677b823 diff --git a/lib/definitions/simple-plist.d.ts b/lib/definitions/simple-plist.d.ts deleted file mode 100644 index adc559fc81..0000000000 --- a/lib/definitions/simple-plist.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -declare module "simple-plist" { - export function readFile(filePath: string, callback?:(err: Error, obj: any) => void): void; - export function readFileSync(filePath: string): any; -} diff --git a/lib/services/ios-project-service.ts b/lib/services/ios-project-service.ts index 365aa08448..a6055c3661 100644 --- a/lib/services/ios-project-service.ts +++ b/lib/services/ios-project-service.ts @@ -13,7 +13,6 @@ import * as plist from "plist"; import { IOSProvisionService } from "./ios-provision-service"; import { IOSEntitlementsService } from "./ios-entitlements-service"; import { XCConfigService } from "./xcconfig-service"; -import * as simplePlist from "simple-plist"; import * as mobileprovision from "ios-mobileprovision-finder"; import { SpawnOptions } from "child_process"; import { BUILD_XCCONFIG_FILE_NAME } from "../constants"; @@ -51,6 +50,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ private $xcode: IXcode, private $iOSEntitlementsService: IOSEntitlementsService, private $platformEnvironmentRequirements: IPlatformEnvironmentRequirements, + private $plistParser: IPlistParser, private $sysInfo: ISysInfo, private $xCConfigService: XCConfigService) { super($fs, $projectDataService); @@ -1045,7 +1045,7 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f this.$errors.failWithoutHelp("The bundle at %s does not contain an Info.plist file.", libraryPath); } - const plistJson = simplePlist.readFileSync(infoPlistPath); + const plistJson = this.$plistParser.parseFileSync(infoPlistPath); const packageType = plistJson["CFBundlePackageType"]; if (packageType !== "FMWK") { diff --git a/lib/services/itmstransporter-service.ts b/lib/services/itmstransporter-service.ts index e60b23da2c..474aea69c0 100644 --- a/lib/services/itmstransporter-service.ts +++ b/lib/services/itmstransporter-service.ts @@ -10,7 +10,7 @@ export class ITMSTransporterService implements IITMSTransporterService { private _itunesConnectApplications: IiTunesConnectApplication[] = null; private _bundleIdentifier: string = null; - constructor(private $bplistParser: IBinaryPlistParser, + constructor(private $plistParser: IPlistParser, private $childProcess: IChildProcess, private $errors: IErrors, private $fs: IFileSystem, @@ -135,8 +135,8 @@ export class ITMSTransporterService implements IITMSTransporterService { } const appFile = path.join(payloadDir, allApps[0]); - const plistObject = await this.$bplistParser.parseFile(path.join(appFile, INFO_PLIST_FILE_NAME)); - const bundleId = plistObject && plistObject[0] && plistObject[0].CFBundleIdentifier; + const plistObject = await this.$plistParser.parseFile(path.join(appFile, INFO_PLIST_FILE_NAME)); + const bundleId = plistObject && plistObject.CFBundleIdentifier; if (!bundleId) { this.$errors.failWithoutHelp(`Unable to determine bundle identifier from ${ipaFileFullPath}.`); } diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index df0cdd4eed..b6af7f5bca 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -434,11 +434,6 @@ "stream-buffers": "2.2.0" } }, - "bplist-parser": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.1.0.tgz", - "integrity": "sha1-Ywgj8gVkN9Tb78IOhAF/i6xI4Ag=" - }, "brace-expansion": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", diff --git a/package.json b/package.json index 28e0b4d7b2..e12acda886 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,6 @@ ], "dependencies": { "@types/ora": "1.3.2", - "bplist-parser": "0.1.0", "bufferpack": "0.0.6", "byline": "4.2.1", "chalk": "1.1.0", diff --git a/test/ios-project-service.ts b/test/ios-project-service.ts index 8e9a09626c..e860bab8cc 100644 --- a/test/ios-project-service.ts +++ b/test/ios-project-service.ts @@ -120,6 +120,7 @@ function createTestInjector(projectPath: string, projectName: string): IInjector testInjector.register("settingsService", SettingsService); testInjector.register("httpClient", {}); testInjector.register("platformEnvironmentRequirements", {}); + testInjector.register("plistParser", {}); return testInjector; } From aa4cf8076dca478584ba9dee16fcdde300d667fc Mon Sep 17 00:00:00 2001 From: Fatme Date: Mon, 26 Mar 2018 22:58:53 +0300 Subject: [PATCH 06/32] fix: Move @types/ora as devDependency Ora's definition files are not needed in production package, so move it as devDependency. --- npm-shrinkwrap.json | 10 ++++++---- package.json | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index b6af7f5bca..126425193d 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -70,12 +70,14 @@ "@types/node": { "version": "6.0.61", "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.61.tgz", - "integrity": "sha1-7qF0itmd7K8xm1cQFwGGMZdKxvA=" + "integrity": "sha1-7qF0itmd7K8xm1cQFwGGMZdKxvA=", + "dev": true }, "@types/ora": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/ora/-/ora-1.3.2.tgz", - "integrity": "sha512-YZjIN90YKxkQjmDZHr1CQP1Z20qUU3TLC10k+SnDqoRv0CNUxREwaaDc3aCRNcOfjCjktdoP2Z8Cxqf4wHjO2w==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@types/ora/-/ora-1.3.3.tgz", + "integrity": "sha512-XaSVRyCfnGq1xGlb6iuoxnomMXPIlZnvIIkKiGNMTCeVOg7G1Si+FA9N1lPrykPEfiRHwbuZXuTCSoYcHyjcdg==", + "dev": true, "requires": { "@types/node": "6.0.61" } diff --git a/package.json b/package.json index e12acda886..0ab413bc2c 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,6 @@ "mobile" ], "dependencies": { - "@types/ora": "1.3.2", "bufferpack": "0.0.6", "byline": "4.2.1", "chalk": "1.1.0", @@ -94,6 +93,7 @@ "@types/color": "3.0.0", "@types/lockfile": "1.0.0", "@types/node": "6.0.61", + "@types/ora": "1.3.3", "@types/qr-image": "3.2.0", "@types/request": "0.0.45", "@types/semver": "^5.3.31", From f9ef10be0ac9487dfa0ecf69c743723948e19e22 Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Tue, 27 Mar 2018 01:12:06 +0300 Subject: [PATCH 07/32] feat(commands) Introduce postCommandAction Introduce postCommandAction that is executed when the command succeeds. Use the action to print additional information to user how to continue after command is finished. Show some information on successful postinstall - instruct the users how to use local builds, cloud builds and playground. --- lib/commands/create-project.ts | 13 ++++++++++++- lib/commands/post-install.ts | 21 +++++++++++++++++++++ lib/common | 2 +- lib/definitions/project.d.ts | 13 ++++++++++--- lib/services/project-service.ts | 3 ++- test/project-commands.ts | 3 ++- test/project-service.ts | 2 +- 7 files changed, 49 insertions(+), 8 deletions(-) diff --git a/lib/commands/create-project.ts b/lib/commands/create-project.ts index 802f829f44..bc024dc6f5 100644 --- a/lib/commands/create-project.ts +++ b/lib/commands/create-project.ts @@ -1,10 +1,14 @@ import * as constants from "../constants"; +import * as path from "path"; export class CreateProjectCommand implements ICommand { public enableHooks = false; public allowedParameters: ICommandParameter[] = [this.$stringParameterBuilder.createMandatoryParameter("Project name cannot be empty.")]; + private createdProjecData: ICreateProjectData; + constructor(private $projectService: IProjectService, + private $logger: ILogger, private $errors: IErrors, private $options: IOptions, private $stringParameterBuilder: IStringParameterBuilder) { } @@ -23,7 +27,7 @@ export class CreateProjectCommand implements ICommand { selectedTemplate = this.$options.template; } - await this.$projectService.createProject({ + this.createdProjecData = await this.$projectService.createProject({ projectName: args[0], template: selectedTemplate, appId: this.$options.appid, @@ -32,6 +36,13 @@ export class CreateProjectCommand implements ICommand { ignoreScripts: this.$options.ignoreScripts }); } + + public async postCommandAction(args: string[]): Promise { + const { projectDir } = this.createdProjecData; + const relativePath = path.relative(process.cwd(), projectDir); + this.$logger.printMarkdown(`Now you can navigate to your project with \`$ cd ${relativePath}\``); + this.$logger.printMarkdown(`After that you can run it on device/emulator by executing \`$ tns run \``); + } } $injector.registerCommand("create", CreateProjectCommand); diff --git a/lib/commands/post-install.ts b/lib/commands/post-install.ts index 80db0dfc9b..75c600e6a5 100644 --- a/lib/commands/post-install.ts +++ b/lib/commands/post-install.ts @@ -18,6 +18,27 @@ export class PostInstallCliCommand extends PostInstallCommand { await this.$subscriptionService.subscribeForNewsletter(); } + + public async postCommandAction(args: string[]): Promise { + this.$logger.info("You have successfully installed NativeScript CLI."); + this.$logger.info("In order to create a new project, you can use:".green); + this.$logger.printMarkdown("`tns create `"); + this.$logger.info("To build your project locally you can use:".green); + this.$logger.printMarkdown("`tns build `"); + this.$logger.printMarkdown("NOTE: Local builds require additional setup of your environment. You can find more information here: `https://docs.nativescript.org/start/quick-setup`"); + + // Add a new line just to ensure separation between local builds and cloud builds info. + this.$logger.info(""); + this.$logger.info("To build your project in the cloud you can use:".green); + this.$logger.printMarkdown("`tns cloud build `"); + this.$logger.printMarkdown("NOTE: Cloud builds require Telerik account. You can find more information here: `https://docs.nativescript.org/sidekick/intro/requirements`"); + + this.$logger.info(""); + this.$logger.printMarkdown("In case you want to experiment quickly with NativeScript, you can try the Playground: `https://play.nativescript.org`"); + + this.$logger.info(""); + this.$logger.printMarkdown("In case you have any questions, you can check our forum: `https://forum.nativescript.org` and our public Slack channel: `https://nativescriptcommunity.slack.com/`"); + } } $injector.registerCommand("post-install-cli", PostInstallCliCommand); diff --git a/lib/common b/lib/common index 2b4ee454a1..d5b8319094 160000 --- a/lib/common +++ b/lib/common @@ -1 +1 @@ -Subproject commit 2b4ee454a17575d3a1bb028fa8df42d78677b823 +Subproject commit d5b83190946bae0cbb2aae5d90d89128aeb63d15 diff --git a/lib/definitions/project.d.ts b/lib/definitions/project.d.ts index 01132e0d95..2e99a72bfd 100644 --- a/lib/definitions/project.d.ts +++ b/lib/definitions/project.d.ts @@ -37,13 +37,21 @@ interface IProjectSettings { ignoreScripts?: boolean; } +interface IProjectName { + projectName: string; +} + +interface ICreateProjectData extends IProjectDir, IProjectName { + +} + interface IProjectService { /** * Creates new NativeScript application. * @param {any} projectSettings Options describing new project - its name, appId, path and template from which to be created. * @returns {Promise} */ - createProject(projectSettings: IProjectSettings): Promise; + createProject(projectSettings: IProjectSettings): Promise; /** * Checks if the specified project is valid NativeScript project. @@ -58,8 +66,7 @@ interface INsConfig { appResourcesPath?: string; } -interface IProjectData extends IProjectDir { - projectName: string; +interface IProjectData extends ICreateProjectData { platformsDir: string; projectFilePath: string; projectId?: string; diff --git a/lib/services/project-service.ts b/lib/services/project-service.ts index ecabbc9b5e..2a92ea0a0c 100644 --- a/lib/services/project-service.ts +++ b/lib/services/project-service.ts @@ -18,7 +18,7 @@ export class ProjectService implements IProjectService { private $npmInstallationManager: INpmInstallationManager) { } @exported("projectService") - public async createProject(projectOptions: IProjectSettings): Promise { + public async createProject(projectOptions: IProjectSettings): Promise { let projectName = projectOptions.projectName; let selectedTemplate = projectOptions.template; @@ -74,6 +74,7 @@ export class ProjectService implements IProjectService { } this.$logger.printMarkdown("Project `%s` was successfully created.", projectName); + return { projectName, projectDir }; } @exported("projectService") diff --git a/test/project-commands.ts b/test/project-commands.ts index d5ddccaa41..20722bceb8 100644 --- a/test/project-commands.ts +++ b/test/project-commands.ts @@ -10,9 +10,10 @@ let isProjectCreated: boolean; const dummyArgs = ["dummyArgsString"]; class ProjectServiceMock implements IProjectService { - async createProject(projectOptions: IProjectSettings): Promise { + async createProject(projectOptions: IProjectSettings): Promise { selectedTemplateName = projectOptions.template; isProjectCreated = true; + return null; } isValidNativeScriptProject(pathToProject?: string): boolean { diff --git a/test/project-service.ts b/test/project-service.ts index 027598df2d..3b54318e80 100644 --- a/test/project-service.ts +++ b/test/project-service.ts @@ -59,7 +59,7 @@ class ProjectIntegrationTest { this.createTestInjector(); } - public async createProject(projectOptions: IProjectSettings): Promise { + public async createProject(projectOptions: IProjectSettings): Promise { const projectService: IProjectService = this.testInjector.resolve("projectService"); if (!projectOptions.template) { projectOptions.template = constants.RESERVED_TEMPLATE_NAMES["default"]; From 88dde98ea0730c52ec769f460588b4fe56754638 Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Wed, 28 Mar 2018 16:15:17 +0300 Subject: [PATCH 08/32] docs: Fix the help of `tns generate splashes` command Fix the help of `tns generate splashes` command as the content for `--background` option is incorrect. --- .../resources/resources-generate-splashes.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/man_pages/project/configuration/resources/resources-generate-splashes.md b/docs/man_pages/project/configuration/resources/resources-generate-splashes.md index 5db76757dc..02655d7020 100644 --- a/docs/man_pages/project/configuration/resources/resources-generate-splashes.md +++ b/docs/man_pages/project/configuration/resources/resources-generate-splashes.md @@ -6,13 +6,16 @@ position: 12 Usage | Synopsis ------|------- -`$ tns resources generate splashes []` | Generate all splashscreens for Android and iOS based on the specified image. +`$ tns resources generate splashes [--background ]` | Generate all splashscreens for Android and iOS based on the specified image. -Generates all icons for Android and iOS platforms and places the generated images in the correct directories under `App_Resources/` directory. +Generates all splashscreens for Android and iOS platforms and places the generated images in the correct directories under `App_Resources/` directory. + +### Options +* `--background` Sets the background color of the splashscreen. Defaults to white in case it is not specified. ### Attributes * `` is a valid path to an image that will be used to generate all splashscreens. -* `` is a valid path to an image that will be used as a background of the splashscreen. Defaults to white in case it is not specified. +* `` is a valid color. It can be represented with string, like `white`, `black`, `blue`, etc. or its HEX representation, for example `#FFFFFF`, `#000000`, `#0000FF`. NOTE: As the `#` is special symbol in some terminals, make sure to place the value in quotes, for example `$ tns resources generate splashes ../myImage.png --background "#FF00FF"`. <% if(isHtml) { %> ### Related Commands From 791ac7efa5828eef2614b10257e4361bebe0c3ce Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Wed, 28 Mar 2018 22:38:11 +0300 Subject: [PATCH 09/32] fix(deps): Remove bufferpack Remove bufferpack dependency, as it is no longer user in CLI's code directly. --- lib/common | 2 +- package.json | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/common b/lib/common index d5b8319094..dd221de96a 160000 --- a/lib/common +++ b/lib/common @@ -1 +1 @@ -Subproject commit d5b83190946bae0cbb2aae5d90d89128aeb63d15 +Subproject commit dd221de96a7b42f4043bb211b4bfda5bda6ae5be diff --git a/package.json b/package.json index 0ab413bc2c..77dd16c1ac 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,6 @@ "mobile" ], "dependencies": { - "bufferpack": "0.0.6", "byline": "4.2.1", "chalk": "1.1.0", "chokidar": "1.7.0", From f141d0d58d39bb75ecd21058252c0782efb25581 Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Wed, 28 Mar 2018 22:50:57 +0300 Subject: [PATCH 10/32] fix(deps): Remove glob Remove bufferpack glob, as it is no longer user in CLI's code directly. --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 77dd16c1ac..7630240157 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,6 @@ "esprima": "2.7.0", "filesize": "3.1.2", "gaze": "1.1.0", - "glob": "^7.0.3", "iconv-lite": "0.4.11", "inquirer": "0.9.0", "ios-device-lib": "0.4.10", From 0d7b2194c09dae0dc8e0e730238fcd3bfdcde680 Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Wed, 28 Mar 2018 23:22:53 +0300 Subject: [PATCH 11/32] fix(deps): Remove properties-parser The properties-parser has been used years ago, to parse `.properties` files. We have not used this code since August 2015, so just remove the support for it. We have used it in AndroidProjectPropertiesManager, but this code is not used since the mentioned date, so remove it as well. --- lib/common | 2 +- lib/definitions/project.d.ts | 6 - .../android-project-properties-manager.ts | 101 ------------ lib/services/android-project-service.ts | 2 - npm-shrinkwrap.json | 5 - package.json | 1 - test/android-project-properties-manager.ts | 145 ------------------ 7 files changed, 1 insertion(+), 261 deletions(-) delete mode 100644 lib/services/android-project-properties-manager.ts delete mode 100644 test/android-project-properties-manager.ts diff --git a/lib/common b/lib/common index dd221de96a..883a0d2faf 160000 --- a/lib/common +++ b/lib/common @@ -1 +1 @@ -Subproject commit dd221de96a7b42f4043bb211b4bfda5bda6ae5be +Subproject commit 883a0d2faf2eb37df0a9087b27c63b59b5f2e048 diff --git a/lib/definitions/project.d.ts b/lib/definitions/project.d.ts index 2e99a72bfd..4ec6eb1d49 100644 --- a/lib/definitions/project.d.ts +++ b/lib/definitions/project.d.ts @@ -401,12 +401,6 @@ interface IPlatformProjectService extends NodeJS.EventEmitter { executeCommand(projectRoot: string, args: any, childProcessOpts?: any, spawnFromEventOptions?: ISpawnFromEventOptions): Promise; } -interface IAndroidProjectPropertiesManager { - getProjectReferences(): Promise; - addProjectReference(referencePath: string): Promise; - removeProjectReference(referencePath: string): Promise; -} - interface ITestExecutionService { startTestRunner(platform: string, projectData: IProjectData, projectFilesConfig: IProjectFilesConfig): Promise; startKarmaServer(platform: string, projectData: IProjectData, projectFilesConfig: IProjectFilesConfig): Promise; diff --git a/lib/services/android-project-properties-manager.ts b/lib/services/android-project-properties-manager.ts deleted file mode 100644 index 71a1338b61..0000000000 --- a/lib/services/android-project-properties-manager.ts +++ /dev/null @@ -1,101 +0,0 @@ -import * as path from "path"; - -export class AndroidProjectPropertiesManager implements IAndroidProjectPropertiesManager { - private _editor: IPropertiesParserEditor = null; - private filePath: string = null; - private projectReferences: ILibRef[]; - private dirty = false; - - constructor(private $propertiesParser: IPropertiesParser, - private $logger: ILogger, - directoryPath: string) { - this.filePath = path.join(directoryPath, "project.properties"); - } - - public async getProjectReferences(): Promise { - if (!this.projectReferences || this.dirty) { - const allProjectProperties = await this.getAllProjectProperties(); - const allProjectPropertiesKeys = _.keys(allProjectProperties); - this.projectReferences = _(allProjectPropertiesKeys) - .filter(key => _.startsWith(key, "android.library.reference.")) - .map(key => this.createLibraryReference(key, allProjectProperties[key])) - .value(); - } - - return this.projectReferences; - } - - public async addProjectReference(referencePath: string): Promise { - const references = await this.getProjectReferences(); - const libRefExists = _.some(references, r => path.normalize(r.path) === path.normalize(referencePath)); - if (!libRefExists) { - await this.addToPropertyList("android.library.reference", referencePath); - } - } - - public async removeProjectReference(referencePath: string): Promise { - const references = await this.getProjectReferences(); - const libRefExists = _.some(references, r => path.normalize(r.path) === path.normalize(referencePath)); - if (libRefExists) { - await this.removeFromPropertyList("android.library.reference", referencePath); - } else { - this.$logger.error(`Could not find ${referencePath}.`); - } - } - - private async createEditor(): Promise { - return this._editor || await this.$propertiesParser.createEditor(this.filePath); - } - - private buildKeyName(key: string, index: number): string { - return `${key}.${index}`; - } - - private async getAllProjectProperties(): Promise { - return this.$propertiesParser.read(this.filePath); - } - - private createLibraryReference(referenceName: string, referencePath: string): ILibRef { - return { - idx: parseInt(referenceName.split("android.library.reference.")[1]), - key: referenceName, - path: referencePath, - adjustedPath: path.join(path.dirname(this.filePath), referencePath) - }; - } - - private async addToPropertyList(key: string, value: string): Promise { - const editor = await this.createEditor(); - let i = 1; - while (editor.get(this.buildKeyName(key, i))) { - i++; - } - - editor.set(this.buildKeyName(key, i), value); - await this.$propertiesParser.saveEditor(); - this.dirty = true; - } - - private async removeFromPropertyList(key: string, value: string): Promise { - const editor = await this.createEditor(); - const valueLowerCase = value.toLowerCase(); - let i = 1; - let currentValue: any; - while (currentValue = editor.get(this.buildKeyName(key, i))) { - if (currentValue.toLowerCase() === valueLowerCase) { - while (currentValue = editor.get(this.buildKeyName(key, i + 1))) { - editor.set(this.buildKeyName(key, i), currentValue); - i++; - } - - editor.set(this.buildKeyName(key, i)); - break; - } - - i++; - } - - await this.$propertiesParser.saveEditor(); - this.dirty = true; - } -} diff --git a/lib/services/android-project-service.ts b/lib/services/android-project-service.ts index e7c36762d3..d47626112f 100644 --- a/lib/services/android-project-service.ts +++ b/lib/services/android-project-service.ts @@ -20,7 +20,6 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject { name: "lazy", version: "^1.0.11" } ]; - private _androidProjectPropertiesManagers: IDictionary; private isAndroidStudioTemplate: boolean; constructor(private $androidEmulatorServices: Mobile.IEmulatorPlatformServices, @@ -39,7 +38,6 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject private $platformEnvironmentRequirements: IPlatformEnvironmentRequirements, private $androidResourcesMigrationService: IAndroidResourcesMigrationService) { super($fs, $projectDataService); - this._androidProjectPropertiesManagers = Object.create(null); this.isAndroidStudioTemplate = false; } diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 126425193d..f16dd37f3d 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -4615,11 +4615,6 @@ "through2": "0.2.3" } }, - "properties-parser": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/properties-parser/-/properties-parser-0.2.3.tgz", - "integrity": "sha1-91kSVfcHq7/yJ8e1a2N9uwNzoQ8=" - }, "proxy-lib": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/proxy-lib/-/proxy-lib-0.4.0.tgz", diff --git a/package.json b/package.json index 7630240157..de0ba52467 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,6 @@ "plist": "1.1.0", "plist-merge-patch": "0.1.1", "progress-stream": "1.1.1", - "properties-parser": "0.2.3", "proxy-lib": "0.4.0", "qr-image": "3.2.0", "request": "2.81.0", diff --git a/test/android-project-properties-manager.ts b/test/android-project-properties-manager.ts deleted file mode 100644 index 1c51a3a75b..0000000000 --- a/test/android-project-properties-manager.ts +++ /dev/null @@ -1,145 +0,0 @@ -import * as ProjectPropertiesParserLib from "../lib/common/properties-parser"; -import * as FsLib from "../lib/common/file-system"; -import * as ProjectPropertiesManagerLib from "../lib/services/android-project-properties-manager"; -import * as HostInfoLib from "../lib/common/host-info"; -import * as StaticConfigLib from "../lib/config"; -import * as ErrorsLib from "../lib/common/errors"; -import * as LoggerLib from "../lib/common/logger"; -import * as ConfigLib from "../lib/config"; -import * as OptionsLib from "../lib/options"; -import * as yok from "../lib/common/yok"; -import { SettingsService } from "../lib/common/test/unit-tests/stubs"; -import * as path from "path"; -import temp = require("temp"); -temp.track(); -import { assert } from "chai"; - -function createTestInjector(): IInjector { - const testInjector = new yok.Yok(); - testInjector.register("propertiesParser", ProjectPropertiesParserLib.PropertiesParser); - testInjector.register("fs", FsLib.FileSystem); - testInjector.register("hostInfo", HostInfoLib.HostInfo); - testInjector.register("staticConfig", StaticConfigLib.StaticConfig); - testInjector.register("errors", ErrorsLib.Errors); - testInjector.register("logger", LoggerLib.Logger); - testInjector.register("config", ConfigLib.Configuration); - testInjector.register("options", OptionsLib.Options); - testInjector.register("settingsService", SettingsService); - - return testInjector; -} - -describe("Android project properties parser tests", () => { - it("adds project reference", async () => { - const testInjector = createTestInjector(); - const fs = testInjector.resolve("fs"); - - const projectPropertiesFileContent = 'target=android-21'; - const tempFolder = temp.mkdirSync("AndroidProjectPropertiesManager"); - fs.writeFile(path.join(tempFolder, "project.properties"), projectPropertiesFileContent); - - const projectPropertiesManager: IAndroidProjectPropertiesManager = testInjector.resolve( - ProjectPropertiesManagerLib.AndroidProjectPropertiesManager, { directoryPath: tempFolder }); - await projectPropertiesManager.addProjectReference("testValue"); - - const expectedContent = 'target=android-21' + '\n' + - 'android.library.reference.1=testValue'; - const actualContent = fs.readText(path.join(tempFolder, "project.properties")); - - assert.equal(expectedContent, actualContent); - assert.equal(1, _.keys(await projectPropertiesManager.getProjectReferences()).length); - }); - - it("adds project reference if another referencence already exists in project.properties file", async () => { - const testInjector = createTestInjector(); - const fs = testInjector.resolve("fs"); - - const projectPropertiesFileContent = 'target=android-21' + '\n' + - 'android.library.reference.1=someValue'; - const tempFolder = temp.mkdirSync("AndroidProjectPropertiesManager"); - fs.writeFile(path.join(tempFolder, "project.properties"), projectPropertiesFileContent); - - const projectPropertiesManager = testInjector.resolve( - ProjectPropertiesManagerLib.AndroidProjectPropertiesManager, { directoryPath: tempFolder }); - await projectPropertiesManager.addProjectReference("testValue"); - - const expectedContent = ['target=android-21', - 'android.library.reference.1=someValue', - 'android.library.reference.2=testValue'].join('\n'); - const actualContent = fs.readText(path.join(tempFolder, "project.properties")); - - assert.equal(expectedContent, actualContent); - assert.equal(2, _.keys(await projectPropertiesManager.getProjectReferences()).length); - }); - it("adds project reference if more than one references exist in project.properties file", async () => { - const testInjector = createTestInjector(); - const fs = testInjector.resolve("fs"); - - const projectPropertiesFileContent = ['target=android-21', - 'android.library.reference.1=value1', - 'android.library.reference.2=value2', - 'android.library.reference.3=value3', - 'android.library.reference.4=value4', - 'android.library.reference.5=value5'].join('\n'); - const tempFolder = temp.mkdirSync("AndroidProjectPropertiesManager"); - fs.writeFile(path.join(tempFolder, "project.properties"), projectPropertiesFileContent); - - const projectPropertiesManager: IAndroidProjectPropertiesManager = testInjector.resolve( - ProjectPropertiesManagerLib.AndroidProjectPropertiesManager, { directoryPath: tempFolder }); - await projectPropertiesManager.addProjectReference("testValue"); - - const expectedContent = projectPropertiesFileContent + '\n' + - 'android.library.reference.6=testValue'; - - const actualContent = fs.readText(path.join(tempFolder, "project.properties")); - - assert.equal(expectedContent, actualContent); - assert.equal(6, _.keys(await projectPropertiesManager.getProjectReferences()).length); - }); - it("removes project reference if only one reference exists", async () => { - const testInjector = createTestInjector(); - const fs = testInjector.resolve("fs"); - - const projectPropertiesFileContent = 'android.library.reference.1=value1' + '\n' + - 'target=android-21'; - const tempFolder = temp.mkdirSync("AndroidProjectPropertiesManager"); - fs.writeFile(path.join(tempFolder, "project.properties"), projectPropertiesFileContent); - - const projectPropertiesManager: IAndroidProjectPropertiesManager = testInjector.resolve( - ProjectPropertiesManagerLib.AndroidProjectPropertiesManager, { directoryPath: tempFolder }); - await projectPropertiesManager.removeProjectReference("value1"); - - const expectedContent = 'target=android-21'; - const actualContent = fs.readText(path.join(tempFolder, "project.properties")); - - assert.equal(expectedContent, actualContent); - assert.equal(0, _.keys(await projectPropertiesManager.getProjectReferences()).length); - }); - it("removes project reference when another references exist before and after the specified reference", async () => { - const testInjector = createTestInjector(); - const fs = testInjector.resolve("fs"); - - const projectPropertiesFileContent = ['target=android-17', - 'android.library.reference.1=value1', - 'android.library.reference.2=value2', - 'android.library.reference.3=value3', - 'android.library.reference.4=value4', - 'android.library.reference.5=value5'].join('\n'); - const tempFolder = temp.mkdirSync("AndroidProjectPropertiesManager"); - fs.writeFile(path.join(tempFolder, "project.properties"), projectPropertiesFileContent); - - const projectPropertiesManager: IAndroidProjectPropertiesManager = testInjector.resolve( - ProjectPropertiesManagerLib.AndroidProjectPropertiesManager, { directoryPath: tempFolder }); - await projectPropertiesManager.removeProjectReference("value3"); - - const expectedContent = ['target=android-17', - 'android.library.reference.1=value1', - 'android.library.reference.2=value2', - 'android.library.reference.3=value4', - 'android.library.reference.4=value5'].join('\n') + '\n'; - const actualContent = fs.readText(path.join(tempFolder, "project.properties")); - - assert.equal(expectedContent, actualContent); - assert.equal(4, _.keys(await projectPropertiesManager.getProjectReferences()).length); - }); -}); From 825a378762d08153bc637f0db89baa06126c6f52 Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Thu, 29 Mar 2018 00:17:26 +0300 Subject: [PATCH 12/32] fix(deps): Remove filesize and progress-stream Remove filesize and progress-stream dependencies as they've been used only in a function that is never called. As the function implements interesting functionality, it is commented, not deleted. However, the dependencies are not used anywhere else, so they can be safely removed. --- lib/common | 2 +- npm-shrinkwrap.json | 70 --------------------------------------------- package.json | 2 -- 3 files changed, 1 insertion(+), 73 deletions(-) diff --git a/lib/common b/lib/common index 883a0d2faf..a860d8d9a5 160000 --- a/lib/common +++ b/lib/common @@ -1 +1 @@ -Subproject commit 883a0d2faf2eb37df0a9087b27c63b59b5f2e048 +Subproject commit a860d8d9a536b74b0856f5e02d3300c45bed25f7 diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index f16dd37f3d..14929f16b0 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1452,11 +1452,6 @@ "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=" }, - "filesize": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.1.2.tgz", - "integrity": "sha1-jB0EdXYIY3CZmyPDLyF8TVGr8oo=" - }, "fill-range": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", @@ -4152,11 +4147,6 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, - "object-keys": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", - "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=" - }, "object.omit": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", @@ -4605,16 +4595,6 @@ "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", "dev": true }, - "progress-stream": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/progress-stream/-/progress-stream-1.1.1.tgz", - "integrity": "sha1-nsvxh5MsSUHVUCGRkNdN7ArEX1Q=", - "requires": { - "single-line-log": "0.3.1", - "speedometer": "0.1.4", - "through2": "0.2.3" - } - }, "proxy-lib": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/proxy-lib/-/proxy-lib-0.4.0.tgz", @@ -5126,11 +5106,6 @@ } } }, - "single-line-log": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/single-line-log/-/single-line-log-0.3.1.tgz", - "integrity": "sha1-p61lB/IYzl3+FsS/LWWSRkGeegY=" - }, "sinon": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/sinon/-/sinon-4.1.2.tgz", @@ -5254,11 +5229,6 @@ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=" }, - "speedometer": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/speedometer/-/speedometer-0.1.4.tgz", - "integrity": "sha1-mHbb0qFp0xFUAtSObqYynIgWpQ0=" - }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -5510,38 +5480,6 @@ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, - "through2": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.2.3.tgz", - "integrity": "sha1-6zKE2k6jEbbMis42U3SKUqvyWj8=", - "requires": { - "readable-stream": "1.1.14", - "xtend": "2.1.2" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - } - } - }, "tiny-lr": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-0.2.1.tgz", @@ -6047,14 +5985,6 @@ "version": "https://github.com/telerik/node-XMLHttpRequest/tarball/master", "integrity": "sha1-gyu8L8J4DhCCCmdOlAQRCpQ0M6c=" }, - "xtend": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", - "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=", - "requires": { - "object-keys": "0.4.0" - } - }, "y18n": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", diff --git a/package.json b/package.json index de0ba52467..41f2828895 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,6 @@ "colors": "1.1.2", "email-validator": "1.0.4", "esprima": "2.7.0", - "filesize": "3.1.2", "gaze": "1.1.0", "iconv-lite": "0.4.11", "inquirer": "0.9.0", @@ -61,7 +60,6 @@ "pbxproj-dom": "1.0.11", "plist": "1.1.0", "plist-merge-patch": "0.1.1", - "progress-stream": "1.1.1", "proxy-lib": "0.4.0", "qr-image": "3.2.0", "request": "2.81.0", From 9d196fd9af5eb3ed54d0f71b1a71d55e4d63e0c0 Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Thu, 29 Mar 2018 09:50:31 +0300 Subject: [PATCH 13/32] chore: Update to latest common lib --- lib/common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/common b/lib/common index a860d8d9a5..f325d788fe 160000 --- a/lib/common +++ b/lib/common @@ -1 +1 @@ -Subproject commit a860d8d9a536b74b0856f5e02d3300c45bed25f7 +Subproject commit f325d788fe7304039465fde0091d9ae0f7f7c6a9 From e56d57de6f2beda411f0a5d413de9376b0034ff7 Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Thu, 29 Mar 2018 10:35:25 +0300 Subject: [PATCH 14/32] fix(logs): Logs from iOS device are not shown on Windows When cloud build is used and iOS device does not have Developer Disk Image mounted, the logs are not visible. The problem is that the code fails to start/stop the application before starting the device log streams. Fix this by starting the logs before trying to start/stop the application. --- lib/common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/common b/lib/common index f325d788fe..01cb744eda 160000 --- a/lib/common +++ b/lib/common @@ -1 +1 @@ -Subproject commit f325d788fe7304039465fde0091d9ae0f7f7c6a9 +Subproject commit 01cb744eda754c004d86e348ae1253429e33d583 From ad23f8c3c225492c1eddbc59cd4a984d8dc9ea05 Mon Sep 17 00:00:00 2001 From: fatme Date: Tue, 20 Mar 2018 09:39:46 +0200 Subject: [PATCH 15/32] [WIP] Fix env messages --- lib/declarations.d.ts | 5 ++++ .../nativescript-cloud-extension-service.ts | 11 +++++++-- .../platform-environment-requirements.ts | 23 ++++++++++++++----- 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/lib/declarations.d.ts b/lib/declarations.d.ts index bb644633c1..4be5e13ea3 100644 --- a/lib/declarations.d.ts +++ b/lib/declarations.d.ts @@ -794,6 +794,11 @@ interface INativescriptCloudExtensionService { * @return {Promise} returns the extension data */ install(): Promise; + /** + * Checks if nativescript-cloud extension is installed + * @return {boolean} returns true in case when nativescript-cloud extension is installed, false otherwise + */ + isInstalled(): boolean } /** diff --git a/lib/services/nativescript-cloud-extension-service.ts b/lib/services/nativescript-cloud-extension-service.ts index 14eeacd46c..1debab122b 100644 --- a/lib/services/nativescript-cloud-extension-service.ts +++ b/lib/services/nativescript-cloud-extension-service.ts @@ -6,12 +6,19 @@ export class NativescriptCloudExtensionService implements INativescriptCloudExte private $logger: ILogger) { } public install(): Promise { - const installedExtensions = this.$extensibilityService.getInstalledExtensions() || {}; - if (!installedExtensions[constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME]) { + if (!this.isInstalled()) { return this.$extensibilityService.installExtension(constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME); } this.$logger.out(`Extension ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} is already installed.`); } + + public isInstalled(): boolean { + return !!this.getInstalledExtensions()[constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME]; + } + + private getInstalledExtensions(): IStringDictionary { + return this.$extensibilityService.getInstalledExtensions() || {}; + } } $injector.register("nativescriptCloudExtensionService", NativescriptCloudExtensionService); diff --git a/lib/services/platform-environment-requirements.ts b/lib/services/platform-environment-requirements.ts index 0ae315c8dd..1b2abcc01b 100644 --- a/lib/services/platform-environment-requirements.ts +++ b/lib/services/platform-environment-requirements.ts @@ -32,13 +32,10 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ const canExecute = await this.$doctorService.canExecuteLocalBuild(platform); if (!canExecute) { if (!isInteractive()) { - this.fail(`You are missing the ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension and you will not be able to execute cloud builds. Your environment is not configured properly and you will not be able to execute local builds. To continue, choose one of the following options: ` + EOL - + "Run $ tns setup command to run the setup script to try to automatically configure your environment for local builds." + EOL - + `Run $ tns cloud setup command to install the ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension to configure your environment for cloud builds.` + EOL - + `Verify that your environment is configured according to the system requirements described at ${this.$staticConfig.SYS_REQUIREMENTS_LINK}`); + this.fail(this.getNonInteractiveConsoleMessage(platform)); } - this.$logger.info(`You are missing the ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension and you will not be able to execute cloud builds. Your environment is not configured properly and you will not be able to execute local builds. ` + EOL + this.$logger.info(`` + EOL + `Select "Configure for Cloud Builds" to install the ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension and automatically configure your environment for cloud builds.` + EOL + `Select "Configure for Local Builds" to run the setup script and automatically configure your environment for local builds.` + `Select "Configure for Both Local and Cloud Builds" to automatically configure your environment for both options.` @@ -100,7 +97,7 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ return this.$nativescriptCloudExtensionService.install(); } - private getCloudBuildsMessage(platform: string): string { + private getCloudBuildsMessage(platform: string): string { const cloudCommandName = this.cliCommandToCloudCommandName[this.$commandsService.currentCommandData.commandName]; if (!cloudCommandName) { return `In order to test your application use the $ tns login command to log in with your account and then $ tns cloud build command to build your app in the cloud.`; @@ -136,5 +133,19 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ private fail(message: string): void { this.$errors.fail({ formatStr: message, suppressCommandHelp: true, printOnStdout: true }); } + + private getNonInteractiveConsoleMessage(platform: string) { + if (!this.$nativescriptCloudExtensionService.isInstalled()) { + return `You are missing the ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension and you will not be able to execute cloud builds. Your environment is not configured properly and you will not be able to execute local builds. To continue, choose one of the following options: ` + EOL + + "Run $ tns setup command to run the setup script to try to automatically configure your environment for local builds." + EOL + + `Run $ tns cloud setup command to install the ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension to configure your environment for cloud builds.` + EOL + + `Verify that your environment is configured according to the system requirements described at ${this.$staticConfig.SYS_REQUIREMENTS_LINK}.` + } + + return `Your environment is not configured properly and you will not be able to execute local builds. To continue, choose one of the following options: ` + EOL + + "Run $ tns setup command to run the setup script to try to automatically configure your environment for local builds." + EOL + + `${this.getCloudBuildsMessage(platform)}` + EOL + + `Verify that your environment is configured according to the system requirements described at ${this.$staticConfig.SYS_REQUIREMENTS_LINK}.`; + } } $injector.register("platformEnvironmentRequirements", PlatformEnvironmentRequirements); From 28a0cbd8e988bb595a22166f8351c0587c1dd997 Mon Sep 17 00:00:00 2001 From: fatme Date: Thu, 22 Mar 2018 15:18:25 +0200 Subject: [PATCH 16/32] Fixes the behaviour of getting started when `nativescript-cloud` is already installed. Fixes messages when console is non-interactive. Add `In case you have any issues, you can ask in our forum.` message when env is not configured after setup script. Refactor unit tests --- .../nativescript-cloud-extension-service.ts | 22 +- .../platform-environment-requirements.ts | 91 ++++--- .../platform-environment-requirements.ts | 244 +++++++++--------- 3 files changed, 205 insertions(+), 152 deletions(-) diff --git a/lib/services/nativescript-cloud-extension-service.ts b/lib/services/nativescript-cloud-extension-service.ts index 1debab122b..9b6933fbd8 100644 --- a/lib/services/nativescript-cloud-extension-service.ts +++ b/lib/services/nativescript-cloud-extension-service.ts @@ -1,9 +1,10 @@ import * as constants from "../constants"; +import * as semver from "semver"; export class NativescriptCloudExtensionService implements INativescriptCloudExtensionService { - constructor(private $extensibilityService: IExtensibilityService, - private $logger: ILogger) { } + private $logger: ILogger, + private $npmInstallationManager: INpmInstallationManager) { } public install(): Promise { if (!this.isInstalled()) { @@ -14,11 +15,22 @@ export class NativescriptCloudExtensionService implements INativescriptCloudExte } public isInstalled(): boolean { - return !!this.getInstalledExtensions()[constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME]; + return !!this.getExtensionData(); + } + + public async isLatestVersionInstalled(): Promise { + const extensionData = this.getExtensionData(); + if (extensionData) { + const latestVersion = await this.$npmInstallationManager.getLatestVersion(constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME); + return semver.eq(latestVersion, extensionData.version); + } + + return false; } - private getInstalledExtensions(): IStringDictionary { - return this.$extensibilityService.getInstalledExtensions() || {}; + private getExtensionData(): IExtensionData { + return this.$extensibilityService.getInstalledExtensionsData() + .find(extensionData => extensionData.extensionName === constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME); } } $injector.register("nativescriptCloudExtensionService", NativescriptCloudExtensionService); diff --git a/lib/services/platform-environment-requirements.ts b/lib/services/platform-environment-requirements.ts index 1b2abcc01b..d6ecedfbbf 100644 --- a/lib/services/platform-environment-requirements.ts +++ b/lib/services/platform-environment-requirements.ts @@ -6,17 +6,19 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ constructor(private $commandsService: ICommandsService, private $doctorService: IDoctorService, private $errors: IErrors, - private $nativescriptCloudExtensionService: INativescriptCloudExtensionService, private $logger: ILogger, + private $nativescriptCloudExtensionService: INativescriptCloudExtensionService, private $prompter: IPrompter, private $staticConfig: IStaticConfig) { } - public static CLOUD_BUILDS_OPTION_NAME = "Configure for Cloud Builds"; - public static SETUP_SCRIPT_OPTION_NAME = "Configure for Local Builds"; + public static CLOUD_SETUP_OPTION_NAME = "Configure for Cloud Builds"; + public static LOCAL_SETUP_OPTION_NAME = "Configure for Local Builds"; public static MANUALLY_SETUP_OPTION_NAME = "Skip Step and Configure Manually"; - private static BOTH_CLOUD_BUILDS_AND_SETUP_SCRIPT_OPTION_NAME = "Configure for Both Local and Cloud Builds"; + private static BOTH_CLOUD_SETUP_AND_LOCAL_SETUP_OPTION_NAME = "Configure for Both Local and Cloud Builds"; private static NOT_CONFIGURED_ENV_MESSAGE = "To continue, choose one of the following options: "; - private static NOT_CONFIGURED_ENV_AFTER_SETUP_SCRIPT_MESSAGE = "The setup script was not able to configure your environment for local builds. To execute local builds, you have to set up your environment manually. To continue, choose one of the following options:"; + private static NOT_CONFIGURED_ENV_AFTER_SETUP_SCRIPT_MESSAGE = "The setup script was not able to configure your environment for local builds. To execute local builds, you have to set up your environment manually. In case you have any issues, you can ask in our forum. To continue, choose one of the following options:"; + private static MISSING_LOCAL_AND_CLOUD_SETUP_MESSAGE = `You are missing the ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension and you will not be able to execute cloud builds. Your environment is not configured properly and you will not be able to execute local builds. To continue, choose one of the following options: `; + private static MISSING_LOCAL_SETUP_MESSAGE = 'Your environment is not configured properly and you will not be able to execute local builds.'; private cliCommandToCloudCommandName: IStringDictionary = { "build": "tns cloud build", @@ -35,41 +37,35 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ this.fail(this.getNonInteractiveConsoleMessage(platform)); } - this.$logger.info(`` + EOL - + `Select "Configure for Cloud Builds" to install the ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension and automatically configure your environment for cloud builds.` + EOL - + `Select "Configure for Local Builds" to run the setup script and automatically configure your environment for local builds.` - + `Select "Configure for Both Local and Cloud Builds" to automatically configure your environment for both options.` - + `Select "Skip Step and Configure Manually" to disregard these options and install any required components manually.`); + this.$logger.info(this.getInteractiveConsoleMessage(platform)); - const selectedOption = await this.$prompter.promptForChoice(PlatformEnvironmentRequirements.NOT_CONFIGURED_ENV_MESSAGE, [ - PlatformEnvironmentRequirements.CLOUD_BUILDS_OPTION_NAME, - PlatformEnvironmentRequirements.SETUP_SCRIPT_OPTION_NAME, - PlatformEnvironmentRequirements.BOTH_CLOUD_BUILDS_AND_SETUP_SCRIPT_OPTION_NAME, - PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME, - ]); + const selectedOption = await this.promptForChoice(); await this.processCloudBuildsIfNeeded(platform, selectedOption); - this.processManuallySetupIfNeeded(platform, selectedOption); - if (selectedOption === PlatformEnvironmentRequirements.SETUP_SCRIPT_OPTION_NAME) { + if (selectedOption === PlatformEnvironmentRequirements.LOCAL_SETUP_OPTION_NAME) { await this.$doctorService.runSetupScript(); if (await this.$doctorService.canExecuteLocalBuild(platform)) { return true; } - const option = await this.$prompter.promptForChoice(PlatformEnvironmentRequirements.NOT_CONFIGURED_ENV_AFTER_SETUP_SCRIPT_MESSAGE, [ - PlatformEnvironmentRequirements.CLOUD_BUILDS_OPTION_NAME, - PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME - ]); + if (this.$nativescriptCloudExtensionService.isInstalled()) { + this.processManuallySetup(platform); + } else { + const option = await this.$prompter.promptForChoice(PlatformEnvironmentRequirements.NOT_CONFIGURED_ENV_AFTER_SETUP_SCRIPT_MESSAGE, [ + PlatformEnvironmentRequirements.CLOUD_SETUP_OPTION_NAME, + PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME + ]); - await this.processCloudBuildsIfNeeded(platform, option); + await this.processCloudBuildsIfNeeded(platform, option); - this.processManuallySetupIfNeeded(platform, option); + this.processManuallySetupIfNeeded(platform, option); + } } - if (selectedOption === PlatformEnvironmentRequirements.BOTH_CLOUD_BUILDS_AND_SETUP_SCRIPT_OPTION_NAME) { + if (selectedOption === PlatformEnvironmentRequirements.BOTH_CLOUD_SETUP_AND_LOCAL_SETUP_OPTION_NAME) { await this.processBothCloudBuildsAndSetupScript(platform); if (await this.$doctorService.canExecuteLocalBuild(platform)) { return true; @@ -83,7 +79,7 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ } private async processCloudBuildsIfNeeded(platform: string, selectedOption: string): Promise { - if (selectedOption === PlatformEnvironmentRequirements.CLOUD_BUILDS_OPTION_NAME) { + if (selectedOption === PlatformEnvironmentRequirements.CLOUD_SETUP_OPTION_NAME) { await this.processCloudBuilds(platform); } } @@ -135,17 +131,48 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ } private getNonInteractiveConsoleMessage(platform: string) { - if (!this.$nativescriptCloudExtensionService.isInstalled()) { - return `You are missing the ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension and you will not be able to execute cloud builds. Your environment is not configured properly and you will not be able to execute local builds. To continue, choose one of the following options: ` + EOL + if (this.$nativescriptCloudExtensionService.isInstalled()) { + return `${PlatformEnvironmentRequirements.MISSING_LOCAL_SETUP_MESSAGE} To continue, choose one of the following options: ` + EOL + "Run $ tns setup command to run the setup script to try to automatically configure your environment for local builds." + EOL - + `Run $ tns cloud setup command to install the ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension to configure your environment for cloud builds.` + EOL - + `Verify that your environment is configured according to the system requirements described at ${this.$staticConfig.SYS_REQUIREMENTS_LINK}.` + + `${this.getCloudBuildsMessage(platform)}` + EOL + + `Verify that your environment is configured according to the system requirements described at ${this.$staticConfig.SYS_REQUIREMENTS_LINK}.`; } - return `Your environment is not configured properly and you will not be able to execute local builds. To continue, choose one of the following options: ` + EOL + return `${PlatformEnvironmentRequirements.MISSING_LOCAL_AND_CLOUD_SETUP_MESSAGE}` + EOL + "Run $ tns setup command to run the setup script to try to automatically configure your environment for local builds." + EOL - + `${this.getCloudBuildsMessage(platform)}` + EOL + + `Run $ tns cloud setup command to install the ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension to configure your environment for cloud builds.` + EOL + `Verify that your environment is configured according to the system requirements described at ${this.$staticConfig.SYS_REQUIREMENTS_LINK}.`; } + + private getInteractiveConsoleMessage(platform: string) { + if (this.$nativescriptCloudExtensionService.isInstalled()) { + const message = `The ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension is installed and you can ${_.lowerFirst(this.getCloudBuildsMessage(platform))}`; + + return `${message.bold}` + EOL + + `${PlatformEnvironmentRequirements.MISSING_LOCAL_SETUP_MESSAGE} To continue, choose one of the following options: ` + EOL + + `Select "Configure for Local Builds" to run the setup script and automatically configure your environment for local builds.` + EOL + + `Select "Skip Step and Configure Manually" to disregard this option and install any required components manually.`; + } + + return `${PlatformEnvironmentRequirements.MISSING_LOCAL_AND_CLOUD_SETUP_MESSAGE}` + EOL + + `Select "Configure for Cloud Builds" to install the ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension and automatically configure your environment for cloud builds.` + EOL + + `Select "Configure for Local Builds" to run the setup script and automatically configure your environment for local builds.` + + `Select "Configure for Both Local and Cloud Builds" to automatically configure your environment for both options.` + + `Select "Skip Step and Configure Manually" to disregard these options and install any required components manually.`; + } + + private promptForChoice(): Promise { + const choices = this.$nativescriptCloudExtensionService.isInstalled() ? [ + PlatformEnvironmentRequirements.LOCAL_SETUP_OPTION_NAME, + PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME, + ] : [ + PlatformEnvironmentRequirements.CLOUD_SETUP_OPTION_NAME, + PlatformEnvironmentRequirements.LOCAL_SETUP_OPTION_NAME, + PlatformEnvironmentRequirements.BOTH_CLOUD_SETUP_AND_LOCAL_SETUP_OPTION_NAME, + PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME, + ]; + + return this.$prompter.promptForChoice(PlatformEnvironmentRequirements.NOT_CONFIGURED_ENV_MESSAGE, choices); + } } $injector.register("platformEnvironmentRequirements", PlatformEnvironmentRequirements); diff --git a/test/services/platform-environment-requirements.ts b/test/services/platform-environment-requirements.ts index 8c52e7635e..83133a6562 100644 --- a/test/services/platform-environment-requirements.ts +++ b/test/services/platform-environment-requirements.ts @@ -6,7 +6,8 @@ import { assert } from "chai"; const platform = "android"; const cloudBuildsErrorMessage = `In order to test your application use the $ tns login command to log in with your account and then $ tns cloud build command to build your app in the cloud.`; const manuallySetupErrorMessage = `To be able to build for ${platform}, verify that your environment is configured according to the system requirements described at `; -const nonInteractiveConsoleErrorMessage = `You are missing the nativescript-cloud extension and you will not be able to execute cloud builds. Your environment is not configured properly and you will not be able to execute local builds. To continue, choose one of the following options: \nRun $ tns setup command to run the setup script to try to automatically configure your environment for local builds.\nRun $ tns cloud setup command to install the nativescript-cloud extension to configure your environment for cloud builds.\nVerify that your environment is configured according to the system requirements described at `; +const nonInteractiveConsoleMessageWhenExtensionIsNotInstalled = `You are missing the nativescript-cloud extension and you will not be able to execute cloud builds. Your environment is not configured properly and you will not be able to execute local builds. To continue, choose one of the following options: \nRun $ tns setup command to run the setup script to try to automatically configure your environment for local builds.\nRun $ tns cloud setup command to install the nativescript-cloud extension to configure your environment for cloud builds.\nVerify that your environment is configured according to the system requirements described at `; +const nonInteractiveConsoleMessageWhenExtensionIsInstalled = `Your environment is not configured properly and you will not be able to execute local builds. To continue, choose one of the following options: \nRun $ tns setup command to run the setup script to try to automatically configure your environment for local builds.\nIn order to test your application use the $ tns login command to log in with your account and then $ tns cloud build command to build your app in the cloud.\nVerify that your environment is configured according to the system requirements described at .`; function createTestInjector() { const testInjector = new Yok(); @@ -31,6 +32,37 @@ describe("platformEnvironmentRequirements ", () => { describe("checkRequirements", () => { let testInjector: IInjector = null; let platformEnvironmentRequirements: IPlatformEnvironmentRequirements = null; + let promptForChoiceData: {message: string, choices: string[]}[] = []; + let isExtensionInstallCalled = false; + + function mockDoctorService(data: {canExecuteLocalBuild: boolean, mockSetupScript?: boolean}) { + const doctorService = testInjector.resolve("doctorService"); + doctorService.canExecuteLocalBuild = () => data.canExecuteLocalBuild; + if (data.mockSetupScript) { + doctorService.runSetupScript = () => Promise.resolve(); + } + } + + function mockPrompter(data: {firstCallOptionName: string, secondCallOptionName?: string}) { + const prompter = testInjector.resolve("prompter"); + prompter.promptForChoice = (message: string, choices: string[]) => { + promptForChoiceData.push({message: message, choices: choices}); + + if (promptForChoiceData.length === 1) { + return Promise.resolve(data.firstCallOptionName); + } + + if (data.secondCallOptionName) { + return Promise.resolve(data.secondCallOptionName); + } + }; + } + + function mockNativescriptCloudExtensionService(data: {isInstalled: boolean}) { + const nativescriptCloudExtensionService = testInjector.resolve("nativescriptCloudExtensionService"); + nativescriptCloudExtensionService.isInstalled = () => data.isInstalled; + nativescriptCloudExtensionService.install = () => { isExtensionInstallCalled = true; }; + } beforeEach(() => { testInjector = createTestInjector(); @@ -39,156 +71,138 @@ describe("platformEnvironmentRequirements ", () => { process.stdin.isTTY = true; }); - it("should show prompt when environment is not configured", async () => { - const doctorService = testInjector.resolve("doctorService"); - doctorService.canExecuteLocalBuild = () => false; - - let isPromptForChoiceCalled = false; - const prompter = testInjector.resolve("prompter"); - prompter.promptForChoice = () => { - isPromptForChoiceCalled = true; - return PlatformEnvironmentRequirements.CLOUD_BUILDS_OPTION_NAME; - }; + afterEach(() => { + promptForChoiceData = []; + isExtensionInstallCalled = false; + delete process.env.NS_SKIP_ENV_CHECK; + }); - let isInstallExtensionCalled = false; - const nativescriptCloudExtensionService = testInjector.resolve("nativescriptCloudExtensionService"); - nativescriptCloudExtensionService.install = () => {isInstallExtensionCalled = true; }; + it("should return true when environment is configured", async () => { + mockDoctorService({ canExecuteLocalBuild: true }); + const result = await platformEnvironmentRequirements.checkEnvironmentRequirements(platform); + assert.isTrue(result); + assert.isTrue(promptForChoiceData.length === 0); + }); + it("should show prompt when environment is not configured and nativescript-cloud extension is not installed", async () => { + mockDoctorService({ canExecuteLocalBuild: false }); + mockPrompter({ firstCallOptionName: PlatformEnvironmentRequirements.CLOUD_SETUP_OPTION_NAME }); + mockNativescriptCloudExtensionService({ isInstalled: false }); await assert.isRejected(platformEnvironmentRequirements.checkEnvironmentRequirements(platform)); - assert.isTrue(isPromptForChoiceCalled); - assert.isTrue(isInstallExtensionCalled); + assert.isTrue(promptForChoiceData.length === 1); + assert.isTrue(isExtensionInstallCalled); + assert.deepEqual("To continue, choose one of the following options: ", promptForChoiceData[0].message); + assert.deepEqual(['Configure for Cloud Builds', 'Configure for Local Builds', 'Configure for Both Local and Cloud Builds', 'Skip Step and Configure Manually'], promptForChoiceData[0].choices); }); + it("should show prompt when environment is not configured and nativescript-cloud extension is installed", async () => { + mockDoctorService({ canExecuteLocalBuild: false }); + mockPrompter({ firstCallOptionName: PlatformEnvironmentRequirements.CLOUD_SETUP_OPTION_NAME }); + mockNativescriptCloudExtensionService({ isInstalled: true }); - it("should return true when environment is configured", async () => { - const doctorService = testInjector.resolve("doctorService"); - doctorService.canExecuteLocalBuild = () => true; + await assert.isRejected(platformEnvironmentRequirements.checkEnvironmentRequirements(platform)); + assert.isTrue(promptForChoiceData.length === 1); + assert.deepEqual("To continue, choose one of the following options: ", promptForChoiceData[0].message); + assert.deepEqual(['Configure for Local Builds', 'Skip Step and Configure Manually'], promptForChoiceData[0].choices); + }); + it("should skip env chech when NS_SKIP_ENV_CHECK environment variable is passed", async() => { + process.env.NS_SKIP_ENV_CHECK = true; - const result = await platformEnvironmentRequirements.checkEnvironmentRequirements(platform); - assert.isTrue(result); + assert.isTrue(await platformEnvironmentRequirements.checkEnvironmentRequirements(platform)); + assert.isFalse(isExtensionInstallCalled); + assert.isTrue(promptForChoiceData.length === 0); }); - describe("when setup script option is selected ", () => { + describe("when local setup option is selected", () => { + beforeEach(() => { + mockPrompter( {firstCallOptionName: PlatformEnvironmentRequirements.LOCAL_SETUP_OPTION_NAME}); + }); + it("should return true when env is configured after executing setup script", async () => { const doctorService = testInjector.resolve("doctorService"); doctorService.canExecuteLocalBuild = () => false; doctorService.runSetupScript = async () => { doctorService.canExecuteLocalBuild = () => true; }; - const prompter = testInjector.resolve("prompter"); - prompter.promptForChoice = () => Promise.resolve(PlatformEnvironmentRequirements.SETUP_SCRIPT_OPTION_NAME); - - const result = await platformEnvironmentRequirements.checkEnvironmentRequirements(platform); - assert.isTrue(result); - }); - it("should prompt for choice when env is not configured after executing setup script", async () => { - const doctorService = testInjector.resolve("doctorService"); - doctorService.canExecuteLocalBuild = () => false; - doctorService.runSetupScript = () => Promise.resolve(); + mockNativescriptCloudExtensionService({ isInstalled: null }); - let isPromptForChoiceCalled = true; - const prompter = testInjector.resolve("prompter"); - prompter.promptForChoice = () => { - if (isPromptForChoiceCalled) { - isPromptForChoiceCalled = false; - return PlatformEnvironmentRequirements.SETUP_SCRIPT_OPTION_NAME; - } - - isPromptForChoiceCalled = true; - return PlatformEnvironmentRequirements.CLOUD_BUILDS_OPTION_NAME; - }; - - let isInstallExtensionCalled = false; - const nativescriptCloudExtensionService = testInjector.resolve("nativescriptCloudExtensionService"); - nativescriptCloudExtensionService.install = () => {isInstallExtensionCalled = true; }; - - await assert.isRejected(platformEnvironmentRequirements.checkEnvironmentRequirements(platform)); - assert.isTrue(isInstallExtensionCalled); - assert.isTrue(isPromptForChoiceCalled); + assert.isTrue(await platformEnvironmentRequirements.checkEnvironmentRequirements(platform)); }); - describe("and environment is not configured after executing setup script ", () => { - beforeEach(() => { - const doctorService = testInjector.resolve("doctorService"); - doctorService.canExecuteLocalBuild = () => false; - doctorService.runSetupScript = () => Promise.resolve(); - }); - it("should install nativescript-cloud extension when cloud builds option is selected", async () => { - let isPromptForChoiceCalled = true; - const prompter = testInjector.resolve("prompter"); - prompter.promptForChoice = () => { - if (isPromptForChoiceCalled) { - isPromptForChoiceCalled = false; - return PlatformEnvironmentRequirements.SETUP_SCRIPT_OPTION_NAME; - } - - isPromptForChoiceCalled = true; - return PlatformEnvironmentRequirements.CLOUD_BUILDS_OPTION_NAME; - }; - - let isInstallExtensionCalled = false; - const nativescriptCloudExtensionService = testInjector.resolve("nativescriptCloudExtensionService"); - nativescriptCloudExtensionService.install = () => {isInstallExtensionCalled = true; }; - - await assert.isRejected(platformEnvironmentRequirements.checkEnvironmentRequirements(platform), cloudBuildsErrorMessage); - assert.isTrue(isInstallExtensionCalled); - assert.isTrue(isPromptForChoiceCalled); - }); - it("should fail when manually setup option is selected", async () => { - let isPromptForChoiceCalled = true; - const prompter = testInjector.resolve("prompter"); - prompter.promptForChoice = () => { - if (isPromptForChoiceCalled) { - isPromptForChoiceCalled = false; - return PlatformEnvironmentRequirements.SETUP_SCRIPT_OPTION_NAME; - } - - isPromptForChoiceCalled = true; - return PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME; - }; + describe("and env is not configured after executing setup script", () => { + it("should setup manually when cloud extension is installed", async () => { + mockDoctorService( { canExecuteLocalBuild: false, mockSetupScript: true }); + mockPrompter({ firstCallOptionName: PlatformEnvironmentRequirements.LOCAL_SETUP_OPTION_NAME, secondCallOptionName: PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME }); + mockNativescriptCloudExtensionService({ isInstalled: true }); await assert.isRejected(platformEnvironmentRequirements.checkEnvironmentRequirements(platform), manuallySetupErrorMessage); - assert.isTrue(isPromptForChoiceCalled); + }); + describe("and cloud extension is not installed", () => { + beforeEach(() => { + mockDoctorService({ canExecuteLocalBuild: false, mockSetupScript: true }); + mockNativescriptCloudExtensionService({ isInstalled: false }); + }); + it("should list 2 posibile options to select", async () => { + mockPrompter({ firstCallOptionName: PlatformEnvironmentRequirements.LOCAL_SETUP_OPTION_NAME }); + + await platformEnvironmentRequirements.checkEnvironmentRequirements(platform); + assert.deepEqual(promptForChoiceData[1].choices, ['Configure for Cloud Builds', 'Skip Step and Configure Manually']); + }); + it("should install nativescript-cloud extension when 'Configure for Cloud Builds' option is selected", async () => { + mockPrompter({ firstCallOptionName: PlatformEnvironmentRequirements.LOCAL_SETUP_OPTION_NAME, secondCallOptionName: PlatformEnvironmentRequirements.CLOUD_SETUP_OPTION_NAME }); + + await assert.isRejected(platformEnvironmentRequirements.checkEnvironmentRequirements(platform), cloudBuildsErrorMessage); + assert.deepEqual(isExtensionInstallCalled, true); + }); + it("should setup manually when 'Skip Step and Configure Manually' option is selected", async () => { + mockPrompter({ firstCallOptionName: PlatformEnvironmentRequirements.LOCAL_SETUP_OPTION_NAME, secondCallOptionName: PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME }); + await assert.isRejected(platformEnvironmentRequirements.checkEnvironmentRequirements(platform), manuallySetupErrorMessage); + }); }); }); }); - describe("when cloud builds option is selected", () => { - it("should install nativescript-cloud extension when cloud builds option is selected", async () => { - const doctorService = testInjector.resolve("doctorService"); - doctorService.canExecuteLocalBuild = () => false; - - const prompter = testInjector.resolve("prompter"); - prompter.promptForChoice = () => Promise.resolve(PlatformEnvironmentRequirements.CLOUD_BUILDS_OPTION_NAME); - - let isInstallExtensionCalled = false; - const nativescriptCloudExtensionService = testInjector.resolve("nativescriptCloudExtensionService"); - nativescriptCloudExtensionService.install = () => {isInstallExtensionCalled = true; }; + describe("when cloud setup option is selected", () => { + beforeEach(() => { + mockDoctorService({ canExecuteLocalBuild: false }); + mockPrompter({ firstCallOptionName: PlatformEnvironmentRequirements.CLOUD_SETUP_OPTION_NAME }); + }); + it("should install nativescript-cloud extension when it is not installed", async () => { + mockNativescriptCloudExtensionService({ isInstalled: false }); await assert.isRejected(platformEnvironmentRequirements.checkEnvironmentRequirements(platform), cloudBuildsErrorMessage); - assert.isTrue(isInstallExtensionCalled); + assert.isTrue(isExtensionInstallCalled); }); }); describe("when manually setup option is selected", () => { - it("should fail when manually setup option is selected", async () => { - const doctorService = testInjector.resolve("doctorService"); - doctorService.canExecuteLocalBuild = () => false; - - const prompter = testInjector.resolve("prompter"); - prompter.promptForChoice = () => PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME; + beforeEach(() => { + mockDoctorService({ canExecuteLocalBuild: false }); + mockPrompter({ firstCallOptionName: PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME }); + }); + it("should fail when nativescript-cloud extension is installed", async () => { + mockNativescriptCloudExtensionService({ isInstalled: true }); + await assert.isRejected(platformEnvironmentRequirements.checkEnvironmentRequirements(platform), manuallySetupErrorMessage); + }); + it("should fail when nativescript-cloud extension is not installed", async () => { + mockNativescriptCloudExtensionService({ isInstalled: false }); await assert.isRejected(platformEnvironmentRequirements.checkEnvironmentRequirements(platform), manuallySetupErrorMessage); }); }); - describe("when console is not interactive", () => { - it("should fail when console is not interactive", async () => { + describe("when console is non interactive", () => { + beforeEach(() => { process.stdout.isTTY = false; process.stdin.isTTY = false; + mockDoctorService({ canExecuteLocalBuild: false }); + }); - const doctorService = testInjector.resolve("doctorService"); - doctorService.canExecuteLocalBuild = () => false; - - await assert.isRejected(platformEnvironmentRequirements.checkEnvironmentRequirements(platform), nonInteractiveConsoleErrorMessage); + it("should fail when nativescript-cloud extension is installed", async () => { + mockNativescriptCloudExtensionService({ isInstalled: true }); + await assert.isRejected(platformEnvironmentRequirements.checkEnvironmentRequirements(platform), nonInteractiveConsoleMessageWhenExtensionIsInstalled); + }); + it("should fail when nativescript-cloud extension is not installed", async () => { + mockNativescriptCloudExtensionService({ isInstalled: false }); + await assert.isRejected(platformEnvironmentRequirements.checkEnvironmentRequirements(platform), nonInteractiveConsoleMessageWhenExtensionIsNotInstalled); }); }); }); From 9940fdd3c391a416040638bef3131b2dfa399bc4 Mon Sep 17 00:00:00 2001 From: fatme Date: Thu, 29 Mar 2018 12:45:29 +0300 Subject: [PATCH 17/32] Fix PR comments --- .../nativescript-cloud-extension-service.ts | 3 +- .../platform-environment-requirements.ts | 73 +++++++++++-------- .../platform-environment-requirements.ts | 5 +- 3 files changed, 47 insertions(+), 34 deletions(-) diff --git a/lib/services/nativescript-cloud-extension-service.ts b/lib/services/nativescript-cloud-extension-service.ts index 9b6933fbd8..cc355388e2 100644 --- a/lib/services/nativescript-cloud-extension-service.ts +++ b/lib/services/nativescript-cloud-extension-service.ts @@ -29,8 +29,7 @@ export class NativescriptCloudExtensionService implements INativescriptCloudExte } private getExtensionData(): IExtensionData { - return this.$extensibilityService.getInstalledExtensionsData() - .find(extensionData => extensionData.extensionName === constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME); + return _.find(this.$extensibilityService.getInstalledExtensionsData(), extensionData => extensionData.extensionName === constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME); } } $injector.register("nativescriptCloudExtensionService", NativescriptCloudExtensionService); diff --git a/lib/services/platform-environment-requirements.ts b/lib/services/platform-environment-requirements.ts index d6ecedfbbf..1ac40617b4 100644 --- a/lib/services/platform-environment-requirements.ts +++ b/lib/services/platform-environment-requirements.ts @@ -15,10 +15,11 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ public static LOCAL_SETUP_OPTION_NAME = "Configure for Local Builds"; public static MANUALLY_SETUP_OPTION_NAME = "Skip Step and Configure Manually"; private static BOTH_CLOUD_SETUP_AND_LOCAL_SETUP_OPTION_NAME = "Configure for Both Local and Cloud Builds"; - private static NOT_CONFIGURED_ENV_MESSAGE = "To continue, choose one of the following options: "; - private static NOT_CONFIGURED_ENV_AFTER_SETUP_SCRIPT_MESSAGE = "The setup script was not able to configure your environment for local builds. To execute local builds, you have to set up your environment manually. In case you have any issues, you can ask in our forum. To continue, choose one of the following options:"; - private static MISSING_LOCAL_AND_CLOUD_SETUP_MESSAGE = `You are missing the ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension and you will not be able to execute cloud builds. Your environment is not configured properly and you will not be able to execute local builds. To continue, choose one of the following options: `; - private static MISSING_LOCAL_SETUP_MESSAGE = 'Your environment is not configured properly and you will not be able to execute local builds.'; + private static CHOOSE_OPTIONS_MESSAGE = "To continue, choose one of the following options: "; + private static NOT_CONFIGURED_ENV_AFTER_SETUP_SCRIPT_MESSAGE = `The setup script was not able to configure your environment for local builds. To execute local builds, you have to set up your environment manually. In case you have any questions, you can check our forum: 'http://forum.nativescript.org' and our public Slack channel: 'https://nativescriptcommunity.slack.com/'. ${PlatformEnvironmentRequirements.CHOOSE_OPTIONS_MESSAGE}`; + private static MISSING_LOCAL_SETUP_MESSAGE = "Your environment is not configured properly and you will not be able to execute local builds."; + private static MISSING_LOCAL_AND_CLOUD_SETUP_MESSAGE = `You are missing the ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension and you will not be able to execute cloud builds. ${PlatformEnvironmentRequirements.MISSING_LOCAL_SETUP_MESSAGE} ${PlatformEnvironmentRequirements.CHOOSE_OPTIONS_MESSAGE} `; + private static RUN_TNS_SETUP_MESSAGE = 'Run $ tns setup command to run the setup script to try to automatically configure your environment for local builds.'; private cliCommandToCloudCommandName: IStringDictionary = { "build": "tns cloud build", @@ -131,34 +132,38 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ } private getNonInteractiveConsoleMessage(platform: string) { - if (this.$nativescriptCloudExtensionService.isInstalled()) { - return `${PlatformEnvironmentRequirements.MISSING_LOCAL_SETUP_MESSAGE} To continue, choose one of the following options: ` + EOL - + "Run $ tns setup command to run the setup script to try to automatically configure your environment for local builds." + EOL - + `${this.getCloudBuildsMessage(platform)}` + EOL - + `Verify that your environment is configured according to the system requirements described at ${this.$staticConfig.SYS_REQUIREMENTS_LINK}.`; - } - - return `${PlatformEnvironmentRequirements.MISSING_LOCAL_AND_CLOUD_SETUP_MESSAGE}` + EOL - + "Run $ tns setup command to run the setup script to try to automatically configure your environment for local builds." + EOL - + `Run $ tns cloud setup command to install the ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension to configure your environment for cloud builds.` + EOL - + `Verify that your environment is configured according to the system requirements described at ${this.$staticConfig.SYS_REQUIREMENTS_LINK}.`; + return this.$nativescriptCloudExtensionService.isInstalled() ? + this.buildMultilineMessage([ + `${PlatformEnvironmentRequirements.MISSING_LOCAL_SETUP_MESSAGE} ${PlatformEnvironmentRequirements.CHOOSE_OPTIONS_MESSAGE}`, + PlatformEnvironmentRequirements.RUN_TNS_SETUP_MESSAGE, + this.getCloudBuildsMessage(platform), + this.getEnvVerificationMessage() + ]) : + this.buildMultilineMessage([ + PlatformEnvironmentRequirements.MISSING_LOCAL_AND_CLOUD_SETUP_MESSAGE, + PlatformEnvironmentRequirements.RUN_TNS_SETUP_MESSAGE, + `Run $ tns cloud setup command to install the ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension to configure your environment for cloud builds.`, + this.getEnvVerificationMessage() + ]); } private getInteractiveConsoleMessage(platform: string) { - if (this.$nativescriptCloudExtensionService.isInstalled()) { - const message = `The ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension is installed and you can ${_.lowerFirst(this.getCloudBuildsMessage(platform))}`; - - return `${message.bold}` + EOL - + `${PlatformEnvironmentRequirements.MISSING_LOCAL_SETUP_MESSAGE} To continue, choose one of the following options: ` + EOL - + `Select "Configure for Local Builds" to run the setup script and automatically configure your environment for local builds.` + EOL - + `Select "Skip Step and Configure Manually" to disregard this option and install any required components manually.`; - } - - return `${PlatformEnvironmentRequirements.MISSING_LOCAL_AND_CLOUD_SETUP_MESSAGE}` + EOL - + `Select "Configure for Cloud Builds" to install the ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension and automatically configure your environment for cloud builds.` + EOL - + `Select "Configure for Local Builds" to run the setup script and automatically configure your environment for local builds.` - + `Select "Configure for Both Local and Cloud Builds" to automatically configure your environment for both options.` - + `Select "Skip Step and Configure Manually" to disregard these options and install any required components manually.`; + const message = `The ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension is installed and you can ${_.lowerFirst(this.getCloudBuildsMessage(platform))}`; + + return this.$nativescriptCloudExtensionService.isInstalled() ? + this.buildMultilineMessage([ + `${message.bold}`, + `${PlatformEnvironmentRequirements.MISSING_LOCAL_SETUP_MESSAGE} ${PlatformEnvironmentRequirements.CHOOSE_OPTIONS_MESSAGE}`, + `Select "Configure for Local Builds" to run the setup script and automatically configure your environment for local builds.`, + `Select "Skip Step and Configure Manually" to disregard this option and install any required components manually.` + ]) : + this.buildMultilineMessage([ + PlatformEnvironmentRequirements.MISSING_LOCAL_AND_CLOUD_SETUP_MESSAGE, + `Select "Configure for Cloud Builds" to install the ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension and automatically configure your environment for cloud builds.`, + `Select "Configure for Local Builds" to run the setup script and automatically configure your environment for local builds.`, + `Select "Configure for Both Local and Cloud Builds" to automatically configure your environment for both options.`, + `Select "Configure for Both Local and Cloud Builds" to automatically configure your environment for both options.` + ]); } private promptForChoice(): Promise { @@ -172,7 +177,15 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME, ]; - return this.$prompter.promptForChoice(PlatformEnvironmentRequirements.NOT_CONFIGURED_ENV_MESSAGE, choices); + return this.$prompter.promptForChoice(PlatformEnvironmentRequirements.CHOOSE_OPTIONS_MESSAGE, choices); + } + + private getEnvVerificationMessage() { + return `Verify that your environment is configured according to the system requirements described at ${this.$staticConfig.SYS_REQUIREMENTS_LINK}.`; + } + + private buildMultilineMessage(parts: string[]): string { + return parts.join(EOL); } } $injector.register("platformEnvironmentRequirements", PlatformEnvironmentRequirements); diff --git a/test/services/platform-environment-requirements.ts b/test/services/platform-environment-requirements.ts index 83133a6562..31417a2f11 100644 --- a/test/services/platform-environment-requirements.ts +++ b/test/services/platform-environment-requirements.ts @@ -2,12 +2,13 @@ import { Yok } from "../../lib/common/yok"; import { PlatformEnvironmentRequirements } from '../../lib/services/platform-environment-requirements'; import * as stubs from "../stubs"; import { assert } from "chai"; +import { EOL } from "os"; const platform = "android"; const cloudBuildsErrorMessage = `In order to test your application use the $ tns login command to log in with your account and then $ tns cloud build command to build your app in the cloud.`; const manuallySetupErrorMessage = `To be able to build for ${platform}, verify that your environment is configured according to the system requirements described at `; -const nonInteractiveConsoleMessageWhenExtensionIsNotInstalled = `You are missing the nativescript-cloud extension and you will not be able to execute cloud builds. Your environment is not configured properly and you will not be able to execute local builds. To continue, choose one of the following options: \nRun $ tns setup command to run the setup script to try to automatically configure your environment for local builds.\nRun $ tns cloud setup command to install the nativescript-cloud extension to configure your environment for cloud builds.\nVerify that your environment is configured according to the system requirements described at `; -const nonInteractiveConsoleMessageWhenExtensionIsInstalled = `Your environment is not configured properly and you will not be able to execute local builds. To continue, choose one of the following options: \nRun $ tns setup command to run the setup script to try to automatically configure your environment for local builds.\nIn order to test your application use the $ tns login command to log in with your account and then $ tns cloud build command to build your app in the cloud.\nVerify that your environment is configured according to the system requirements described at .`; +const nonInteractiveConsoleMessageWhenExtensionIsNotInstalled = `You are missing the nativescript-cloud extension and you will not be able to execute cloud builds. Your environment is not configured properly and you will not be able to execute local builds. To continue, choose one of the following options: ${EOL}Run $ tns setup command to run the setup script to try to automatically configure your environment for local builds.${EOL}Run $ tns cloud setup command to install the nativescript-cloud extension to configure your environment for cloud builds.${EOL}Verify that your environment is configured according to the system requirements described at `; +const nonInteractiveConsoleMessageWhenExtensionIsInstalled = `Your environment is not configured properly and you will not be able to execute local builds. To continue, choose one of the following options: ${EOL}Run $ tns setup command to run the setup script to try to automatically configure your environment for local builds.${EOL}In order to test your application use the $ tns login command to log in with your account and then $ tns cloud build command to build your app in the cloud.${EOL}Verify that your environment is configured according to the system requirements described at .`; function createTestInjector() { const testInjector = new Yok(); From dfa2df03336a1dbdb916f9279820a0f361fb5028 Mon Sep 17 00:00:00 2001 From: Kristian Dimitrov Date: Fri, 23 Mar 2018 19:31:07 +0200 Subject: [PATCH 18/32] fix(AppResources): try recover if resources update fails --- .../android-resources-migration-service.ts | 37 +++++++++++++++++-- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/lib/services/android-resources-migration-service.ts b/lib/services/android-resources-migration-service.ts index 612fe07558..2aac57b327 100644 --- a/lib/services/android-resources-migration-service.ts +++ b/lib/services/android-resources-migration-service.ts @@ -1,6 +1,6 @@ import * as path from "path"; -import * as shell from "shelljs"; import * as constants from "../constants"; +import { EOL } from "os"; export class AndroidResourcesMigrationService implements IAndroidResourcesMigrationService { private static ANDROID_DIR = "Android"; @@ -8,6 +8,7 @@ export class AndroidResourcesMigrationService implements IAndroidResourcesMigrat private static ANDROID_DIR_OLD = "Android-Pre-v4"; constructor(private $fs: IFileSystem, + private $errors: IErrors, private $logger: ILogger, private $devicePlatformsConstants: Mobile.IDevicePlatformsConstants) { } @@ -22,6 +23,25 @@ export class AndroidResourcesMigrationService implements IAndroidResourcesMigrat public async migrate(appResourcesDir: string): Promise { const originalAppResources = path.join(appResourcesDir, AndroidResourcesMigrationService.ANDROID_DIR); const appResourcesDestination = path.join(appResourcesDir, AndroidResourcesMigrationService.ANDROID_DIR_TEMP); + const appResourcesBackup = path.join(appResourcesDir, AndroidResourcesMigrationService.ANDROID_DIR_OLD); + + try { + await this.tryMigrate(originalAppResources, appResourcesDestination, appResourcesBackup); + this.$logger.out(`Successfully updated your project's application resources '/Android' directory structure.${EOL}The previous version of your Android application resources has been renamed to '/${AndroidResourcesMigrationService.ANDROID_DIR_OLD}'`); + } catch (error) { + try { + this.recover(originalAppResources, appResourcesDestination, appResourcesBackup); + this.$logger.out("Failed to update resources. They should be in their initial state."); + } catch (err) { + this.$logger.trace(err); + this.$logger.out(`Failed to update resources.${EOL} Backup of original content is inside "${appResourcesBackup}".${EOL}If "${originalAppResources} is missing copy from backup folder."`); + } finally { + this.$errors.failWithoutHelp(error.message); + } + } + } + + private async tryMigrate(originalAppResources: string, appResourcesDestination: string, appResourcesBackup: string): Promise { const appMainSourceSet = path.join(appResourcesDestination, constants.SRC_DIR, constants.MAIN_DIR); const appResourcesMainSourceSetResourcesDestination = path.join(appMainSourceSet, constants.RESOURCES_DIR); @@ -64,11 +84,20 @@ export class AndroidResourcesMigrationService implements IAndroidResourcesMigrat this.$fs.copyFile(path.join(originalAppResources, constants.MANIFEST_FILE_NAME), path.join(appMainSourceSet, constants.MANIFEST_FILE_NAME)); // rename the legacy app_resources to ANDROID_DIR_OLD - shell.mv(originalAppResources, path.join(appResourcesDir, AndroidResourcesMigrationService.ANDROID_DIR_OLD)); + this.$fs.rename(originalAppResources, appResourcesBackup); + // move the new, updated app_resources to App_Resources/Android, as the de facto resources - shell.mv(appResourcesDestination, originalAppResources); + this.$fs.rename(appResourcesDestination, originalAppResources); + } + + private recover(originalAppResources: string, appResourcesDestination: string, appResourcesBackup: string): void { + if (!this.$fs.exists(originalAppResources)) { + this.$fs.rename(appResourcesBackup, originalAppResources); + } - this.$logger.out(`Successfully updated your project's application resources '/Android' directory structure.\nThe previous version of your Android application resources has been renamed to '/${AndroidResourcesMigrationService.ANDROID_DIR_OLD}'`); + if (this.$fs.exists(appResourcesDestination)) { + this.$fs.deleteDirectory(appResourcesDestination); + } } } From 50bbfb62582cccaa99d489e2afe13db29458d396 Mon Sep 17 00:00:00 2001 From: fatme Date: Mon, 2 Apr 2018 09:23:14 +0300 Subject: [PATCH 19/32] Rename nativescript to nativeScript --- lib/bootstrap.ts | 2 +- lib/commands/setup.ts | 4 +-- lib/declarations.d.ts | 2 +- .../nativescript-cloud-extension-service.ts | 4 +-- .../platform-environment-requirements.ts | 12 ++++---- .../platform-environment-requirements.ts | 30 +++++++++---------- 6 files changed, 27 insertions(+), 27 deletions(-) diff --git a/lib/bootstrap.ts b/lib/bootstrap.ts index d1e532459f..9f4bb2094d 100644 --- a/lib/bootstrap.ts +++ b/lib/bootstrap.ts @@ -160,7 +160,7 @@ $injector.require("terminalSpinnerService", "./services/terminal-spinner-service $injector.require('playgroundService', './services/playground-service'); $injector.require("platformEnvironmentRequirements", "./services/platform-environment-requirements"); -$injector.require("nativescriptCloudExtensionService", "./services/nativescript-cloud-extension-service"); +$injector.require("nativeScriptCloudExtensionService", "./services/nativescript-cloud-extension-service"); $injector.requireCommand("resources|generate|icons", "./commands/generate-assets"); $injector.requireCommand("resources|generate|splashes", "./commands/generate-assets"); diff --git a/lib/commands/setup.ts b/lib/commands/setup.ts index 928582fb3e..cfddc687a7 100644 --- a/lib/commands/setup.ts +++ b/lib/commands/setup.ts @@ -12,10 +12,10 @@ $injector.registerCommand("setup|*", SetupCommand); export class CloudSetupCommand implements ICommand { public allowedParameters: ICommandParameter[] = []; - constructor(private $nativescriptCloudExtensionService: INativescriptCloudExtensionService) { } + constructor(private $nativeScriptCloudExtensionService: INativeScriptCloudExtensionService) { } public execute(args: string[]): Promise { - return this.$nativescriptCloudExtensionService.install(); + return this.$nativeScriptCloudExtensionService.install(); } } $injector.registerCommand(["setup|cloud", "cloud|setup"], CloudSetupCommand); diff --git a/lib/declarations.d.ts b/lib/declarations.d.ts index 4be5e13ea3..ae5637ae1d 100644 --- a/lib/declarations.d.ts +++ b/lib/declarations.d.ts @@ -788,7 +788,7 @@ interface IBundleValidatorHelper { validate(): void; } -interface INativescriptCloudExtensionService { +interface INativeScriptCloudExtensionService { /** * Installs nativescript-cloud extension * @return {Promise} returns the extension data diff --git a/lib/services/nativescript-cloud-extension-service.ts b/lib/services/nativescript-cloud-extension-service.ts index cc355388e2..8b6a0f5889 100644 --- a/lib/services/nativescript-cloud-extension-service.ts +++ b/lib/services/nativescript-cloud-extension-service.ts @@ -1,7 +1,7 @@ import * as constants from "../constants"; import * as semver from "semver"; -export class NativescriptCloudExtensionService implements INativescriptCloudExtensionService { +export class NativeScriptCloudExtensionService implements INativeScriptCloudExtensionService { constructor(private $extensibilityService: IExtensibilityService, private $logger: ILogger, private $npmInstallationManager: INpmInstallationManager) { } @@ -32,4 +32,4 @@ export class NativescriptCloudExtensionService implements INativescriptCloudExte return _.find(this.$extensibilityService.getInstalledExtensionsData(), extensionData => extensionData.extensionName === constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME); } } -$injector.register("nativescriptCloudExtensionService", NativescriptCloudExtensionService); +$injector.register("nativeScriptCloudExtensionService", NativeScriptCloudExtensionService); diff --git a/lib/services/platform-environment-requirements.ts b/lib/services/platform-environment-requirements.ts index 1ac40617b4..0eba53eb58 100644 --- a/lib/services/platform-environment-requirements.ts +++ b/lib/services/platform-environment-requirements.ts @@ -7,7 +7,7 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ private $doctorService: IDoctorService, private $errors: IErrors, private $logger: ILogger, - private $nativescriptCloudExtensionService: INativescriptCloudExtensionService, + private $nativeScriptCloudExtensionService: INativeScriptCloudExtensionService, private $prompter: IPrompter, private $staticConfig: IStaticConfig) { } @@ -52,7 +52,7 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ return true; } - if (this.$nativescriptCloudExtensionService.isInstalled()) { + if (this.$nativeScriptCloudExtensionService.isInstalled()) { this.processManuallySetup(platform); } else { const option = await this.$prompter.promptForChoice(PlatformEnvironmentRequirements.NOT_CONFIGURED_ENV_AFTER_SETUP_SCRIPT_MESSAGE, [ @@ -91,7 +91,7 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ } private processCloudBuildsCore(platform: string): Promise { - return this.$nativescriptCloudExtensionService.install(); + return this.$nativeScriptCloudExtensionService.install(); } private getCloudBuildsMessage(platform: string): string { @@ -132,7 +132,7 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ } private getNonInteractiveConsoleMessage(platform: string) { - return this.$nativescriptCloudExtensionService.isInstalled() ? + return this.$nativeScriptCloudExtensionService.isInstalled() ? this.buildMultilineMessage([ `${PlatformEnvironmentRequirements.MISSING_LOCAL_SETUP_MESSAGE} ${PlatformEnvironmentRequirements.CHOOSE_OPTIONS_MESSAGE}`, PlatformEnvironmentRequirements.RUN_TNS_SETUP_MESSAGE, @@ -150,7 +150,7 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ private getInteractiveConsoleMessage(platform: string) { const message = `The ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension is installed and you can ${_.lowerFirst(this.getCloudBuildsMessage(platform))}`; - return this.$nativescriptCloudExtensionService.isInstalled() ? + return this.$nativeScriptCloudExtensionService.isInstalled() ? this.buildMultilineMessage([ `${message.bold}`, `${PlatformEnvironmentRequirements.MISSING_LOCAL_SETUP_MESSAGE} ${PlatformEnvironmentRequirements.CHOOSE_OPTIONS_MESSAGE}`, @@ -167,7 +167,7 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ } private promptForChoice(): Promise { - const choices = this.$nativescriptCloudExtensionService.isInstalled() ? [ + const choices = this.$nativeScriptCloudExtensionService.isInstalled() ? [ PlatformEnvironmentRequirements.LOCAL_SETUP_OPTION_NAME, PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME, ] : [ diff --git a/test/services/platform-environment-requirements.ts b/test/services/platform-environment-requirements.ts index 31417a2f11..abb8bb76ee 100644 --- a/test/services/platform-environment-requirements.ts +++ b/test/services/platform-environment-requirements.ts @@ -24,7 +24,7 @@ function createTestInjector() { testInjector.register("prompter", {}); testInjector.register("platformEnvironmentRequirements", PlatformEnvironmentRequirements); testInjector.register("staticConfig", { SYS_REQUIREMENTS_LINK: "" }); - testInjector.register("nativescriptCloudExtensionService", {}); + testInjector.register("nativeScriptCloudExtensionService", {}); return testInjector; } @@ -59,10 +59,10 @@ describe("platformEnvironmentRequirements ", () => { }; } - function mockNativescriptCloudExtensionService(data: {isInstalled: boolean}) { - const nativescriptCloudExtensionService = testInjector.resolve("nativescriptCloudExtensionService"); - nativescriptCloudExtensionService.isInstalled = () => data.isInstalled; - nativescriptCloudExtensionService.install = () => { isExtensionInstallCalled = true; }; + function mockNativeScriptCloudExtensionService(data: {isInstalled: boolean}) { + const nativeScriptCloudExtensionService = testInjector.resolve("nativeScriptCloudExtensionService"); + nativeScriptCloudExtensionService.isInstalled = () => data.isInstalled; + nativeScriptCloudExtensionService.install = () => { isExtensionInstallCalled = true; }; } beforeEach(() => { @@ -87,7 +87,7 @@ describe("platformEnvironmentRequirements ", () => { it("should show prompt when environment is not configured and nativescript-cloud extension is not installed", async () => { mockDoctorService({ canExecuteLocalBuild: false }); mockPrompter({ firstCallOptionName: PlatformEnvironmentRequirements.CLOUD_SETUP_OPTION_NAME }); - mockNativescriptCloudExtensionService({ isInstalled: false }); + mockNativeScriptCloudExtensionService({ isInstalled: false }); await assert.isRejected(platformEnvironmentRequirements.checkEnvironmentRequirements(platform)); assert.isTrue(promptForChoiceData.length === 1); @@ -98,7 +98,7 @@ describe("platformEnvironmentRequirements ", () => { it("should show prompt when environment is not configured and nativescript-cloud extension is installed", async () => { mockDoctorService({ canExecuteLocalBuild: false }); mockPrompter({ firstCallOptionName: PlatformEnvironmentRequirements.CLOUD_SETUP_OPTION_NAME }); - mockNativescriptCloudExtensionService({ isInstalled: true }); + mockNativeScriptCloudExtensionService({ isInstalled: true }); await assert.isRejected(platformEnvironmentRequirements.checkEnvironmentRequirements(platform)); assert.isTrue(promptForChoiceData.length === 1); @@ -123,7 +123,7 @@ describe("platformEnvironmentRequirements ", () => { doctorService.canExecuteLocalBuild = () => false; doctorService.runSetupScript = async () => { doctorService.canExecuteLocalBuild = () => true; }; - mockNativescriptCloudExtensionService({ isInstalled: null }); + mockNativeScriptCloudExtensionService({ isInstalled: null }); assert.isTrue(await platformEnvironmentRequirements.checkEnvironmentRequirements(platform)); }); @@ -132,14 +132,14 @@ describe("platformEnvironmentRequirements ", () => { it("should setup manually when cloud extension is installed", async () => { mockDoctorService( { canExecuteLocalBuild: false, mockSetupScript: true }); mockPrompter({ firstCallOptionName: PlatformEnvironmentRequirements.LOCAL_SETUP_OPTION_NAME, secondCallOptionName: PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME }); - mockNativescriptCloudExtensionService({ isInstalled: true }); + mockNativeScriptCloudExtensionService({ isInstalled: true }); await assert.isRejected(platformEnvironmentRequirements.checkEnvironmentRequirements(platform), manuallySetupErrorMessage); }); describe("and cloud extension is not installed", () => { beforeEach(() => { mockDoctorService({ canExecuteLocalBuild: false, mockSetupScript: true }); - mockNativescriptCloudExtensionService({ isInstalled: false }); + mockNativeScriptCloudExtensionService({ isInstalled: false }); }); it("should list 2 posibile options to select", async () => { mockPrompter({ firstCallOptionName: PlatformEnvironmentRequirements.LOCAL_SETUP_OPTION_NAME }); @@ -168,7 +168,7 @@ describe("platformEnvironmentRequirements ", () => { }); it("should install nativescript-cloud extension when it is not installed", async () => { - mockNativescriptCloudExtensionService({ isInstalled: false }); + mockNativeScriptCloudExtensionService({ isInstalled: false }); await assert.isRejected(platformEnvironmentRequirements.checkEnvironmentRequirements(platform), cloudBuildsErrorMessage); assert.isTrue(isExtensionInstallCalled); }); @@ -181,11 +181,11 @@ describe("platformEnvironmentRequirements ", () => { }); it("should fail when nativescript-cloud extension is installed", async () => { - mockNativescriptCloudExtensionService({ isInstalled: true }); + mockNativeScriptCloudExtensionService({ isInstalled: true }); await assert.isRejected(platformEnvironmentRequirements.checkEnvironmentRequirements(platform), manuallySetupErrorMessage); }); it("should fail when nativescript-cloud extension is not installed", async () => { - mockNativescriptCloudExtensionService({ isInstalled: false }); + mockNativeScriptCloudExtensionService({ isInstalled: false }); await assert.isRejected(platformEnvironmentRequirements.checkEnvironmentRequirements(platform), manuallySetupErrorMessage); }); }); @@ -198,11 +198,11 @@ describe("platformEnvironmentRequirements ", () => { }); it("should fail when nativescript-cloud extension is installed", async () => { - mockNativescriptCloudExtensionService({ isInstalled: true }); + mockNativeScriptCloudExtensionService({ isInstalled: true }); await assert.isRejected(platformEnvironmentRequirements.checkEnvironmentRequirements(platform), nonInteractiveConsoleMessageWhenExtensionIsInstalled); }); it("should fail when nativescript-cloud extension is not installed", async () => { - mockNativescriptCloudExtensionService({ isInstalled: false }); + mockNativeScriptCloudExtensionService({ isInstalled: false }); await assert.isRejected(platformEnvironmentRequirements.checkEnvironmentRequirements(platform), nonInteractiveConsoleMessageWhenExtensionIsNotInstalled); }); }); From 483eaee7dc7fa2eb76362df5dfb1258064ec7f21 Mon Sep 17 00:00:00 2001 From: tdermendjiev Date: Fri, 23 Mar 2018 16:06:19 +0200 Subject: [PATCH 20/32] fix: Add recursive module resolution --- lib/tools/node-modules/node-modules-dependencies-builder.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/tools/node-modules/node-modules-dependencies-builder.ts b/lib/tools/node-modules/node-modules-dependencies-builder.ts index f2482819b5..ac0eef9e57 100644 --- a/lib/tools/node-modules/node-modules-dependencies-builder.ts +++ b/lib/tools/node-modules/node-modules-dependencies-builder.ts @@ -43,6 +43,10 @@ export class NodeModulesDependenciesBuilder implements INodeModulesDependenciesB } }); + _.each(this.getProductionDependencies(resolvedDependency.directory), d => { + resolvedDependencies.push(d); + }); + resolvedDependencies.push(resolvedDependency); } } From f1f8a43abf8e4805eca4d4ffc980bdecde513f9e Mon Sep 17 00:00:00 2001 From: tdermendjiev Date: Fri, 23 Mar 2018 17:25:46 +0200 Subject: [PATCH 21/32] style: Remove whitespaces --- lib/tools/node-modules/node-modules-dependencies-builder.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/tools/node-modules/node-modules-dependencies-builder.ts b/lib/tools/node-modules/node-modules-dependencies-builder.ts index ac0eef9e57..aca21be89e 100644 --- a/lib/tools/node-modules/node-modules-dependencies-builder.ts +++ b/lib/tools/node-modules/node-modules-dependencies-builder.ts @@ -46,7 +46,6 @@ export class NodeModulesDependenciesBuilder implements INodeModulesDependenciesB _.each(this.getProductionDependencies(resolvedDependency.directory), d => { resolvedDependencies.push(d); }); - resolvedDependencies.push(resolvedDependency); } } From 93a693b9a0fa928274c2e78d2257f5c47d06793a Mon Sep 17 00:00:00 2001 From: Teodor Dermendzhiev Date: Tue, 27 Mar 2018 16:03:29 +0300 Subject: [PATCH 22/32] fix: Update findModule function to search through all parents for module --- .../node-modules-dependencies-builder.ts | 42 ++++++++++++------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/lib/tools/node-modules/node-modules-dependencies-builder.ts b/lib/tools/node-modules/node-modules-dependencies-builder.ts index aca21be89e..51975b2df7 100644 --- a/lib/tools/node-modules/node-modules-dependencies-builder.ts +++ b/lib/tools/node-modules/node-modules-dependencies-builder.ts @@ -2,6 +2,7 @@ import * as path from "path"; import { NODE_MODULES_FOLDER_NAME, PACKAGE_JSON_FILE_NAME } from "../../constants"; interface IDependencyDescription { + parent: IDependencyDescription; parentDir: string; name: string; depth: number; @@ -20,6 +21,7 @@ export class NodeModulesDependenciesBuilder implements INodeModulesDependenciesB const queue: IDependencyDescription[] = _.keys(dependencies) .map(dependencyName => ({ + parent: null, parentDir: projectPath, name: dependencyName, depth: 0 @@ -27,13 +29,14 @@ export class NodeModulesDependenciesBuilder implements INodeModulesDependenciesB while (queue.length) { const currentModule = queue.shift(); - const resolvedDependency = this.findModule(rootNodeModulesPath, currentModule.parentDir, currentModule.name, currentModule.depth, resolvedDependencies); + const resolvedDependency = this.findModule(rootNodeModulesPath, currentModule, resolvedDependencies); if (resolvedDependency && !_.some(resolvedDependencies, r => r.directory === resolvedDependency.directory)) { _.each(resolvedDependency.dependencies, d => { - const dependency: IDependencyDescription = { name: d, parentDir: resolvedDependency.directory, depth: resolvedDependency.depth + 1 }; + const dependency: IDependencyDescription = { parent: currentModule, name: d, parentDir: resolvedDependency.directory, depth: resolvedDependency.depth + 1 }; const shouldAdd = !_.some(queue, element => + element.parent == dependency.parent && element.name === dependency.name && element.parentDir === dependency.parentDir && element.depth === dependency.depth); @@ -43,9 +46,6 @@ export class NodeModulesDependenciesBuilder implements INodeModulesDependenciesB } }); - _.each(this.getProductionDependencies(resolvedDependency.directory), d => { - resolvedDependencies.push(d); - }); resolvedDependencies.push(resolvedDependency); } } @@ -53,26 +53,40 @@ export class NodeModulesDependenciesBuilder implements INodeModulesDependenciesB return resolvedDependencies; } - private findModule(rootNodeModulesPath: string, parentModulePath: string, name: string, depth: number, resolvedDependencies: IDependencyData[]): IDependencyData { - let modulePath = path.join(parentModulePath, NODE_MODULES_FOLDER_NAME, name); // node_modules/parent/node_modules/ - const rootModulesPath = path.join(rootNodeModulesPath, name); - let depthInNodeModules = depth; + private findModule(rootNodeModulesPath: string, depDescription: IDependencyDescription, resolvedDependencies: IDependencyData[]): IDependencyData { + let modulePath = path.join(depDescription.parentDir, NODE_MODULES_FOLDER_NAME, depDescription.name); // node_modules/parent/node_modules/ + const rootModulesPath = path.join(rootNodeModulesPath, depDescription.name); + let depthInNodeModules = depDescription.depth; if (!this.moduleExists(modulePath)) { - modulePath = rootModulesPath; // /node_modules/ - if (!this.moduleExists(modulePath)) { - return null; + + let moduleExists = false; + let parent = depDescription.parent; + + while(parent && !moduleExists) { + modulePath = path.join(depDescription.parent.parentDir, NODE_MODULES_FOLDER_NAME, depDescription.name); + moduleExists = this.moduleExists(modulePath); + if (!moduleExists) { + parent = parent.parent; + } } + if (!moduleExists) { + modulePath = rootModulesPath; // /node_modules/ + if (!this.moduleExists(modulePath)) { + return null; + } + } + depthInNodeModules = 0; } - if (_.some(resolvedDependencies, r => r.name === name && r.directory === modulePath)) { + if (_.some(resolvedDependencies, r => r.name === depDescription.name && r.directory === modulePath)) { return null; } - return this.getDependencyData(name, modulePath, depthInNodeModules); + return this.getDependencyData(depDescription.name, modulePath, depthInNodeModules); } private getDependencyData(name: string, directory: string, depth: number): IDependencyData { From e31790a9ba78246aa283a8f4646021734a379cf8 Mon Sep 17 00:00:00 2001 From: Teodor Dermendzhiev Date: Tue, 27 Mar 2018 16:43:14 +0300 Subject: [PATCH 23/32] style: Fix lint errors --- lib/tools/node-modules/node-modules-dependencies-builder.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/tools/node-modules/node-modules-dependencies-builder.ts b/lib/tools/node-modules/node-modules-dependencies-builder.ts index 51975b2df7..53dd1bcfb1 100644 --- a/lib/tools/node-modules/node-modules-dependencies-builder.ts +++ b/lib/tools/node-modules/node-modules-dependencies-builder.ts @@ -36,7 +36,7 @@ export class NodeModulesDependenciesBuilder implements INodeModulesDependenciesB const dependency: IDependencyDescription = { parent: currentModule, name: d, parentDir: resolvedDependency.directory, depth: resolvedDependency.depth + 1 }; const shouldAdd = !_.some(queue, element => - element.parent == dependency.parent && + element.parent === dependency.parent && element.name === dependency.name && element.parentDir === dependency.parentDir && element.depth === dependency.depth); @@ -63,7 +63,7 @@ export class NodeModulesDependenciesBuilder implements INodeModulesDependenciesB let moduleExists = false; let parent = depDescription.parent; - while(parent && !moduleExists) { + while (parent && !moduleExists) { modulePath = path.join(depDescription.parent.parentDir, NODE_MODULES_FOLDER_NAME, depDescription.name); moduleExists = this.moduleExists(modulePath); if (!moduleExists) { @@ -77,7 +77,7 @@ export class NodeModulesDependenciesBuilder implements INodeModulesDependenciesB return null; } } - + depthInNodeModules = 0; } From 4b479fd050bd6323911e758919322edb0fab31bc Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Tue, 3 Apr 2018 10:07:20 +0300 Subject: [PATCH 24/32] fix: Prepare for iOS with cloud builds fails on non macOS In cloud builds, when we try to prepare the project for iOS, sometimes we fail as the `cleanDestinationApp` does not pass correct arguments to `ensurePlatformInstalled` method. When we have cloud builds, the last argument should declare that the native prepartion should be skipped. When we do not pass it, the logic determines that the platform is not fully added and tries to add it again. The whole `platforms/ios` directory is deleted and then we try preparing the project again. At some point the code fails as there are missing files in the `platforms/ios` (we have deleted them). Pass the correct arguments, so the prepare will skip the native part in the mentioned case. --- lib/services/platform-service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/services/platform-service.ts b/lib/services/platform-service.ts index fa61489d05..c817cbf714 100644 --- a/lib/services/platform-service.ts +++ b/lib/services/platform-service.ts @@ -603,7 +603,7 @@ export class PlatformService extends EventEmitter implements IPlatformService { @helpers.hook('cleanApp') public async cleanDestinationApp(platformInfo: IPreparePlatformInfo): Promise { - await this.ensurePlatformInstalled(platformInfo.platform, platformInfo.platformTemplate, platformInfo.projectData, platformInfo.config); + await this.ensurePlatformInstalled(platformInfo.platform, platformInfo.platformTemplate, platformInfo.projectData, platformInfo.config, platformInfo.nativePrepare); const platformData = this.$platformsData.getPlatformData(platformInfo.platform, platformInfo.projectData); const appDestinationDirectoryPath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME); From 1d723eab36283d7362d1edd588a104b9cd0a2e67 Mon Sep 17 00:00:00 2001 From: plamen5kov Date: Tue, 3 Apr 2018 11:03:46 +0300 Subject: [PATCH 25/32] fix: pass supportVersion to plugin builds and update gradle --- vendor/gradle-plugin/build.gradle | 12 +++++++++++- .../gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/vendor/gradle-plugin/build.gradle b/vendor/gradle-plugin/build.gradle index 5171a2e3cc..3a4a89a63d 100644 --- a/vendor/gradle-plugin/build.gradle +++ b/vendor/gradle-plugin/build.gradle @@ -2,9 +2,10 @@ buildscript { repositories { jcenter() + google() } dependencies { - classpath 'com.android.tools.build:gradle:2.3.2' + classpath 'com.android.tools.build:gradle:3.0.1' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -40,3 +41,12 @@ android { versionName "1.0" } } + +dependencies { + def supportVer = "27.0.1" + if (project.hasProperty("supportVersion")) { + supportVer = supportVersion + } + compileOnly "com.android.support:support-v4:$supportVer" + compileOnly "com.android.support:appcompat-v7:$supportVer" +} diff --git a/vendor/gradle-plugin/gradle/wrapper/gradle-wrapper.properties b/vendor/gradle-plugin/gradle/wrapper/gradle-wrapper.properties index 55a7a86c65..aa471e9281 100644 --- a/vendor/gradle-plugin/gradle/wrapper/gradle-wrapper.properties +++ b/vendor/gradle-plugin/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-bin.zip From 72c92c5af5903dbacc3c23ab42c7b451be48c5fd Mon Sep 17 00:00:00 2001 From: plamen5kov Date: Tue, 3 Apr 2018 11:26:51 +0300 Subject: [PATCH 26/32] fix: cli passes support version to plugin builds --- lib/services/android-plugin-build-service.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/services/android-plugin-build-service.ts b/lib/services/android-plugin-build-service.ts index 2a5ac66f87..3e71fd57d1 100644 --- a/lib/services/android-plugin-build-service.ts +++ b/lib/services/android-plugin-build-service.ts @@ -253,9 +253,11 @@ export class AndroidPluginBuildService implements IAndroidPluginBuildService { const androidToolsInfo = this.$androidToolsInfo.getToolsInfo(); const compileSdk = androidToolsInfo.compileSdkVersion; const buildToolsVersion = androidToolsInfo.buildToolsVersion; + const supportVersion = androidToolsInfo.supportRepositoryVersion; localArgs.push(`-PcompileSdk=android-${compileSdk}`); localArgs.push(`-PbuildToolsVersion=${buildToolsVersion}`); + localArgs.push(`-PsupportVersion=${supportVersion}`); try { await this.$childProcess.exec(localArgs.join(" "), { cwd: newPluginDir }); From eb580f2034adcc9141de7e32ab1b9f6be318dbfb Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Tue, 3 Apr 2018 12:47:18 +0300 Subject: [PATCH 27/32] fix: Incorrect error is shown when xcrun simctl is not configured In case `xcrun simctl` throws some error, CLI does not handle it very well. Improve the logic in ios-sim-portable and update its version in order to resolve the issue. --- npm-shrinkwrap.json | 90 ++++++++++++++++++++++----------------------- package.json | 2 +- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 14929f16b0..c8aef1b315 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -31,7 +31,7 @@ "@types/color": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/color/-/color-3.0.0.tgz", - "integrity": "sha512-5qqtNia+m2I0/85+pd2YzAXaTyKO8j+svirO5aN+XaQJ5+eZ8nx0jPtEWZLxCi50xwYsX10xUHetFzfb1WEs4Q==", + "integrity": "sha1-QPimvy/YbpaYdrM5qDfY/xsKbjA=", "dev": true, "requires": { "@types/color-convert": "1.9.0" @@ -40,7 +40,7 @@ "@types/color-convert": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/@types/color-convert/-/color-convert-1.9.0.tgz", - "integrity": "sha512-OKGEfULrvSL2VRbkl/gnjjgbbF7ycIlpSsX7Nkab4MOWi5XxmgBYvuiQ7lcCFY5cPDz7MUNaKgxte2VRmtr4Fg==", + "integrity": "sha1-v6ggPkHnxlRx6YQdfjBqfNi1Fy0=", "dev": true, "requires": { "@types/color-name": "1.1.0" @@ -49,7 +49,7 @@ "@types/color-name": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.0.tgz", - "integrity": "sha512-gZ/Rb+MFXF0pXSEQxdRoPMm5jeO3TycjOdvbpbcpHX/B+n9AqaHFe5q6Ga9CsZ7ir/UgIWPfrBzUzn3F19VH/w==", + "integrity": "sha1-km929+ZvScxZrYgLsVsDCrvwtm0=", "dev": true }, "@types/form-data": { @@ -76,7 +76,7 @@ "@types/ora": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/@types/ora/-/ora-1.3.3.tgz", - "integrity": "sha512-XaSVRyCfnGq1xGlb6iuoxnomMXPIlZnvIIkKiGNMTCeVOg7G1Si+FA9N1lPrykPEfiRHwbuZXuTCSoYcHyjcdg==", + "integrity": "sha1-0xhkGMPPN6gxeZs3a+ykqOG/yi0=", "dev": true, "requires": { "@types/node": "6.0.61" @@ -110,7 +110,7 @@ "@types/sinon": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-4.0.0.tgz", - "integrity": "sha512-cuK4xM8Lg2wd8cxshcQa8RG4IK/xfyB6TNE6tNVvkrShR4xdrYgsV04q6Dp6v1Lp6biEFdzD8k8zg/ujQeiw+A==", + "integrity": "sha1-mpP/pO4TKehRZieKXtmfgdxMg2I=", "dev": true }, "@types/source-map": { @@ -128,7 +128,7 @@ "@types/xml2js": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.2.tgz", - "integrity": "sha512-8aKUBSj3oGcnuiBmDLm3BIk09RYg01mz9HlQ2u4aS17oJ25DxjQrEUVGFSBVNOfM45pQW4OjcBPplq6r/exJdA==", + "integrity": "sha1-pLhLOHn/1HEJU/2Syr/emopOhFY=", "dev": true, "requires": { "@types/node": "6.0.61" @@ -245,7 +245,7 @@ "arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + "integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE=" }, "array-find-index": { "version": "1.0.2", @@ -436,6 +436,13 @@ "stream-buffers": "2.2.0" } }, + "bplist-parser": { + "version": "https://github.com/telerik/node-bplist-parser/tarball/master", + "integrity": "sha512-B7Agq6ELA8hOERzvUhhgQPFe1Hcx6HCAtdaxHv/YS/PAUdxhxtCYzWFJ3zDfGIWXT1X2Nt2Q8lqeEASKoY3Wfw==", + "requires": { + "big-integer": "1.6.23" + } + }, "brace-expansion": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", @@ -701,7 +708,7 @@ "color": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", - "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", + "integrity": "sha1-2SC0Mo1TSjrIKV1o971LpsQnvpo=", "requires": { "color-convert": "1.9.1", "color-string": "1.5.2" @@ -710,7 +717,7 @@ "color-convert": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", - "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", + "integrity": "sha1-wSYRB66y8pTr/+ye2eytUppgl+0=", "requires": { "color-name": "1.1.3" } @@ -3067,9 +3074,9 @@ } }, "ios-sim-portable": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/ios-sim-portable/-/ios-sim-portable-3.3.0.tgz", - "integrity": "sha1-GttoCZqUoskHDY3Mh0bpWO6XFlA=", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/ios-sim-portable/-/ios-sim-portable-3.3.1.tgz", + "integrity": "sha512-4mo/RKy33jQJX+BcbgB5Bq2Y6+yTe7OOo/vEpX5wVurblAhRBdncOtpjUcvkDkTTKANYwUu7lmNP5IpHX53QVw==", "requires": { "bplist-parser": "https://github.com/telerik/node-bplist-parser/tarball/master", "colors": "0.6.2", @@ -3080,13 +3087,6 @@ "yargs": "4.7.1" }, "dependencies": { - "bplist-parser": { - "version": "https://github.com/telerik/node-bplist-parser/tarball/master", - "integrity": "sha1-X7BVlo1KqtkGi+pkMyFRiYKHtFY=", - "requires": { - "big-integer": "1.6.23" - } - }, "colors": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", @@ -3529,7 +3529,7 @@ "just-extend": { "version": "1.1.27", "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-1.1.27.tgz", - "integrity": "sha512-mJVp13Ix6gFo3SBAy9U/kL+oeZqzlYYYLQBwXVBlVzIsZwBqGREnOro24oC/8s8aox+rJhtZ2DiQof++IrkA+g==", + "integrity": "sha1-7G55QQ/5FORyZSq/oOYDwD1g6QU=", "dev": true }, "kind-of": { @@ -3706,7 +3706,7 @@ "log-symbols": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "integrity": "sha1-V0Dhxdbw39pK2TI7UzIQfva0xAo=", "requires": { "chalk": "2.3.2" }, @@ -3714,7 +3714,7 @@ "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", "requires": { "color-convert": "1.9.1" } @@ -3722,7 +3722,7 @@ "chalk": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", - "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", + "integrity": "sha1-JQ3JawdJG/1gHmSNZt319gx6XGU=", "requires": { "ansi-styles": "3.2.1", "escape-string-regexp": "1.0.5", @@ -3737,7 +3737,7 @@ "supports-color": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", - "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", + "integrity": "sha1-WySsFduA+pJ89SJ6SjP9PEx2dsA=", "requires": { "has-flag": "3.0.0" } @@ -3757,7 +3757,7 @@ "lolex": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.3.1.tgz", - "integrity": "sha512-mQuW55GhduF3ppo+ZRUTz1PRjEh1hS5BbqU7d8D0ez2OKxHDod7StPPeAVKisZR5aLkHZjdGWSL42LSONUJsZw==", + "integrity": "sha1-PSMZiURx6glQ72RpLq0qUxjP82I=", "dev": true }, "longest": { @@ -3785,7 +3785,7 @@ "marked": { "version": "0.3.12", "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.12.tgz", - "integrity": "sha512-k4NaW+vS7ytQn6MgJn3fYpQt20/mOgYM5Ft9BYMfQJDz2QT6yEeS9XJ8k2Nw8JTeWK/znPPW2n3UJGzyYEiMoA==" + "integrity": "sha1-fPJf8iUmMvP+JAa94ljpTu6SdRk=" }, "marked-terminal": { "version": "2.0.0", @@ -3900,7 +3900,7 @@ "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + "integrity": "sha1-Ms2eXGRVO9WNGaVor0Uqz/BJgbE=" }, "mime-db": { "version": "1.27.0", @@ -3918,7 +3918,7 @@ "mimic-fn": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" + "integrity": "sha1-ggyGo5M0ZA6ZUWkovQP8qIBX0CI=" }, "min-document": { "version": "2.19.0", @@ -4027,12 +4027,12 @@ "natives": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.2.tgz", - "integrity": "sha512-5bRASydE1gu6zPOenLN043++J8xj1Ob7ArkfdYO3JN4DF5rDmG7bMoiybkTyD+GnXQEMixVeDHMzuqm6kpBmiA==" + "integrity": "sha1-RDfKHtin8EdTHM368nkoU99O+hw=" }, "nativescript-doctor": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/nativescript-doctor/-/nativescript-doctor-0.12.0.tgz", - "integrity": "sha512-eGEx9MFagJ7i2mtFZv5Jbsg6YQqQsVLxLhmg2uOOjLC253daAkGUBFbPnpEajrqhPZX3PBmoYIh+oHfc9/trjA==", + "integrity": "sha1-bC5i5OUOlX4jZKcIRTaKrmiywiY=", "requires": { "osenv": "0.1.3", "semver": "5.3.0", @@ -4063,7 +4063,7 @@ "nise": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/nise/-/nise-1.2.0.tgz", - "integrity": "sha512-q9jXh3UNsMV28KeqI43ILz5+c3l+RiNW8mhurEwCKckuHQbL+hTJIKKTiUlCPKlgQ/OukFvSnKB/Jk3+sFbkGA==", + "integrity": "sha1-B51srbvLErow448cmZ82rU1rqlM=", "dev": true, "requires": { "formatio": "1.2.0", @@ -4219,7 +4219,7 @@ "ora": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ora/-/ora-2.0.0.tgz", - "integrity": "sha512-g+IR0nMUXq1k4nE3gkENbN4wkF0XsVZFyxznTF6CdmwQ9qeTGONGpSR9LM5//1l0TVvJoJF3MkMtJp6slUsWFg==", + "integrity": "sha1-jsOjf6e/+1SjoMGIofZ5jn4YJ80=", "requires": { "chalk": "2.3.2", "cli-cursor": "2.1.0", @@ -4237,7 +4237,7 @@ "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", "requires": { "color-convert": "1.9.1" } @@ -4245,7 +4245,7 @@ "chalk": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", - "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", + "integrity": "sha1-JQ3JawdJG/1gHmSNZt319gx6XGU=", "requires": { "ansi-styles": "3.2.1", "escape-string-regexp": "1.0.5", @@ -4293,7 +4293,7 @@ "supports-color": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", - "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", + "integrity": "sha1-WySsFduA+pJ89SJ6SjP9PEx2dsA=", "requires": { "has-flag": "3.0.0" } @@ -4566,7 +4566,7 @@ "pngjs": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.3.2.tgz", - "integrity": "sha512-bVNd3LMXRzdo6s4ehr4XW2wFMu9cb40nPgHEjSSppm8/++Xc+g0b2QQb+SeDesgfANXbjydOr1or9YQ+pcCZPQ==" + "integrity": "sha1-CXw8KnX+siPq3d6mvJ8AUM+DC8M=" }, "prelude-ls": { "version": "1.1.2", @@ -4598,7 +4598,7 @@ "proxy-lib": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/proxy-lib/-/proxy-lib-0.4.0.tgz", - "integrity": "sha512-oUDDpf0NTtKPyXjBNUcKzwZhA9GjEdu8Z47GsxGv5rZvKyCqsSrHurJtlL1yp7uVzA2NOmxd4aX7qmB1ZOdCwQ==", + "integrity": "sha1-Dt7+MSUKacPMU8xJ7RR9zk8zbXs=", "requires": { "osenv": "0.1.4" }, @@ -4666,7 +4666,7 @@ "randomatic": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", - "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", + "integrity": "sha1-x6vpzIuHwLqodrGf3oP9RkeX44w=", "requires": { "is-number": "3.0.0", "kind-of": "4.0.0" @@ -4978,7 +4978,7 @@ "samsam": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.3.0.tgz", - "integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==", + "integrity": "sha1-jR2TUOJWItow3j5EumkrUiGrfFA=", "dev": true }, "sax": { @@ -5109,7 +5109,7 @@ "sinon": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/sinon/-/sinon-4.1.2.tgz", - "integrity": "sha512-5uLBZPdCWl59Lpbf45ygKj7Z0LVol+ftBe7RDIXOQV/sF58pcFmbK8raA7bt6eljNuGnvBP+/ZxlicVn0emDjA==", + "integrity": "sha1-ZWEFIdkm+1N0LdhM1ZnwuJqC9EA=", "dev": true, "requires": { "diff": "3.4.0", @@ -5124,7 +5124,7 @@ "diff": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.4.0.tgz", - "integrity": "sha512-QpVuMTEoJMF7cKzi6bvWhRulU1fZqZnvyVQgNhPaxxuTYwyjn/j1v9falseQ/uXWwPnO56RBfwtg4h/EQXmucA==", + "integrity": "sha1-sdhVB9rzlkgo3lSzfQ1zumfdpWw=", "dev": true }, "has-flag": { @@ -5197,7 +5197,7 @@ "source-map-support": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.3.tgz", - "integrity": "sha512-eKkTgWYeBOQqFGXRfKabMFdnWepo51vWqEdoeikaEPFiJC7MCU5j2h4+6Q8npkZTeLGbSyecZvRxiSoWl3rh+w==", + "integrity": "sha1-Kz1f/ymM+k0a/X1DUtVp6aAVjnY=", "dev": true, "requires": { "source-map": "0.6.1" @@ -5206,7 +5206,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", "dev": true } } @@ -5935,7 +5935,7 @@ "xhr": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.4.1.tgz", - "integrity": "sha512-pAIU5vBr9Hiy5cpFIbPnwf0C18ZF86DBsZKrlsf87N5De/JbA6RJ83UP/cv+aljl4S40iRVMqP4pr4sF9Dnj0A==", + "integrity": "sha1-upgsztIFrl7sOHFprJ3HfKSFPTg=", "requires": { "global": "4.3.2", "is-function": "1.0.1", @@ -5958,7 +5958,7 @@ "xml2js": { "version": "0.4.19", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", - "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "integrity": "sha1-aGwg8hMgnpSr8NG88e+qKRx4J6c=", "requires": { "sax": "1.2.4", "xmlbuilder": "9.0.7" diff --git a/package.json b/package.json index 41f2828895..877ee38c1b 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "inquirer": "0.9.0", "ios-device-lib": "0.4.10", "ios-mobileprovision-finder": "1.0.10", - "ios-sim-portable": "3.3.0", + "ios-sim-portable": "3.3.1", "jimp": "0.2.28", "lockfile": "1.0.3", "lodash": "4.13.1", From b1101cca1f15dbc7384985dc9f9e54463ec2c5d8 Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Tue, 3 Apr 2018 12:21:22 +0300 Subject: [PATCH 28/32] feat(analytics): Remove tracking in cross-client project We are no longer using the cross clients analytics project, so delete the code that sends information to it. --- .../analytics/google-analytics-provider.ts | 33 +++---------------- 1 file changed, 5 insertions(+), 28 deletions(-) diff --git a/lib/services/analytics/google-analytics-provider.ts b/lib/services/analytics/google-analytics-provider.ts index 2ce3a8284e..785e6d1c10 100644 --- a/lib/services/analytics/google-analytics-provider.ts +++ b/lib/services/analytics/google-analytics-provider.ts @@ -4,7 +4,6 @@ import { AnalyticsClients } from "../../common/constants"; export class GoogleAnalyticsProvider implements IGoogleAnalyticsProvider { private static GA_TRACKING_ID = "UA-111455-44"; - private static GA_CROSS_CLIENT_TRACKING_ID = "UA-111455-51"; private currentPage: string; constructor(private clientId: string, @@ -15,15 +14,12 @@ export class GoogleAnalyticsProvider implements IGoogleAnalyticsProvider { } public async trackHit(trackInfo: IGoogleAnalyticsData): Promise { - const trackingIds = [GoogleAnalyticsProvider.GA_TRACKING_ID, GoogleAnalyticsProvider.GA_CROSS_CLIENT_TRACKING_ID]; const sessionId = uuid.v4(); - for (const gaTrackingId of trackingIds) { - try { - await this.track(gaTrackingId, trackInfo, sessionId); - } catch (e) { - this.$logger.trace("Analytics exception: ", e); - } + try { + await this.track(GoogleAnalyticsProvider.GA_TRACKING_ID, trackInfo, sessionId); + } catch (e) { + this.$logger.trace("Analytics exception: ", e); } } @@ -41,14 +37,7 @@ export class GoogleAnalyticsProvider implements IGoogleAnalyticsProvider { } }); - switch (gaTrackingId) { - case GoogleAnalyticsProvider.GA_CROSS_CLIENT_TRACKING_ID: - this.setCrossClientCustomDimensions(visitor, sessionId); - break; - default: - await this.setCustomDimensions(visitor, trackInfo.customDimensions, sessionId); - break; - } + await this.setCustomDimensions(visitor, trackInfo.customDimensions, sessionId); switch (trackInfo.googleAnalyticsDataType) { case GoogleAnalyticsDataType.Page: @@ -83,18 +72,6 @@ export class GoogleAnalyticsProvider implements IGoogleAnalyticsProvider { }); } - private async setCrossClientCustomDimensions(visitor: ua.Visitor, sessionId: string): Promise { - const customDimensions: IStringDictionary = { - [GoogleAnalyticsCrossClientCustomDimensions.sessionId]: sessionId, - [GoogleAnalyticsCrossClientCustomDimensions.clientId]: this.clientId, - [GoogleAnalyticsCrossClientCustomDimensions.crossClientId]: this.clientId, - }; - - _.each(customDimensions, (value, key) => { - visitor.set(key, value); - }); - } - private trackEvent(visitor: ua.Visitor, trackInfo: IGoogleAnalyticsEventData): Promise { return new Promise((resolve, reject) => { visitor.event(trackInfo.category, trackInfo.action, trackInfo.label, trackInfo.value, { p: this.currentPage }, (err: Error) => { From 676b77426de00f5142e3663b43e17e524024e885 Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Wed, 4 Apr 2018 01:26:44 +0300 Subject: [PATCH 29/32] fix: Getting started prompter fails The prompter for getting started changes fails in some cases, as we do not await the validation of the livesyncCommandHelper.validate call. So we try to execute some operations as we think the environment is setup correctly, but we are unable to do so and the code fails. Also add additional option to prompter in case cloud extension is installed. This gives better visibility of the feature --- lib/commands/run.ts | 2 +- lib/definitions/platform.d.ts | 2 +- lib/services/analytics/analytics-service.ts | 2 +- lib/services/android-project-service.ts | 2 +- lib/services/doctor-service.ts | 42 +++++++++++++++--- lib/services/ios-project-service.ts | 2 +- .../platform-environment-requirements.ts | 44 ++++++++++++++----- 7 files changed, 76 insertions(+), 20 deletions(-) diff --git a/lib/commands/run.ts b/lib/commands/run.ts index 38365c2a59..f2d361d609 100644 --- a/lib/commands/run.ts +++ b/lib/commands/run.ts @@ -28,7 +28,7 @@ export class RunCommandBase implements ICommand { this.platform = this.$devicePlatformsConstants.Android; } - this.$liveSyncCommandHelper.validatePlatform(this.platform); + await this.$liveSyncCommandHelper.validatePlatform(this.platform); return true; } diff --git a/lib/definitions/platform.d.ts b/lib/definitions/platform.d.ts index 190467ddd0..59d6977667 100644 --- a/lib/definitions/platform.d.ts +++ b/lib/definitions/platform.d.ts @@ -381,5 +381,5 @@ interface IUpdateAppOptions extends IOptionalFilesToSync, IOptionalFilesToRemove } interface IPlatformEnvironmentRequirements { - checkEnvironmentRequirements(platform: string): Promise; + checkEnvironmentRequirements(platform: string, projectDir: string): Promise; } \ No newline at end of file diff --git a/lib/services/analytics/analytics-service.ts b/lib/services/analytics/analytics-service.ts index 3c28cd138f..5e24e81871 100644 --- a/lib/services/analytics/analytics-service.ts +++ b/lib/services/analytics/analytics-service.ts @@ -73,7 +73,7 @@ export class AnalyticsService extends AnalyticsServiceBase { // In some cases (like in case action is Build and platform is Android), we do not know if the deviceType is emulator or device. // Just exclude the device_type in this case. - if (isForDevice !== null) { + if (isForDevice !== null && isForDevice !== undefined) { const deviceType = isForDevice ? DeviceTypes.Device : (this.$mobileHelper.isAndroidPlatform(platform) ? DeviceTypes.Emulator : DeviceTypes.Simulator); label = this.addDataToLabel(label, deviceType); } diff --git a/lib/services/android-project-service.ts b/lib/services/android-project-service.ts index d47626112f..66ce5ec28a 100644 --- a/lib/services/android-project-service.ts +++ b/lib/services/android-project-service.ts @@ -133,7 +133,7 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject this.validatePackageName(projectData.projectId); this.validateProjectName(projectData.projectName); - await this.$platformEnvironmentRequirements.checkEnvironmentRequirements(this.getPlatformData(projectData).normalizedPlatformName); + await this.$platformEnvironmentRequirements.checkEnvironmentRequirements(this.getPlatformData(projectData).normalizedPlatformName, projectData.projectDir); this.$androidToolsInfo.validateTargetSdk({ showWarningsAsErrors: true }); } diff --git a/lib/services/doctor-service.ts b/lib/services/doctor-service.ts index 4b0b95580b..2da86d2f25 100644 --- a/lib/services/doctor-service.ts +++ b/lib/services/doctor-service.ts @@ -53,32 +53,64 @@ class DoctorService implements IDoctorService { } } - public runSetupScript(): Promise { + public async runSetupScript(): Promise { + await this.$analyticsService.trackEventActionInGoogleAnalytics({ + action: "Run setup script", + additionalData: "Start", + }); + if (this.$hostInfo.isLinux) { + await this.$analyticsService.trackEventActionInGoogleAnalytics({ + action: "Run setup script", + additionalData: "Skipped as OS is Linux", + }); return; } this.$logger.out("Running the setup script to try and automatically configure your environment."); if (this.$hostInfo.isDarwin) { - return this.runSetupScriptCore(DoctorService.DarwinSetupScriptLocation, []); + await this.runSetupScriptCore(DoctorService.DarwinSetupScriptLocation, []); } if (this.$hostInfo.isWindows) { - return this.runSetupScriptCore(DoctorService.WindowsSetupScriptExecutable, DoctorService.WindowsSetupScriptArguments); + await this.runSetupScriptCore(DoctorService.WindowsSetupScriptExecutable, DoctorService.WindowsSetupScriptArguments); } + + await this.$analyticsService.trackEventActionInGoogleAnalytics({ + action: "Run setup script", + additionalData: "Finished", + }); } public async canExecuteLocalBuild(platform?: string): Promise { + await this.$analyticsService.trackEventActionInGoogleAnalytics({ + action: "Check Local Build Setup", + additionalData: "Started", + }); const infos = await doctor.getInfos({ platform }); const warnings = this.filterInfosByType(infos, constants.WARNING_TYPE_NAME); - if (warnings.length > 0) { + const hasWarnings = warnings.length > 0; + if (hasWarnings) { + // TODO: Separate the track per platform: + // Could be in two separate trackings or in the same, but with additional information, for example: + // Errors:__.join(--)$$__.join(--)... + await this.$analyticsService.trackEventActionInGoogleAnalytics({ + action: "Check Local Build Setup", + additionalData: `Warnings:${warnings.map(w => w.message).join("__")}`, + }); this.printInfosCore(infos); } else { infos.map(info => this.$logger.trace(info.message)); } - return warnings.length === 0; + + await this.$analyticsService.trackEventActionInGoogleAnalytics({ + action: "Check Local Build Setup", + additionalData: `Finished: ${hasWarnings}`, + }); + + return !hasWarnings; } private async promptForDocs(link: string): Promise { diff --git a/lib/services/ios-project-service.ts b/lib/services/ios-project-service.ts index 4191bee724..b8054ab86e 100644 --- a/lib/services/ios-project-service.ts +++ b/lib/services/ios-project-service.ts @@ -139,7 +139,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ return; } - await this.$platformEnvironmentRequirements.checkEnvironmentRequirements(this.getPlatformData(projectData).normalizedPlatformName); + await this.$platformEnvironmentRequirements.checkEnvironmentRequirements(this.getPlatformData(projectData).normalizedPlatformName, projectData.projectDir); const xcodeBuildVersion = await this.getXcodeVersion(); if (helpers.versionCompare(xcodeBuildVersion, IOSProjectService.XCODEBUILD_MIN_VERSION) < 0) { diff --git a/lib/services/platform-environment-requirements.ts b/lib/services/platform-environment-requirements.ts index 0eba53eb58..faf33d9192 100644 --- a/lib/services/platform-environment-requirements.ts +++ b/lib/services/platform-environment-requirements.ts @@ -9,10 +9,12 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ private $logger: ILogger, private $nativeScriptCloudExtensionService: INativeScriptCloudExtensionService, private $prompter: IPrompter, - private $staticConfig: IStaticConfig) { } + private $staticConfig: IStaticConfig, + private $analyticsService: IAnalyticsService) { } public static CLOUD_SETUP_OPTION_NAME = "Configure for Cloud Builds"; public static LOCAL_SETUP_OPTION_NAME = "Configure for Local Builds"; + public static TRY_CLOUD_OPERATION_OPTION_NAME = "Try Cloud Operation"; public static MANUALLY_SETUP_OPTION_NAME = "Skip Step and Configure Manually"; private static BOTH_CLOUD_SETUP_AND_LOCAL_SETUP_OPTION_NAME = "Configure for Both Local and Cloud Builds"; private static CHOOSE_OPTIONS_MESSAGE = "To continue, choose one of the following options: "; @@ -27,14 +29,24 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ "deploy": "tns cloud deploy" }; - public async checkEnvironmentRequirements(platform: string): Promise { + public async checkEnvironmentRequirements(platform: string, projectDir: string): Promise { if (process.env.NS_SKIP_ENV_CHECK) { + await this.$analyticsService.trackEventActionInGoogleAnalytics({ + action: "Check Environment Requirements", + additionalData: "Skipped:NS_SKIP_ENV_CHECK is set", + projectDir + }); return true; } const canExecute = await this.$doctorService.canExecuteLocalBuild(platform); if (!canExecute) { if (!isInteractive()) { + await this.$analyticsService.trackEventActionInGoogleAnalytics({ + action: "Check Environment Requirements", + additionalData: "Non-interactive terminal, unable to execute local builds.", + projectDir + }); this.fail(this.getNonInteractiveConsoleMessage(platform)); } @@ -74,6 +86,11 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ this.processManuallySetup(platform); } + + if (selectedOption === PlatformEnvironmentRequirements.TRY_CLOUD_OPERATION_OPTION_NAME) { + const message = `You can use ${_.lowerFirst(this.getCloudBuildsMessage(platform))}`; + this.fail(message); + } } return true; @@ -166,18 +183,25 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ ]); } - private promptForChoice(): Promise { + private async promptForChoice(): Promise { const choices = this.$nativeScriptCloudExtensionService.isInstalled() ? [ + PlatformEnvironmentRequirements.TRY_CLOUD_OPERATION_OPTION_NAME, PlatformEnvironmentRequirements.LOCAL_SETUP_OPTION_NAME, PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME, ] : [ - PlatformEnvironmentRequirements.CLOUD_SETUP_OPTION_NAME, - PlatformEnvironmentRequirements.LOCAL_SETUP_OPTION_NAME, - PlatformEnvironmentRequirements.BOTH_CLOUD_SETUP_AND_LOCAL_SETUP_OPTION_NAME, - PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME, - ]; - - return this.$prompter.promptForChoice(PlatformEnvironmentRequirements.CHOOSE_OPTIONS_MESSAGE, choices); + PlatformEnvironmentRequirements.CLOUD_SETUP_OPTION_NAME, + PlatformEnvironmentRequirements.LOCAL_SETUP_OPTION_NAME, + PlatformEnvironmentRequirements.BOTH_CLOUD_SETUP_AND_LOCAL_SETUP_OPTION_NAME, + PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME, + ]; + + const selection = await this.$prompter.promptForChoice(PlatformEnvironmentRequirements.CHOOSE_OPTIONS_MESSAGE, choices); + await this.$analyticsService.trackEventActionInGoogleAnalytics({ + action: "Check Environment Requirements", + additionalData: `User selected: ${selection}` + // consider passing projectDir here + }); + return selection; } private getEnvVerificationMessage() { From 94978183e1f329d29c4345d21fb57f8e6dceceae Mon Sep 17 00:00:00 2001 From: fatme Date: Wed, 4 Apr 2018 14:16:14 +0300 Subject: [PATCH 30/32] * Show getting started prompts on doctor command * Fix unit test * Show message that user can use forum or slack when manually setup is selected * Fix message when nativescript-cloud extension is installed --- lib/definitions/platform.d.ts | 2 +- lib/services/android-project-service.ts | 2 +- lib/services/doctor-service.ts | 36 ++------------ lib/services/ios-project-service.ts | 2 +- .../platform-environment-requirements.ts | 47 ++++++++----------- .../platform-environment-requirements.ts | 5 +- 6 files changed, 30 insertions(+), 64 deletions(-) diff --git a/lib/definitions/platform.d.ts b/lib/definitions/platform.d.ts index 59d6977667..4f098575eb 100644 --- a/lib/definitions/platform.d.ts +++ b/lib/definitions/platform.d.ts @@ -381,5 +381,5 @@ interface IUpdateAppOptions extends IOptionalFilesToSync, IOptionalFilesToRemove } interface IPlatformEnvironmentRequirements { - checkEnvironmentRequirements(platform: string, projectDir: string): Promise; + checkEnvironmentRequirements(platform?: string): Promise; } \ No newline at end of file diff --git a/lib/services/android-project-service.ts b/lib/services/android-project-service.ts index 66ce5ec28a..d47626112f 100644 --- a/lib/services/android-project-service.ts +++ b/lib/services/android-project-service.ts @@ -133,7 +133,7 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject this.validatePackageName(projectData.projectId); this.validateProjectName(projectData.projectName); - await this.$platformEnvironmentRequirements.checkEnvironmentRequirements(this.getPlatformData(projectData).normalizedPlatformName, projectData.projectDir); + await this.$platformEnvironmentRequirements.checkEnvironmentRequirements(this.getPlatformData(projectData).normalizedPlatformName); this.$androidToolsInfo.validateTargetSdk({ showWarningsAsErrors: true }); } diff --git a/lib/services/doctor-service.ts b/lib/services/doctor-service.ts index 2da86d2f25..bf59077b4e 100644 --- a/lib/services/doctor-service.ts +++ b/lib/services/doctor-service.ts @@ -5,18 +5,14 @@ import { doctor, constants } from "nativescript-doctor"; class DoctorService implements IDoctorService { private static DarwinSetupScriptLocation = path.join(__dirname, "..", "..", "setup", "mac-startup-shell-script.sh"); - private static DarwinSetupDocsLink = "https://docs.nativescript.org/start/ns-setup-os-x"; private static WindowsSetupScriptExecutable = "powershell.exe"; private static WindowsSetupScriptArguments = ["start-process", "-FilePath", "PowerShell.exe", "-NoNewWindow", "-Wait", "-ArgumentList", '"-NoProfile -ExecutionPolicy Bypass -Command iex ((new-object net.webclient).DownloadString(\'https://www.nativescript.org/setup/win\'))"']; - private static WindowsSetupDocsLink = "https://docs.nativescript.org/start/ns-setup-win"; - private static LinuxSetupDocsLink = "https://docs.nativescript.org/start/ns-setup-linux"; constructor(private $analyticsService: IAnalyticsService, private $hostInfo: IHostInfo, private $logger: ILogger, private $childProcess: IChildProcess, - private $opener: IOpener, - private $prompter: IPrompter, + private $injector: IInjector, private $terminalSpinnerService: ITerminalSpinnerService, private $versionsService: IVersionsService) { } @@ -41,7 +37,6 @@ class DoctorService implements IDoctorService { if (hasWarnings) { this.$logger.info("There seem to be issues with your configuration."); - await this.promptForHelp(); } else { this.$logger.out("No issues were detected.".bold); } @@ -51,6 +46,8 @@ class DoctorService implements IDoctorService { } catch (err) { this.$logger.error("Cannot get the latest versions information from npm. Please try again later."); } + + await this.$injector.resolve("platformEnvironmentRequirements").checkEnvironmentRequirements(null); } public async runSetupScript(): Promise { @@ -113,33 +110,6 @@ class DoctorService implements IDoctorService { return !hasWarnings; } - private async promptForDocs(link: string): Promise { - if (await this.$prompter.confirm("Do you want to visit the official documentation?", () => helpers.isInteractive())) { - this.$opener.open(link); - } - } - - private async promptForSetupScript(executablePath: string, setupScriptArgs: string[]): Promise { - if (await this.$prompter.confirm("Do you want to run the setup script?", () => helpers.isInteractive())) { - await this.runSetupScriptCore(executablePath, setupScriptArgs); - } - } - - private async promptForHelp(): Promise { - if (this.$hostInfo.isDarwin) { - await this.promptForHelpCore(DoctorService.DarwinSetupDocsLink, DoctorService.DarwinSetupScriptLocation, []); - } else if (this.$hostInfo.isWindows) { - await this.promptForHelpCore(DoctorService.WindowsSetupDocsLink, DoctorService.WindowsSetupScriptExecutable, DoctorService.WindowsSetupScriptArguments); - } else { - await this.promptForDocs(DoctorService.LinuxSetupDocsLink); - } - } - - private async promptForHelpCore(link: string, setupScriptExecutablePath: string, setupScriptArgs: string[]): Promise { - await this.promptForDocs(link); - await this.promptForSetupScript(setupScriptExecutablePath, setupScriptArgs); - } - private async runSetupScriptCore(executablePath: string, setupScriptArgs: string[]): Promise { return this.$childProcess.spawnFromEvent(executablePath, setupScriptArgs, "close", { stdio: "inherit" }); } diff --git a/lib/services/ios-project-service.ts b/lib/services/ios-project-service.ts index b8054ab86e..4191bee724 100644 --- a/lib/services/ios-project-service.ts +++ b/lib/services/ios-project-service.ts @@ -139,7 +139,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ return; } - await this.$platformEnvironmentRequirements.checkEnvironmentRequirements(this.getPlatformData(projectData).normalizedPlatformName, projectData.projectDir); + await this.$platformEnvironmentRequirements.checkEnvironmentRequirements(this.getPlatformData(projectData).normalizedPlatformName); const xcodeBuildVersion = await this.getXcodeVersion(); if (helpers.versionCompare(xcodeBuildVersion, IOSProjectService.XCODEBUILD_MIN_VERSION) < 0) { diff --git a/lib/services/platform-environment-requirements.ts b/lib/services/platform-environment-requirements.ts index faf33d9192..81b200733a 100644 --- a/lib/services/platform-environment-requirements.ts +++ b/lib/services/platform-environment-requirements.ts @@ -21,6 +21,7 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ private static NOT_CONFIGURED_ENV_AFTER_SETUP_SCRIPT_MESSAGE = `The setup script was not able to configure your environment for local builds. To execute local builds, you have to set up your environment manually. In case you have any questions, you can check our forum: 'http://forum.nativescript.org' and our public Slack channel: 'https://nativescriptcommunity.slack.com/'. ${PlatformEnvironmentRequirements.CHOOSE_OPTIONS_MESSAGE}`; private static MISSING_LOCAL_SETUP_MESSAGE = "Your environment is not configured properly and you will not be able to execute local builds."; private static MISSING_LOCAL_AND_CLOUD_SETUP_MESSAGE = `You are missing the ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension and you will not be able to execute cloud builds. ${PlatformEnvironmentRequirements.MISSING_LOCAL_SETUP_MESSAGE} ${PlatformEnvironmentRequirements.CHOOSE_OPTIONS_MESSAGE} `; + private static MISSING_LOCAL_BUT_CLOUD_SETUP_MESSAGE = `You have ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension installed but ${_.lowerFirst(PlatformEnvironmentRequirements.MISSING_LOCAL_SETUP_MESSAGE)}`; private static RUN_TNS_SETUP_MESSAGE = 'Run $ tns setup command to run the setup script to try to automatically configure your environment for local builds.'; private cliCommandToCloudCommandName: IStringDictionary = { @@ -29,12 +30,11 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ "deploy": "tns cloud deploy" }; - public async checkEnvironmentRequirements(platform: string, projectDir: string): Promise { + public async checkEnvironmentRequirements(platform?: string): Promise { if (process.env.NS_SKIP_ENV_CHECK) { await this.$analyticsService.trackEventActionInGoogleAnalytics({ action: "Check Environment Requirements", - additionalData: "Skipped:NS_SKIP_ENV_CHECK is set", - projectDir + additionalData: "Skipped:NS_SKIP_ENV_CHECK is set" }); return true; } @@ -44,8 +44,7 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ if (!isInteractive()) { await this.$analyticsService.trackEventActionInGoogleAnalytics({ action: "Check Environment Requirements", - additionalData: "Non-interactive terminal, unable to execute local builds.", - projectDir + additionalData: "Non-interactive terminal, unable to execute local builds." }); this.fail(this.getNonInteractiveConsoleMessage(platform)); } @@ -54,8 +53,8 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ const selectedOption = await this.promptForChoice(); - await this.processCloudBuildsIfNeeded(platform, selectedOption); - this.processManuallySetupIfNeeded(platform, selectedOption); + await this.processCloudBuildsIfNeeded(selectedOption, platform); + this.processManuallySetupIfNeeded(selectedOption, platform); if (selectedOption === PlatformEnvironmentRequirements.LOCAL_SETUP_OPTION_NAME) { await this.$doctorService.runSetupScript(); @@ -72,14 +71,13 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME ]); - await this.processCloudBuildsIfNeeded(platform, option); - - this.processManuallySetupIfNeeded(platform, option); + await this.processCloudBuildsIfNeeded(option, platform); + this.processManuallySetupIfNeeded(option, platform); } } if (selectedOption === PlatformEnvironmentRequirements.BOTH_CLOUD_SETUP_AND_LOCAL_SETUP_OPTION_NAME) { - await this.processBothCloudBuildsAndSetupScript(platform); + await this.processBothCloudBuildsAndSetupScript(); if (await this.$doctorService.canExecuteLocalBuild(platform)) { return true; } @@ -88,30 +86,29 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ } if (selectedOption === PlatformEnvironmentRequirements.TRY_CLOUD_OPERATION_OPTION_NAME) { - const message = `You can use ${_.lowerFirst(this.getCloudBuildsMessage(platform))}`; - this.fail(message); + this.fail(this.getCloudBuildsMessage(platform)); } } return true; } - private async processCloudBuildsIfNeeded(platform: string, selectedOption: string): Promise { + private async processCloudBuildsIfNeeded(selectedOption: string, platform?: string): Promise { if (selectedOption === PlatformEnvironmentRequirements.CLOUD_SETUP_OPTION_NAME) { await this.processCloudBuilds(platform); } } private async processCloudBuilds(platform: string): Promise { - await this.processCloudBuildsCore(platform); + await this.processCloudBuildsCore(); this.fail(this.getCloudBuildsMessage(platform)); } - private processCloudBuildsCore(platform: string): Promise { + private processCloudBuildsCore(): Promise { return this.$nativeScriptCloudExtensionService.install(); } - private getCloudBuildsMessage(platform: string): string { + private getCloudBuildsMessage(platform?: string): string { const cloudCommandName = this.cliCommandToCloudCommandName[this.$commandsService.currentCommandData.commandName]; if (!cloudCommandName) { return `In order to test your application use the $ tns login command to log in with your account and then $ tns cloud build command to build your app in the cloud.`; @@ -124,19 +121,19 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ return `Use the $ tns login command to log in with your account and then $ ${cloudCommandName.toLowerCase()} ${platform.toLowerCase()} command.`; } - private processManuallySetupIfNeeded(platform: string, selectedOption: string) { + private processManuallySetupIfNeeded(selectedOption: string, platform?: string) { if (selectedOption === PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME) { this.processManuallySetup(platform); } } - private processManuallySetup(platform: string): void { - this.fail(`To be able to build for ${platform}, verify that your environment is configured according to the system requirements described at ${this.$staticConfig.SYS_REQUIREMENTS_LINK}`); + private processManuallySetup(platform?: string): void { + this.fail(`To be able to ${platform ? `build for ${platform}` : 'build'}, verify that your environment is configured according to the system requirements described at ${this.$staticConfig.SYS_REQUIREMENTS_LINK}. In case you have any questions, you can check our forum: 'http://forum.nativescript.org' and our public Slack channel: 'https://nativescriptcommunity.slack.com/'.`); } - private async processBothCloudBuildsAndSetupScript(platform: string): Promise { + private async processBothCloudBuildsAndSetupScript(): Promise { try { - await this.processCloudBuildsCore(platform); + await this.processCloudBuildsCore(); } catch (e) { this.$logger.trace(`Error while installing ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension. ${e.message}.`); } @@ -165,12 +162,9 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ } private getInteractiveConsoleMessage(platform: string) { - const message = `The ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension is installed and you can ${_.lowerFirst(this.getCloudBuildsMessage(platform))}`; - return this.$nativeScriptCloudExtensionService.isInstalled() ? this.buildMultilineMessage([ - `${message.bold}`, - `${PlatformEnvironmentRequirements.MISSING_LOCAL_SETUP_MESSAGE} ${PlatformEnvironmentRequirements.CHOOSE_OPTIONS_MESSAGE}`, + `${PlatformEnvironmentRequirements.MISSING_LOCAL_BUT_CLOUD_SETUP_MESSAGE} ${PlatformEnvironmentRequirements.CHOOSE_OPTIONS_MESSAGE}`, `Select "Configure for Local Builds" to run the setup script and automatically configure your environment for local builds.`, `Select "Skip Step and Configure Manually" to disregard this option and install any required components manually.` ]) : @@ -199,7 +193,6 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ await this.$analyticsService.trackEventActionInGoogleAnalytics({ action: "Check Environment Requirements", additionalData: `User selected: ${selection}` - // consider passing projectDir here }); return selection; } diff --git a/test/services/platform-environment-requirements.ts b/test/services/platform-environment-requirements.ts index abb8bb76ee..28d577b120 100644 --- a/test/services/platform-environment-requirements.ts +++ b/test/services/platform-environment-requirements.ts @@ -13,6 +13,9 @@ const nonInteractiveConsoleMessageWhenExtensionIsInstalled = `Your environment i function createTestInjector() { const testInjector = new Yok(); + testInjector.register("analyticsService", { + trackEventActionInGoogleAnalytics: () => ({}) + }); testInjector.register("commandsService", {currentCommandData: {commandName: "test", commandArguments: [""]}}); testInjector.register("doctorService", {}); testInjector.register("errors", { @@ -103,7 +106,7 @@ describe("platformEnvironmentRequirements ", () => { await assert.isRejected(platformEnvironmentRequirements.checkEnvironmentRequirements(platform)); assert.isTrue(promptForChoiceData.length === 1); assert.deepEqual("To continue, choose one of the following options: ", promptForChoiceData[0].message); - assert.deepEqual(['Configure for Local Builds', 'Skip Step and Configure Manually'], promptForChoiceData[0].choices); + assert.deepEqual(['Try Cloud Operation', 'Configure for Local Builds', 'Skip Step and Configure Manually'], promptForChoiceData[0].choices); }); it("should skip env chech when NS_SKIP_ENV_CHECK environment variable is passed", async() => { process.env.NS_SKIP_ENV_CHECK = true; From 32115dadc67e6ce2822f8bb921b3156f9f57634b Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Wed, 4 Apr 2018 15:42:53 +0300 Subject: [PATCH 31/32] fix: Use correct messages and tracking for getting started prompters --- lib/constants.ts | 5 +- lib/services/doctor-service.ts | 22 ++--- .../platform-environment-requirements.ts | 92 ++++++++++++------- lib/services/platform-service.ts | 2 +- 4 files changed, 74 insertions(+), 47 deletions(-) diff --git a/lib/constants.ts b/lib/constants.ts index 31fa4d306f..7983e71a1a 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -135,7 +135,10 @@ export const enum TrackActionNames { CreateProject = "Create project", Debug = "Debug", Deploy = "Deploy", - LiveSync = "LiveSync" + LiveSync = "LiveSync", + RunSetupScript = "Run Setup Script", + CheckLocalBuildSetup = "Check Local Build Setup", + CheckEnvironmentRequirements = "Check Environment Requirements" } export const enum BuildStates { diff --git a/lib/services/doctor-service.ts b/lib/services/doctor-service.ts index bf59077b4e..514614833c 100644 --- a/lib/services/doctor-service.ts +++ b/lib/services/doctor-service.ts @@ -1,6 +1,7 @@ import { EOL } from "os"; import * as path from "path"; import * as helpers from "../common/helpers"; +import { TrackActionNames } from "../constants"; import { doctor, constants } from "nativescript-doctor"; class DoctorService implements IDoctorService { @@ -52,13 +53,13 @@ class DoctorService implements IDoctorService { public async runSetupScript(): Promise { await this.$analyticsService.trackEventActionInGoogleAnalytics({ - action: "Run setup script", - additionalData: "Start", + action: TrackActionNames.RunSetupScript, + additionalData: "Starting", }); if (this.$hostInfo.isLinux) { await this.$analyticsService.trackEventActionInGoogleAnalytics({ - action: "Run setup script", + action: TrackActionNames.RunSetupScript, additionalData: "Skipped as OS is Linux", }); return; @@ -75,26 +76,23 @@ class DoctorService implements IDoctorService { } await this.$analyticsService.trackEventActionInGoogleAnalytics({ - action: "Run setup script", + action: TrackActionNames.RunSetupScript, additionalData: "Finished", }); } public async canExecuteLocalBuild(platform?: string): Promise { await this.$analyticsService.trackEventActionInGoogleAnalytics({ - action: "Check Local Build Setup", - additionalData: "Started", + action: TrackActionNames.CheckLocalBuildSetup, + additionalData: "Starting", }); const infos = await doctor.getInfos({ platform }); const warnings = this.filterInfosByType(infos, constants.WARNING_TYPE_NAME); const hasWarnings = warnings.length > 0; if (hasWarnings) { - // TODO: Separate the track per platform: - // Could be in two separate trackings or in the same, but with additional information, for example: - // Errors:__.join(--)$$__.join(--)... await this.$analyticsService.trackEventActionInGoogleAnalytics({ - action: "Check Local Build Setup", + action: TrackActionNames.CheckLocalBuildSetup, additionalData: `Warnings:${warnings.map(w => w.message).join("__")}`, }); this.printInfosCore(infos); @@ -103,8 +101,8 @@ class DoctorService implements IDoctorService { } await this.$analyticsService.trackEventActionInGoogleAnalytics({ - action: "Check Local Build Setup", - additionalData: `Finished: ${hasWarnings}`, + action: TrackActionNames.CheckLocalBuildSetup, + additionalData: `Finished: Is setup correct: ${!hasWarnings}`, }); return !hasWarnings; diff --git a/lib/services/platform-environment-requirements.ts b/lib/services/platform-environment-requirements.ts index 81b200733a..cfc1213c2f 100644 --- a/lib/services/platform-environment-requirements.ts +++ b/lib/services/platform-environment-requirements.ts @@ -1,4 +1,4 @@ -import * as constants from "../constants"; +import { NATIVESCRIPT_CLOUD_EXTENSION_NAME, TrackActionNames } from "../constants"; import { isInteractive } from "../common/helpers"; import { EOL } from "os"; @@ -18,10 +18,10 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ public static MANUALLY_SETUP_OPTION_NAME = "Skip Step and Configure Manually"; private static BOTH_CLOUD_SETUP_AND_LOCAL_SETUP_OPTION_NAME = "Configure for Both Local and Cloud Builds"; private static CHOOSE_OPTIONS_MESSAGE = "To continue, choose one of the following options: "; - private static NOT_CONFIGURED_ENV_AFTER_SETUP_SCRIPT_MESSAGE = `The setup script was not able to configure your environment for local builds. To execute local builds, you have to set up your environment manually. In case you have any questions, you can check our forum: 'http://forum.nativescript.org' and our public Slack channel: 'https://nativescriptcommunity.slack.com/'. ${PlatformEnvironmentRequirements.CHOOSE_OPTIONS_MESSAGE}`; + private static NOT_CONFIGURED_ENV_AFTER_SETUP_SCRIPT_MESSAGE = `The setup script was not able to configure your environment for local builds. To execute local builds, you have to set up your environment manually. In case you have any questions, you can check our forum: 'http://forum.nativescript.org' and our public Slack channel: 'https://nativescriptcommunity.slack.com/'.`; private static MISSING_LOCAL_SETUP_MESSAGE = "Your environment is not configured properly and you will not be able to execute local builds."; - private static MISSING_LOCAL_AND_CLOUD_SETUP_MESSAGE = `You are missing the ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension and you will not be able to execute cloud builds. ${PlatformEnvironmentRequirements.MISSING_LOCAL_SETUP_MESSAGE} ${PlatformEnvironmentRequirements.CHOOSE_OPTIONS_MESSAGE} `; - private static MISSING_LOCAL_BUT_CLOUD_SETUP_MESSAGE = `You have ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension installed but ${_.lowerFirst(PlatformEnvironmentRequirements.MISSING_LOCAL_SETUP_MESSAGE)}`; + private static MISSING_LOCAL_AND_CLOUD_SETUP_MESSAGE = `You are missing the ${NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension and you will not be able to execute cloud builds. ${PlatformEnvironmentRequirements.MISSING_LOCAL_SETUP_MESSAGE} ${PlatformEnvironmentRequirements.CHOOSE_OPTIONS_MESSAGE} `; + private static MISSING_LOCAL_BUT_CLOUD_SETUP_MESSAGE = `You have ${NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension installed, so you can execute cloud builds, but ${_.lowerFirst(PlatformEnvironmentRequirements.MISSING_LOCAL_SETUP_MESSAGE)}`; private static RUN_TNS_SETUP_MESSAGE = 'Run $ tns setup command to run the setup script to try to automatically configure your environment for local builds.'; private cliCommandToCloudCommandName: IStringDictionary = { @@ -33,8 +33,8 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ public async checkEnvironmentRequirements(platform?: string): Promise { if (process.env.NS_SKIP_ENV_CHECK) { await this.$analyticsService.trackEventActionInGoogleAnalytics({ - action: "Check Environment Requirements", - additionalData: "Skipped:NS_SKIP_ENV_CHECK is set" + action: TrackActionNames.CheckEnvironmentRequirements, + additionalData: "Skipped: NS_SKIP_ENV_CHECK is set" }); return true; } @@ -43,15 +43,27 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ if (!canExecute) { if (!isInteractive()) { await this.$analyticsService.trackEventActionInGoogleAnalytics({ - action: "Check Environment Requirements", + action: TrackActionNames.CheckEnvironmentRequirements, additionalData: "Non-interactive terminal, unable to execute local builds." }); this.fail(this.getNonInteractiveConsoleMessage(platform)); } - this.$logger.info(this.getInteractiveConsoleMessage(platform)); + const infoMessage = this.getInteractiveConsoleMessage(platform); + this.$logger.info(infoMessage); - const selectedOption = await this.promptForChoice(); + const choices = this.$nativeScriptCloudExtensionService.isInstalled() ? [ + PlatformEnvironmentRequirements.TRY_CLOUD_OPERATION_OPTION_NAME, + PlatformEnvironmentRequirements.LOCAL_SETUP_OPTION_NAME, + PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME, + ] : [ + PlatformEnvironmentRequirements.CLOUD_SETUP_OPTION_NAME, + PlatformEnvironmentRequirements.LOCAL_SETUP_OPTION_NAME, + PlatformEnvironmentRequirements.BOTH_CLOUD_SETUP_AND_LOCAL_SETUP_OPTION_NAME, + PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME, + ]; + + const selectedOption = await this.promptForChoice({ infoMessage, choices }); await this.processCloudBuildsIfNeeded(selectedOption, platform); this.processManuallySetupIfNeeded(selectedOption, platform); @@ -64,12 +76,24 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ } if (this.$nativeScriptCloudExtensionService.isInstalled()) { - this.processManuallySetup(platform); + const option = await this.promptForChoice({ + infoMessage: PlatformEnvironmentRequirements.NOT_CONFIGURED_ENV_AFTER_SETUP_SCRIPT_MESSAGE, + choices: [ + PlatformEnvironmentRequirements.TRY_CLOUD_OPERATION_OPTION_NAME, + PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME + ] + }); + + this.processTryCloudSetupIfNeeded(option, platform); + this.processManuallySetupIfNeeded(option, platform); } else { - const option = await this.$prompter.promptForChoice(PlatformEnvironmentRequirements.NOT_CONFIGURED_ENV_AFTER_SETUP_SCRIPT_MESSAGE, [ - PlatformEnvironmentRequirements.CLOUD_SETUP_OPTION_NAME, - PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME - ]); + const option = await this.promptForChoice({ + infoMessage: PlatformEnvironmentRequirements.NOT_CONFIGURED_ENV_AFTER_SETUP_SCRIPT_MESSAGE, + choices: [ + PlatformEnvironmentRequirements.CLOUD_SETUP_OPTION_NAME, + PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME + ] + }); await this.processCloudBuildsIfNeeded(option, platform); this.processManuallySetupIfNeeded(option, platform); @@ -85,9 +109,7 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ this.processManuallySetup(platform); } - if (selectedOption === PlatformEnvironmentRequirements.TRY_CLOUD_OPERATION_OPTION_NAME) { - this.fail(this.getCloudBuildsMessage(platform)); - } + this.processTryCloudSetupIfNeeded(selectedOption, platform); } return true; @@ -121,6 +143,12 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ return `Use the $ tns login command to log in with your account and then $ ${cloudCommandName.toLowerCase()} ${platform.toLowerCase()} command.`; } + private processTryCloudSetupIfNeeded(selectedOption: string, platform?: string) { + if (selectedOption === PlatformEnvironmentRequirements.TRY_CLOUD_OPERATION_OPTION_NAME) { + this.fail(this.getCloudBuildsMessage(platform)); + } + } + private processManuallySetupIfNeeded(selectedOption: string, platform?: string) { if (selectedOption === PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME) { this.processManuallySetup(platform); @@ -135,7 +163,7 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ try { await this.processCloudBuildsCore(); } catch (e) { - this.$logger.trace(`Error while installing ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension. ${e.message}.`); + this.$logger.trace(`Error while installing ${NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension. ${e.message}.`); } await this.$doctorService.runSetupScript(); @@ -156,7 +184,7 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ this.buildMultilineMessage([ PlatformEnvironmentRequirements.MISSING_LOCAL_AND_CLOUD_SETUP_MESSAGE, PlatformEnvironmentRequirements.RUN_TNS_SETUP_MESSAGE, - `Run $ tns cloud setup command to install the ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension to configure your environment for cloud builds.`, + `Run $ tns cloud setup command to install the ${NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension to configure your environment for cloud builds.`, this.getEnvVerificationMessage() ]); } @@ -170,30 +198,28 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ ]) : this.buildMultilineMessage([ PlatformEnvironmentRequirements.MISSING_LOCAL_AND_CLOUD_SETUP_MESSAGE, - `Select "Configure for Cloud Builds" to install the ${constants.NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension and automatically configure your environment for cloud builds.`, + `Select "Configure for Cloud Builds" to install the ${NATIVESCRIPT_CLOUD_EXTENSION_NAME} extension and automatically configure your environment for cloud builds.`, `Select "Configure for Local Builds" to run the setup script and automatically configure your environment for local builds.`, `Select "Configure for Both Local and Cloud Builds" to automatically configure your environment for both options.`, `Select "Configure for Both Local and Cloud Builds" to automatically configure your environment for both options.` ]); } - private async promptForChoice(): Promise { - const choices = this.$nativeScriptCloudExtensionService.isInstalled() ? [ - PlatformEnvironmentRequirements.TRY_CLOUD_OPERATION_OPTION_NAME, - PlatformEnvironmentRequirements.LOCAL_SETUP_OPTION_NAME, - PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME, - ] : [ - PlatformEnvironmentRequirements.CLOUD_SETUP_OPTION_NAME, - PlatformEnvironmentRequirements.LOCAL_SETUP_OPTION_NAME, - PlatformEnvironmentRequirements.BOTH_CLOUD_SETUP_AND_LOCAL_SETUP_OPTION_NAME, - PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME, - ]; + private async promptForChoice(opts: { infoMessage: string, choices: string[], }): Promise { + this.$logger.info(opts.infoMessage); - const selection = await this.$prompter.promptForChoice(PlatformEnvironmentRequirements.CHOOSE_OPTIONS_MESSAGE, choices); await this.$analyticsService.trackEventActionInGoogleAnalytics({ - action: "Check Environment Requirements", + action: TrackActionNames.CheckEnvironmentRequirements, + additionalData: `User should select: ${opts.infoMessage}` + }); + + const selection = await this.$prompter.promptForChoice(PlatformEnvironmentRequirements.CHOOSE_OPTIONS_MESSAGE, opts.choices); + + await this.$analyticsService.trackEventActionInGoogleAnalytics({ + action: TrackActionNames.CheckEnvironmentRequirements, additionalData: `User selected: ${selection}` }); + return selection; } diff --git a/lib/services/platform-service.ts b/lib/services/platform-service.ts index c817cbf714..94fff61155 100644 --- a/lib/services/platform-service.ts +++ b/lib/services/platform-service.ts @@ -341,7 +341,7 @@ export class PlatformService extends EventEmitter implements IPlatformService { } const platformData = this.$platformsData.getPlatformData(platform, projectData); - const forDevice = !buildConfig || buildConfig.buildForDevice; + const forDevice = !buildConfig || !!buildConfig.buildForDevice; outputPath = outputPath || (forDevice ? platformData.deviceBuildOutputPath : platformData.emulatorBuildOutputPath || platformData.deviceBuildOutputPath); if (!this.$fs.exists(outputPath)) { return true; From 432d05dfd7ec7226190dd1b7e5aaec288d25dccd Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Wed, 4 Apr 2018 22:48:15 +0300 Subject: [PATCH 32/32] chore: Update to latest common lib --- lib/common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/common b/lib/common index ea2a16a92c..0b68ca58bc 160000 --- a/lib/common +++ b/lib/common @@ -1 +1 @@ -Subproject commit ea2a16a92cf65dcb6092e199744930acf545992a +Subproject commit 0b68ca58bc81c05e8e3cd6a267aaa11eb3ff61b5