Skip to content

fix: errors are shown on postinstall when using sudo #4493

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 19 additions & 6 deletions lib/commands/post-install.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { doesCurrentNpmCommandMatch } from "../common/helpers";

export class PostInstallCliCommand implements ICommand {
constructor(private $fs: IFileSystem,
private $subscriptionService: ISubscriptionService,
Expand All @@ -13,24 +15,35 @@ export class PostInstallCliCommand implements ICommand {
public allowedParameters: ICommandParameter[] = [];

public async execute(args: string[]): Promise<void> {
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<void> {
Expand Down
66 changes: 66 additions & 0 deletions test/commands/post-install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<ISubscriptionService>("subscriptionService");
Expand All @@ -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<void> => {
const testInjector = createTestInjector();
const subscriptionService = testInjector.resolve<ISubscriptionService>("subscriptionService");
let isSubscribeForNewsletterCalled = false;
subscriptionService.subscribeForNewsletter = async (): Promise<void> => {
isSubscribeForNewsletterCalled = true;
};

const helpService = testInjector.resolve<IHelpService>("helpService");
let isGenerateHtmlPagesCalled = false;
helpService.generateHtmlPages = async (): Promise<void> => {
isGenerateHtmlPagesCalled = true;
};

const analyticsService = testInjector.resolve<IAnalyticsService>("analyticsService");
let isCheckConsentCalled = false;
analyticsService.checkConsent = async (): Promise<void> => {
isCheckConsentCalled = true;
};

const commandsService = testInjector.resolve<ICommandsService>("commandsService");
let isTryExecuteCommandCalled = false;
commandsService.tryExecuteCommand = async (): Promise<void> => {
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 });
});
});