Skip to content

Commit 18d3135

Browse files
Merge pull request #3216 from NativeScript/vladimirov/release-331
Cherry-pick commits for 3.3.1
2 parents b232fd5 + 7b8685b commit 18d3135

37 files changed

+548
-115
lines changed

CHANGELOG.md

+18-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,24 @@
11
NativeScript CLI Changelog
22
================
33

4-
3.2.0 - RC.1 (2017, August 29)
4+
3.3.1 (2017, November 17)
5+
### Fixed
6+
* [Fixed #3164](https://github.com/NativeScript/nativescript-cli/issues/3164): `npm run build-*-bundle` gets stuck at nativescript-unit-test-runner hook.
7+
* [Fixed #3182](https://github.com/NativeScript/nativescript-cli/issues/3182): CLI fails when unable to start Analytics Broker process.
8+
9+
3.3.0 (2017, October 26)
10+
==
11+
12+
### New
13+
14+
* [Implemented #3076](https://github.com/NativeScript/nativescript-cli/issues/3076): NativeScript setup scripts should have silent installer mode.
15+
16+
### Fixed
17+
* [Fixed #3141](https://github.com/NativeScript/nativescript-cli/issues/3141): No console.log output Xcode 9 iOS 11.
18+
* [Fixed #3016](https://github.com/NativeScript/nativescript-cli/issues/3016): tns_modules randomly appears in app folder and breaks build.
19+
* [Fixed #2967](https://github.com/NativeScript/nativescript-cli/issues/2967): Create plugin by static static libraries error.
20+
21+
3.2.0 (2017, September 7)
522
==
623

724
### Fixed

PublicAPI.md

+41-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ const tns = require("nativescript");
3535
* [disableDebugging](#disableDebugging)
3636
* [getLiveSyncDeviceDescriptors](#getLiveSyncDeviceDescriptors)
3737
* [events](#events)
38+
* [analyticsSettingsService](#analyticsSettingsService)
39+
* [getClientId](#getClientId)
3840

3941

4042
## Module projectService
@@ -271,7 +273,7 @@ interface ISettingsService {
271273
272274
* Usage:
273275
```JavaScript
274-
tns.settingsService.setSettings({ userAgentName: "myUserAgent" });
276+
tns.settingsService.setSettings({ userAgentName: "myUserAgent", profileDir: "customProfileDir" });
275277
```
276278
277279
## npm
@@ -855,6 +857,44 @@ tns.liveSyncService.on("debuggerDetached", debugInfo => {
855857
console.log(`Detached debugger for device with id ${debugInfo.deviceIdentifier}`);
856858
});
857859
```
860+
## analyticsSettingsService
861+
Provides methods for accessing the analytics settings file data.
862+
863+
### getClientId
864+
The `getClientId` method allows retrieving the clientId used in the analytics tracking
865+
866+
* Definition:
867+
```TypeScript
868+
/**
869+
* Gets the clientId used for analytics tracking
870+
* @returns {Promise<string>} Client identifier in UUIDv4 standard.
871+
*/
872+
getClientId(): Promise<string>;
873+
```
874+
875+
* Usage:
876+
```JavaScript
877+
tns.analyticsSettingsService.getClientId()
878+
.then(clientId => console.log(clientId));
879+
```
880+
881+
### getUserAgentString
882+
The `getUserAgentString` method allows retrieving a user agent string identifying the current system
883+
884+
* Definition:
885+
```TypeScript
886+
/**
887+
* Gets user agent string identifing the current system in the following format: `${identifier} (${systemInfo}) ${osArch}`
888+
* @param {string} identifier The product identifier.
889+
* @returns {string} The user agent string.
890+
*/
891+
getUserAgentString(identifier: string): string;
892+
```
893+
894+
* Usage:
895+
```JavaScript
896+
const userAgentString = tns.analyticsSettingsService.getUserAgentString("tns/3.3.0");
897+
```
858898
859899
## How to add a new method to Public API
860900
CLI is designed as command line tool and when it is used as a library, it does not give you access to all of the methods. This is mainly implementation detail. Most of the CLI's code is created to work in command line, not as a library, so before adding method to public API, most probably it will require some modification.

lib/bootstrap.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ $injector.require("iOSDebugService", "./services/ios-debug-service");
2929
$injector.require("androidDebugService", "./services/android-debug-service");
3030

3131
$injector.require("userSettingsService", "./services/user-settings-service");
32-
$injector.require("analyticsSettingsService", "./services/analytics-settings-service");
32+
$injector.requirePublic("analyticsSettingsService", "./services/analytics-settings-service");
3333
$injector.require("analyticsService", "./services/analytics/analytics-service");
3434
$injector.require("eqatecAnalyticsProvider", "./services/analytics/eqatec-analytics-provider");
3535
$injector.require("googleAnalyticsProvider", "./services/analytics/google-analytics-provider");

lib/commands/generate-help.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
export class GenerateHelpCommand implements ICommand {
22
public allowedParameters: ICommandParameter[] = [];
33

4-
constructor(private $htmlHelpService: IHtmlHelpService) { }
4+
constructor(private $helpService: IHelpService) { }
55

66
public async execute(args: string[]): Promise<void> {
7-
return this.$htmlHelpService.generateHtmlPages();
7+
return this.$helpService.generateHtmlPages();
88
}
99
}
1010

lib/commands/post-install.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ export class PostInstallCliCommand extends PostInstallCommand {
55
private $subscriptionService: ISubscriptionService,
66
$staticConfig: Config.IStaticConfig,
77
$commandsService: ICommandsService,
8-
$htmlHelpService: IHtmlHelpService,
9-
$options: ICommonOptions,
8+
$helpService: IHelpService,
9+
$settingsService: ISettingsService,
1010
$doctorService: IDoctorService,
1111
$analyticsService: IAnalyticsService,
1212
$logger: ILogger) {
13-
super($fs, $staticConfig, $commandsService, $htmlHelpService, $options, $doctorService, $analyticsService, $logger);
13+
super($fs, $staticConfig, $commandsService, $helpService, $settingsService, $doctorService, $analyticsService, $logger);
1414
}
1515

1616
public async execute(args: string[]): Promise<void> {

lib/commands/test.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ function RunTestCommandFactory(platform: string) {
44
return function RunTestCommand(
55
$options: IOptions,
66
$testExecutionService: ITestExecutionService,
7-
$projectData: IProjectData) {
7+
$projectData: IProjectData,
8+
$analyticsService: IAnalyticsService) {
89
$projectData.initializeProjectData();
10+
$analyticsService.setShouldDispose($options.justlaunch || !$options.watch);
911
const projectFilesConfig = helpers.getProjectFilesConfig({ isReleaseBuild: $options.release });
1012
this.execute = (args: string[]): Promise<void> => $testExecutionService.startTestRunner(platform, $projectData, projectFilesConfig);
1113
this.allowedParameters = [];
@@ -16,8 +18,9 @@ $injector.registerCommand("dev-test|android", RunTestCommandFactory('android'));
1618
$injector.registerCommand("dev-test|ios", RunTestCommandFactory('iOS'));
1719

1820
function RunKarmaTestCommandFactory(platform: string) {
19-
return function RunKarmaTestCommand($options: IOptions, $testExecutionService: ITestExecutionService, $projectData: IProjectData) {
21+
return function RunKarmaTestCommand($options: IOptions, $testExecutionService: ITestExecutionService, $projectData: IProjectData, $analyticsService: IAnalyticsService) {
2022
$projectData.initializeProjectData();
23+
$analyticsService.setShouldDispose($options.justlaunch || !$options.watch);
2124
const projectFilesConfig = helpers.getProjectFilesConfig({ isReleaseBuild: $options.release });
2225
this.execute = (args: string[]): Promise<void> => $testExecutionService.startKarmaServer(platform, $projectData, projectFilesConfig);
2326
this.allowedParameters = [];

lib/config.ts

+3-4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ export class StaticConfig extends StaticConfigBase implements IStaticConfig {
2828
public ERROR_REPORT_SETTING_NAME = "TrackExceptions";
2929
public ANALYTICS_INSTALLATION_ID_SETTING_NAME = "AnalyticsInstallationID";
3030
public INSTALLATION_SUCCESS_MESSAGE = "Installation successful. You are good to go. Connect with us on `http://twitter.com/NativeScript`.";
31+
public get PROFILE_DIR_NAME(): string {
32+
return ".nativescript-cli";
33+
}
3134

3235
constructor($injector: IInjector) {
3336
super($injector);
@@ -60,10 +63,6 @@ export class StaticConfig extends StaticConfigBase implements IStaticConfig {
6063

6164
public version = require("../package.json").version;
6265

63-
public get helpTextPath(): string {
64-
return path.join(__dirname, "../resources/help.txt");
65-
}
66-
6766
public get HTML_CLI_HELPERS_DIR(): string {
6867
return path.join(__dirname, "../docs/helpers");
6968
}

lib/nativescript-cli-lib-bootstrap.ts

-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,4 @@ $injector.requirePublic("companionAppsService", "./common/appbuilder/services/li
99
$injector.requirePublicClass("deviceEmitter", "./common/appbuilder/device-emitter");
1010
$injector.requirePublicClass("deviceLogProvider", "./common/appbuilder/device-log-provider");
1111

12-
// We need this because some services check if (!$options.justlaunch) to start the device log after some operation.
13-
// We don't want this behaviour when the CLI is required as library.
14-
$injector.resolve("options").justlaunch = true;
1512
$injector.resolve<IStaticConfig>("staticConfig").disableAnalytics = true;

lib/node-package-manager.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -156,10 +156,12 @@ export class NodePackageManager implements INodePackageManager {
156156
});
157157

158158
// Npm 5 return different object after performing `npm install --dry-run`.
159-
// Considering that the dependency is already installed we should
160-
// find it in the `updated` key as a first element of the array.
159+
// We find the correct dependency by searching for the `userSpecifiedPackageName` in the
160+
// `npm5Output.updated` array and as a fallback, considering that the dependency is already installed,
161+
// we find it as the first element.
161162
if (!name && npm5Output.updated) {
162-
const updatedDependency = npm5Output.updated[0];
163+
const packageNameWithoutVersion = userSpecifiedPackageName.split('@')[0];
164+
const updatedDependency = _.find(npm5Output.updated, ['name', packageNameWithoutVersion]) || npm5Output.updated[0];
163165
return {
164166
name: updatedDependency.name,
165167
originalOutput,

lib/npm-installation-manager.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export class NpmInstallationManager implements INpmInstallationManager {
77
private $childProcess: IChildProcess,
88
private $logger: ILogger,
99
private $options: IOptions,
10+
private $settingsService: ISettingsService,
1011
private $fs: IFileSystem,
1112
private $staticConfig: IStaticConfig) {
1213
}
@@ -59,7 +60,7 @@ export class NpmInstallationManager implements INpmInstallationManager {
5960

6061
// local installation takes precedence over cache
6162
if (!this.inspectorAlreadyInstalled(inspectorPath)) {
62-
const cachePath = path.join(this.$options.profileDir, constants.INSPECTOR_CACHE_DIRNAME);
63+
const cachePath = path.join(this.$settingsService.getProfileDir(), constants.INSPECTOR_CACHE_DIRNAME);
6364
this.prepareCacheDir(cachePath);
6465
const pathToPackageInCache = path.join(cachePath, constants.NODE_MODULES_FOLDER_NAME, inspectorNpmPackageName);
6566

lib/options.ts

+3-21
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import * as commonOptionsLibPath from "./common/options";
2-
import * as osenv from "osenv";
3-
import * as path from "path";
42

53
export class Options extends commonOptionsLibPath.OptionsBase {
64
constructor($errors: IErrors,
75
$staticConfig: IStaticConfig,
8-
$hostInfo: IHostInfo) {
6+
$hostInfo: IHostInfo,
7+
$settingsService: ISettingsService) {
98
super({
109
ipa: { type: OptionType.String },
1110
frameworkPath: { type: OptionType.String },
@@ -39,24 +38,7 @@ export class Options extends commonOptionsLibPath.OptionsBase {
3938
clean: { type: OptionType.Boolean },
4039
watch: { type: OptionType.Boolean, default: true }
4140
},
42-
path.join($hostInfo.isWindows ? process.env.AppData : path.join(osenv.home(), ".local/share"), ".nativescript-cli"),
43-
$errors, $staticConfig);
44-
45-
// On Windows we moved settings from LocalAppData to AppData. Move the existing file to keep the existing settings
46-
// I guess we can remove this code after some grace period, say after 1.7 is out
47-
if ($hostInfo.isWindows) {
48-
try {
49-
const shelljs = require("shelljs"),
50-
oldSettings = path.join(process.env.LocalAppData, ".nativescript-cli", "user-settings.json"),
51-
newSettings = path.join(process.env.AppData, ".nativescript-cli", "user-settings.json");
52-
if (shelljs.test("-e", oldSettings) && !shelljs.test("-e", newSettings)) {
53-
shelljs.mkdir(path.join(process.env.AppData, ".nativescript-cli"));
54-
shelljs.mv(oldSettings, newSettings);
55-
}
56-
} catch (err) {
57-
// ignore the error - it is too early to use $logger here
58-
}
59-
}
41+
$errors, $staticConfig, $settingsService);
6042

6143
const that = (<any>this);
6244
// if justlaunch is set, it takes precedence over the --watch flag and the default true value

lib/services/analytics-settings-service.ts

+38
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import { createGUID } from "../common/helpers";
2+
import { exported } from "../common/decorators";
23

34
class AnalyticsSettingsService implements IAnalyticsSettingsService {
45
private static SESSIONS_STARTED_KEY_PREFIX = "SESSIONS_STARTED_";
56

67
constructor(private $userSettingsService: UserSettings.IUserSettingsService,
78
private $staticConfig: IStaticConfig,
9+
private $hostInfo: IHostInfo,
10+
private $osInfo: IOsInfo,
811
private $logger: ILogger) { }
912

1013
public async canDoRequest(): Promise<boolean> {
@@ -15,6 +18,7 @@ class AnalyticsSettingsService implements IAnalyticsSettingsService {
1518
return this.getSettingValueOrDefault("USER_ID");
1619
}
1720

21+
@exported("analyticsSettingsService")
1822
public getClientId(): Promise<string> {
1923
return this.getSettingValueOrDefault(this.$staticConfig.ANALYTICS_INSTALLATION_ID_SETTING_NAME);
2024
}
@@ -36,6 +40,40 @@ class AnalyticsSettingsService implements IAnalyticsSettingsService {
3640
return this.$userSettingsService.saveSetting<number>(this.getSessionsProjectKey(projectName), count);
3741
}
3842

43+
@exported("analyticsSettingsService")
44+
public getUserAgentString(identifier: string): string {
45+
let osString = "";
46+
const osRelease = this.$osInfo.release();
47+
48+
if (this.$hostInfo.isWindows) {
49+
osString = `Windows NT ${osRelease}`;
50+
} else if (this.$hostInfo.isDarwin) {
51+
osString = `Macintosh`;
52+
const macRelease = this.getMacOSReleaseVersion(osRelease);
53+
if (macRelease) {
54+
osString += `; Intel Mac OS X ${macRelease}`;
55+
}
56+
} else {
57+
osString = `Linux x86`;
58+
if (this.$osInfo.arch() === "x64") {
59+
osString += "_64";
60+
}
61+
}
62+
63+
const userAgent = `${identifier} (${osString}; ${this.$osInfo.arch()})`;
64+
65+
return userAgent;
66+
}
67+
68+
private getMacOSReleaseVersion(osRelease: string): string {
69+
// https://en.wikipedia.org/wiki/Darwin_(operating_system)#Release_history
70+
// Each macOS version is labeled 10.<version>, where it looks like <versions> is taken from the major version returned by os.release() (16.x.x for example) and subtracting 4 from it.
71+
// So the version becomes "10.12" in this case.
72+
// Could be improved by spawning `system_profiler SPSoftwareDataType` and getting the System Version line from the result.
73+
const majorVersion = osRelease && _.first(osRelease.split("."));
74+
return majorVersion && `10.${+majorVersion - 4}`;
75+
}
76+
3977
private getSessionsProjectKey(projectName: string): string {
4078
return `${AnalyticsSettingsService.SESSIONS_STARTED_KEY_PREFIX}${projectName}`;
4179
}

lib/services/analytics/analytics-service.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { isInteractive } from '../../common/helpers';
66
import { DeviceTypes, AnalyticsClients } from "../../common/constants";
77

88
export class AnalyticsService extends AnalyticsServiceBase {
9-
private static ANALYTICS_BROKER_START_TIMEOUT = 30 * 1000;
9+
private static ANALYTICS_BROKER_START_TIMEOUT = 10 * 1000;
1010
private brokerProcess: ChildProcess;
1111

1212
constructor(protected $logger: ILogger,
@@ -182,7 +182,14 @@ export class AnalyticsService extends AnalyticsServiceBase {
182182
}
183183

184184
private async sendMessageToBroker(message: ITrackingInformation): Promise<void> {
185-
const broker = await this.getAnalyticsBroker();
185+
let broker: ChildProcess;
186+
try {
187+
broker = await this.getAnalyticsBroker();
188+
} catch (err) {
189+
this.$logger.trace("Unable to get broker instance due to error: ", err);
190+
return;
191+
}
192+
186193
return new Promise<void>((resolve, reject) => {
187194
if (broker && broker.connected) {
188195
try {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Sync indexes with the custom dimensions of the cross client analytics project
2+
declare const enum GoogleAnalyticsCrossClientCustomDimensions {
3+
sessionId = "cd9",
4+
clientId = "cd10",
5+
crossClientId = "cd12",
6+
}

lib/services/analytics/google-analytics-custom-dimensions.ts renamed to lib/services/analytics/google-analytics-custom-dimensions.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const enum GoogleAnalyticsCustomDimensions {
1+
declare const enum GoogleAnalyticsCustomDimensions {
22
cliVersion = "cd1",
33
projectType = "cd2",
44
clientID = "cd3",

0 commit comments

Comments
 (0)