Skip to content

Commit a2cbfaf

Browse files
Track from which template a project is created
Add tracking from which template a project is created. This will give us better picture of the usage of CLI and the types of projects that the users are creating.
1 parent 99e1ad6 commit a2cbfaf

File tree

3 files changed

+48
-43
lines changed

3 files changed

+48
-43
lines changed

lib/services/project-templates-service.ts

+20-19
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,32 @@ temp.track();
66
export class ProjectTemplatesService implements IProjectTemplatesService {
77

88
public constructor(private $errors: IErrors,
9-
private $fs: IFileSystem,
10-
private $logger: ILogger,
11-
private $npm: INodePackageManager,
12-
private $npmInstallationManager: INpmInstallationManager) { }
9+
private $fs: IFileSystem,
10+
private $logger: ILogger,
11+
private $npm: INodePackageManager,
12+
private $npmInstallationManager: INpmInstallationManager,
13+
private $analyticsService: IAnalyticsService) { }
1314

1415
public prepareTemplate(originalTemplateName: string, projectDir: string): IFuture<string> {
1516
return ((): string => {
16-
let realTemplatePath: string;
17-
if(originalTemplateName) {
17+
let templateName = originalTemplateName || constants.RESERVED_TEMPLATE_NAMES["default"],
18+
version: string = null;
19+
20+
if (originalTemplateName) {
1821
// support <reserved_name>@<version> syntax
1922
let data = originalTemplateName.split("@"),
20-
name = data[0],
21-
version = data[1];
22-
23-
if(constants.RESERVED_TEMPLATE_NAMES[name.toLowerCase()]) {
24-
realTemplatePath = this.prepareNativeScriptTemplate(constants.RESERVED_TEMPLATE_NAMES[name.toLowerCase()], version, projectDir).wait();
25-
} else {
26-
// Use the original template name, specified by user as it may be case-sensitive.
27-
realTemplatePath = this.prepareNativeScriptTemplate(name, version, projectDir).wait();
28-
}
29-
} else {
30-
realTemplatePath = this.prepareNativeScriptTemplate(constants.RESERVED_TEMPLATE_NAMES["default"], null/*version*/, projectDir).wait();
23+
name = data[0];
24+
25+
version = data[1];
26+
27+
templateName = constants.RESERVED_TEMPLATE_NAMES[name.toLowerCase()] || name;
3128
}
3229

33-
if(realTemplatePath) {
30+
this.$analyticsService.track("Template used for project creation", templateName).wait();
31+
32+
const realTemplatePath = this.prepareNativeScriptTemplate(templateName, version, projectDir).wait();
33+
34+
if (realTemplatePath) {
3435
//this removes dependencies from templates so they are not copied to app folder
3536
this.$fs.deleteDirectory(path.join(realTemplatePath, constants.NODE_MODULES_FOLDER_NAME));
3637
return realTemplatePath;
@@ -51,7 +52,7 @@ export class ProjectTemplatesService implements IProjectTemplatesService {
5152
*/
5253
private prepareNativeScriptTemplate(templateName: string, version?: string, projectDir?: string): IFuture<string> {
5354
this.$logger.trace(`Using NativeScript verified template: ${templateName} with version ${version}.`);
54-
return this.$npmInstallationManager.install(templateName, projectDir, {version: version, dependencyType: "save"});
55+
return this.$npmInstallationManager.install(templateName, projectDir, { version: version, dependencyType: "save" });
5556
}
5657
}
5758
$injector.register("projectTemplatesService", ProjectTemplatesService);

test/project-service.ts

+11-9
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ class ProjectIntegrationTest {
112112
this.testInjector.register("fs", FileSystem);
113113
this.testInjector.register("projectDataService", ProjectDataServiceLib.ProjectDataService);
114114
this.testInjector.register("staticConfig", StaticConfig);
115+
this.testInjector.register("analyticsService", { track: () => Future.fromResult() });
115116

116117
this.testInjector.register("npmInstallationManager", NpmInstallationManager);
117118
this.testInjector.register("npm", NpmLib.NodePackageManager);
@@ -134,12 +135,12 @@ class ProjectIntegrationTest {
134135

135136
describe("Project Service Tests", () => {
136137
describe("project service integration tests", () => {
137-
let defaultTemplatePath:string;
138-
let defaultSpecificVersionTemplatePath:string;
139-
let angularTemplatePath:string;
138+
let defaultTemplatePath: string;
139+
let defaultSpecificVersionTemplatePath: string;
140+
let angularTemplatePath: string;
140141
let typescriptTemplatePath: string;
141142

142-
before(function() {
143+
before(function () {
143144
let projectIntegrationTest = new ProjectIntegrationTest();
144145
let fs: IFileSystem = projectIntegrationTest.testInjector.resolve("fs");
145146
let npmInstallationManager: INpmInstallationManager = projectIntegrationTest.testInjector.resolve("npmInstallationManager");
@@ -153,7 +154,7 @@ describe("Project Service Tests", () => {
153154
"readme": "dummy",
154155
"repository": "dummy"
155156
});
156-
npmInstallationManager.install("tns-template-hello-world", defaultTemplateDir, {dependencyType: "save"}).wait();
157+
npmInstallationManager.install("tns-template-hello-world", defaultTemplateDir, { dependencyType: "save" }).wait();
157158
defaultTemplatePath = path.join(defaultTemplateDir, "node_modules", "tns-template-hello-world");
158159
fs.deleteDirectory(path.join(defaultTemplatePath, "node_modules"));
159160

@@ -166,7 +167,7 @@ describe("Project Service Tests", () => {
166167
"readme": "dummy",
167168
"repository": "dummy"
168169
});
169-
npmInstallationManager.install("tns-template-hello-world", defaultSpecificVersionTemplateDir, {version: "1.4.0", dependencyType: "save"}).wait();
170+
npmInstallationManager.install("tns-template-hello-world", defaultSpecificVersionTemplateDir, { version: "1.4.0", dependencyType: "save" }).wait();
170171
defaultSpecificVersionTemplatePath = path.join(defaultSpecificVersionTemplateDir, "node_modules", "tns-template-hello-world");
171172
fs.deleteDirectory(path.join(defaultSpecificVersionTemplatePath, "node_modules"));
172173

@@ -179,7 +180,7 @@ describe("Project Service Tests", () => {
179180
"readme": "dummy",
180181
"repository": "dummy"
181182
});
182-
npmInstallationManager.install("tns-template-hello-world-ng", angularTemplateDir, {dependencyType: "save"}).wait();
183+
npmInstallationManager.install("tns-template-hello-world-ng", angularTemplateDir, { dependencyType: "save" }).wait();
183184
angularTemplatePath = path.join(angularTemplateDir, "node_modules", "tns-template-hello-world-ng");
184185
fs.deleteDirectory(path.join(angularTemplatePath, "node_modules"));
185186

@@ -192,7 +193,7 @@ describe("Project Service Tests", () => {
192193
"readme": "dummy",
193194
"repository": "dummy"
194195
});
195-
npmInstallationManager.install("tns-template-hello-world-ts", typescriptTemplateDir, {dependencyType: "save"}).wait();
196+
npmInstallationManager.install("tns-template-hello-world-ts", typescriptTemplateDir, { dependencyType: "save" }).wait();
196197
typescriptTemplatePath = path.join(typescriptTemplateDir, "node_modules", "tns-template-hello-world-ts");
197198
fs.deleteDirectory(path.join(typescriptTemplatePath, "node_modules"));
198199
});
@@ -447,7 +448,7 @@ describe("Project Service Tests", () => {
447448
projectIntegrationTest.createProject(projectName).wait();
448449
options.copyFrom = defaultTemplatePath;
449450

450-
projectIntegrationTest.assertProject(tempFolder, projectName, `org.nativescript.${projectName}`,null).wait();
451+
projectIntegrationTest.assertProject(tempFolder, projectName, `org.nativescript.${projectName}`, null).wait();
451452
});
452453
});
453454

@@ -468,6 +469,7 @@ function createTestInjector() {
468469
testInjector.register("projectDataService", ProjectDataServiceLib.ProjectDataService);
469470

470471
testInjector.register("staticConfig", StaticConfig);
472+
testInjector.register("analyticsService", { track: () => Future.fromResult() });
471473

472474
testInjector.register("npmInstallationManager", NpmInstallationManager);
473475
testInjector.register("httpClient", HttpClientLib.HttpClient);

test/project-templates-service.ts

+17-15
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import {Yok} from "../lib/common/yok";
1+
import { Yok } from "../lib/common/yok";
22
import * as stubs from "./stubs";
3-
import {ProjectTemplatesService} from "../lib/services/project-templates-service";
3+
import { ProjectTemplatesService } from "../lib/services/project-templates-service";
44
import * as assert from "assert";
55
import Future = require("fibers/future");
66
import * as path from "path";
@@ -9,28 +9,28 @@ import temp = require("temp");
99
let isDeleteDirectoryCalledForNodeModulesDir = false;
1010
let nativeScriptValidatedTemplatePath = "nsValidatedTemplatePath";
1111

12-
function createTestInjector(configuration?: {shouldNpmInstallThrow: boolean, npmInstallationDirContents: string[], npmInstallationDirNodeModulesContents: string[]}): IInjector {
12+
function createTestInjector(configuration?: { shouldNpmInstallThrow: boolean, npmInstallationDirContents: string[], npmInstallationDirNodeModulesContents: string[] }): IInjector {
1313
let injector = new Yok();
1414
injector.register("errors", stubs.ErrorsStub);
1515
injector.register("logger", stubs.LoggerStub);
1616
injector.register("fs", {
1717
readDirectory: (dirPath: string): string[] => {
18-
if(dirPath.toLowerCase().indexOf("node_modules") !== -1) {
18+
if (dirPath.toLowerCase().indexOf("node_modules") !== -1) {
1919
return configuration.npmInstallationDirNodeModulesContents;
2020
}
2121
return configuration.npmInstallationDirContents;
2222
},
2323

2424
deleteDirectory: (directory: string) => {
25-
if(directory.indexOf("node_modules") !== -1) {
25+
if (directory.indexOf("node_modules") !== -1) {
2626
isDeleteDirectoryCalledForNodeModulesDir = true;
2727
}
2828
}
2929

3030
});
3131
injector.register("npm", {
3232
install: (packageName: string, pathToSave: string, config?: any) => {
33-
if(configuration.shouldNpmInstallThrow) {
33+
if (configuration.shouldNpmInstallThrow) {
3434
throw new Error("NPM install throws error.");
3535
}
3636

@@ -40,7 +40,7 @@ function createTestInjector(configuration?: {shouldNpmInstallThrow: boolean, npm
4040

4141
injector.register("npmInstallationManager", {
4242
install: (packageName: string, options?: INpmInstallOptions) => {
43-
if(configuration.shouldNpmInstallThrow) {
43+
if (configuration.shouldNpmInstallThrow) {
4444
throw new Error("NPM install throws error.");
4545
}
4646

@@ -50,6 +50,8 @@ function createTestInjector(configuration?: {shouldNpmInstallThrow: boolean, npm
5050

5151
injector.register("projectTemplatesService", ProjectTemplatesService);
5252

53+
injector.register("analyticsService", { track: () => Future.fromResult() });
54+
5355
return injector;
5456
}
5557

@@ -61,36 +63,36 @@ describe("project-templates-service", () => {
6163
});
6264

6365
describe("prepareTemplate", () => {
64-
describe("throws error", () =>{
66+
describe("throws error", () => {
6567
it("when npm install fails", () => {
66-
testInjector = createTestInjector({shouldNpmInstallThrow: true, npmInstallationDirContents: [], npmInstallationDirNodeModulesContents: null});
68+
testInjector = createTestInjector({ shouldNpmInstallThrow: true, npmInstallationDirContents: [], npmInstallationDirNodeModulesContents: null });
6769
projectTemplatesService = testInjector.resolve("projectTemplatesService");
6870
let tempFolder = temp.mkdirSync("preparetemplate");
6971
assert.throws(() => projectTemplatesService.prepareTemplate("invalidName", tempFolder).wait());
7072
});
7173
});
7274

7375
describe("returns correct path to template", () => {
74-
it("when reserved template name is used", () =>{
75-
testInjector = createTestInjector({shouldNpmInstallThrow: false, npmInstallationDirContents: [], npmInstallationDirNodeModulesContents: []});
76+
it("when reserved template name is used", () => {
77+
testInjector = createTestInjector({ shouldNpmInstallThrow: false, npmInstallationDirContents: [], npmInstallationDirNodeModulesContents: [] });
7678
projectTemplatesService = testInjector.resolve("projectTemplatesService");
7779
let tempFolder = temp.mkdirSync("preparetemplate");
7880
let actualPathToTemplate = projectTemplatesService.prepareTemplate("typescript", tempFolder).wait();
7981
assert.strictEqual(path.basename(actualPathToTemplate), nativeScriptValidatedTemplatePath);
8082
assert.strictEqual(isDeleteDirectoryCalledForNodeModulesDir, true, "When correct path is returned, template's node_modules directory should be deleted.");
8183
});
8284

83-
it("when reserved template name is used (case-insensitive test)", () =>{
84-
testInjector = createTestInjector({shouldNpmInstallThrow: false, npmInstallationDirContents: [], npmInstallationDirNodeModulesContents: []});
85+
it("when reserved template name is used (case-insensitive test)", () => {
86+
testInjector = createTestInjector({ shouldNpmInstallThrow: false, npmInstallationDirContents: [], npmInstallationDirNodeModulesContents: [] });
8587
projectTemplatesService = testInjector.resolve("projectTemplatesService");
8688
let tempFolder = temp.mkdirSync("preparetemplate");
8789
let actualPathToTemplate = projectTemplatesService.prepareTemplate("tYpEsCriPT", tempFolder).wait();
8890
assert.strictEqual(path.basename(actualPathToTemplate), nativeScriptValidatedTemplatePath);
8991
assert.strictEqual(isDeleteDirectoryCalledForNodeModulesDir, true, "When correct path is returned, template's node_modules directory should be deleted.");
9092
});
9193

92-
it("uses defaultTemplate when undefined is passed as parameter", () =>{
93-
testInjector = createTestInjector({shouldNpmInstallThrow: false, npmInstallationDirContents: [], npmInstallationDirNodeModulesContents: []});
94+
it("uses defaultTemplate when undefined is passed as parameter", () => {
95+
testInjector = createTestInjector({ shouldNpmInstallThrow: false, npmInstallationDirContents: [], npmInstallationDirNodeModulesContents: [] });
9496
projectTemplatesService = testInjector.resolve("projectTemplatesService");
9597
let tempFolder = temp.mkdirSync("preparetemplate");
9698
let actualPathToTemplate = projectTemplatesService.prepareTemplate(undefined, tempFolder).wait();

0 commit comments

Comments
 (0)