diff --git a/lib/commands/post-install.ts b/lib/commands/post-install.ts index d3f998e157..f9539d84f3 100644 --- a/lib/commands/post-install.ts +++ b/lib/commands/post-install.ts @@ -1,3 +1,5 @@ +import { doesCurrentNpmCommandMatch } from "../common/helpers"; + export class PostInstallCliCommand implements ICommand { constructor(private $fs: IFileSystem, private $subscriptionService: ISubscriptionService, @@ -13,24 +15,35 @@ export class PostInstallCliCommand implements ICommand { public allowedParameters: ICommandParameter[] = []; public async execute(args: string[]): Promise { + const isRunningWithSudoUser = !!process.env.SUDO_USER; + if (!this.$hostInfo.isWindows) { // when running under 'sudo' we create a working dir with wrong owner (root) and // it is no longer accessible for the user initiating the installation // patch the owner here - if (process.env.SUDO_USER) { + if (isRunningWithSudoUser) { // TODO: Check if this is the correct place, probably we should set this at the end of the command. await this.$fs.setCurrentUserAsOwner(this.$settingsService.getProfileDir(), process.env.SUDO_USER); } } - await this.$helpService.generateHtmlPages(); - // Explicitly ask for confirmation of usage-reporting: - await this.$analyticsService.checkConsent(); - await this.$commandsService.tryExecuteCommand("autocomplete", []); + const canExecutePostInstallTask = !isRunningWithSudoUser || doesCurrentNpmCommandMatch([/^--unsafe-perm$/]); + + if (canExecutePostInstallTask) { + await this.$helpService.generateHtmlPages(); + + // Explicitly ask for confirmation of usage-reporting: + await this.$analyticsService.checkConsent(); + await this.$commandsService.tryExecuteCommand("autocomplete", []); + } + // Make sure the success message is separated with at least one line from all other messages. this.$logger.out(); this.$logger.printMarkdown("Installation successful. You are good to go. Connect with us on `http://twitter.com/NativeScript`."); - await this.$subscriptionService.subscribeForNewsletter(); + + if (canExecutePostInstallTask) { + await this.$subscriptionService.subscribeForNewsletter(); + } } public async postCommandAction(args: string[]): Promise { diff --git a/test/commands/post-install.ts b/test/commands/post-install.ts index ecfb2070f4..6be24a78bc 100644 --- a/test/commands/post-install.ts +++ b/test/commands/post-install.ts @@ -49,6 +49,14 @@ const createTestInjector = (): IInjector => { }; describe("post-install command", () => { + const originalNpmArgv = process.env.npm_config_argv; + const originalSudoUser = process.env.SUDO_USER; + + afterEach(() => { + process.env.npm_config_argv = originalNpmArgv; + process.env.SUDO_USER = originalSudoUser; + }); + it("calls subscriptionService.subscribeForNewsletter method", async () => { const testInjector = createTestInjector(); const subscriptionService = testInjector.resolve("subscriptionService"); @@ -61,4 +69,62 @@ describe("post-install command", () => { await postInstallCommand.execute([]); assert.isTrue(isSubscribeForNewsletterCalled, "post-install-cli command must call subscriptionService.subscribeForNewsletter"); }); + + const verifyResult = async (opts: { shouldCallMethod: boolean }): Promise => { + const testInjector = createTestInjector(); + const subscriptionService = testInjector.resolve("subscriptionService"); + let isSubscribeForNewsletterCalled = false; + subscriptionService.subscribeForNewsletter = async (): Promise => { + isSubscribeForNewsletterCalled = true; + }; + + const helpService = testInjector.resolve("helpService"); + let isGenerateHtmlPagesCalled = false; + helpService.generateHtmlPages = async (): Promise => { + isGenerateHtmlPagesCalled = true; + }; + + const analyticsService = testInjector.resolve("analyticsService"); + let isCheckConsentCalled = false; + analyticsService.checkConsent = async (): Promise => { + isCheckConsentCalled = true; + }; + + const commandsService = testInjector.resolve("commandsService"); + let isTryExecuteCommandCalled = false; + commandsService.tryExecuteCommand = async (): Promise => { + isTryExecuteCommandCalled = true; + }; + + const postInstallCommand = testInjector.resolveCommand("post-install-cli"); + await postInstallCommand.execute([]); + + process.env.npm_config_argv = originalNpmArgv; + process.env.SUDO_USER = originalSudoUser; + + const hasNotInMsg = opts.shouldCallMethod ? "" : "NOT"; + + assert.equal(isSubscribeForNewsletterCalled, opts.shouldCallMethod, `post-install-cli command must ${hasNotInMsg} call subscriptionService.subscribeForNewsletter`); + assert.equal(isGenerateHtmlPagesCalled, opts.shouldCallMethod, `post-install-cli command must ${hasNotInMsg} call helpService.generateHtmlPages`); + assert.equal(isCheckConsentCalled, opts.shouldCallMethod, `post-install-cli command must ${hasNotInMsg} call analyticsService.checkConsent`); + assert.equal(isTryExecuteCommandCalled, opts.shouldCallMethod, `post-install-cli command must ${hasNotInMsg} call commandsService.tryExecuteCommand`); + }; + + it("does not call specific methods when CLI is installed with sudo without `--unsafe-perm`", () => { + process.env.npm_config_argv = JSON.stringify({}); + process.env.SUDO_USER = "user1"; + return verifyResult({ shouldCallMethod: false }); + }); + + it("calls specific methods when CLI is installed with sudo with `--unsafe-perm`", async () => { + process.env.npm_config_argv = JSON.stringify({ original: ["--unsafe-perm"] }); + process.env.SUDO_USER = "user1"; + return verifyResult({ shouldCallMethod: true }); + }); + + it("calls specific methods when CLI is installed without sudo", async () => { + process.env.npm_config_argv = JSON.stringify({}); + delete process.env.SUDO_USER; + return verifyResult({ shouldCallMethod: true }); + }); });