Skip to content

chore: merge release into master #5212

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 7 commits into from
Jan 13, 2020
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
NativeScript CLI Changelog
================

6.3.3 (2020, January 13)
===

### New

* [Implemented #5205](https://github.com/NativeScript/nativescript-cli/issues/5205): Support build hooks
* [Implemented #5210](https://github.com/NativeScript/nativescript-cli/issues/5210): Support environment check hooks

### Fixed

* [Fixed #3818](https://github.com/NativeScript/nativescript-cli/issues/3818): Cannot set property 'socket' of null


6.3.2 (2020, January 9)
===

Expand Down
22 changes: 18 additions & 4 deletions lib/services/livesync/android-livesync-tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export class AndroidLivesyncTool implements IAndroidLivesyncTool {
abstractPort: `localabstract:${configuration.appIdentifier}-livesync`
});

const connectionResult = await this.connectEventuallyUntilTimeout(this.createSocket.bind(this, port), connectTimeout);
const connectionResult = await this.connectEventuallyUntilTimeout(this.createSocket.bind(this, port), connectTimeout, configuration);
this.handleConnection(connectionResult);
}

Expand Down Expand Up @@ -299,19 +299,33 @@ export class AndroidLivesyncTool implements IAndroidLivesyncTool {
});
}

private connectEventuallyUntilTimeout(factory: () => ILiveSyncSocket, timeout: number): Promise<{ socket: ILiveSyncSocket, data: Buffer | string }> {
private connectEventuallyUntilTimeout(factory: () => ILiveSyncSocket, timeout: number, configuration: IAndroidLivesyncToolConfiguration): Promise<{ socket: ILiveSyncSocket, data: Buffer | string }> {
return new Promise((resolve, reject) => {
let lastKnownError: Error | string,
isConnected = false;

const connectionTimer = setTimeout(() => {
const connectionTimer = setTimeout(async () => {
if (!isConnected) {
isConnected = true;
if (this.pendingConnectionData && this.pendingConnectionData.socketTimer) {
clearTimeout(this.pendingConnectionData.socketTimer);
}

reject(lastKnownError || new Error(AndroidLivesyncTool.SOCKET_CONNECTION_TIMED_OUT_ERROR));
const applicationPid = await this.$androidProcessService.getAppProcessId(configuration.deviceIdentifier, configuration.appIdentifier);
if (!applicationPid) {
this.$logger.trace("In Android LiveSync tool, lastKnownError is: ", lastKnownError);
this.$logger.info(`Application ${configuration.appIdentifier} is not running on device ${configuration.deviceIdentifier}.`.yellow);
this.$logger.info(
`This issue may be caused by:
* crash at startup (try \`tns debug android --debug-brk\` to check why it crashes)
* different application identifier in your package.json and in your gradle files (check your identifier in \`package.json\` and in all *.gradle files in your App_Resources directory)
* device is locked
* manual closing of the application`.cyan);
reject(new Error(`Application ${configuration.appIdentifier} is not running`));
} else {
reject(lastKnownError || new Error(AndroidLivesyncTool.SOCKET_CONNECTION_TIMED_OUT_ERROR));
}

this.pendingConnectionData = null;
}
}, timeout);
Expand Down
3 changes: 2 additions & 1 deletion lib/services/platform-environment-requirements.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { NATIVESCRIPT_CLOUD_EXTENSION_NAME, TrackActionNames } from "../constants";
import { isInteractive } from "../common/helpers";
import { isInteractive, hook } from "../common/helpers";
import { EOL } from "os";

export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequirements {
Expand Down Expand Up @@ -39,6 +39,7 @@ export class PlatformEnvironmentRequirements implements IPlatformEnvironmentRequ
"deploy": "tns cloud deploy"
};

@hook("checkEnvironment")
public async checkEnvironmentRequirements(input: ICheckEnvironmentRequirementsInput): Promise<ICheckEnvironmentRequirementsOutput> {
const { platform, projectDir, runtimeVersion } = input;
const notConfiguredEnvOptions = input.notConfiguredEnvOptions || {};
Expand Down
3 changes: 2 additions & 1 deletion test/services/livesync/android-livesync-tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ const createTestInjector = (socket: INetSocket, fileStreams: IDictionary<NodeJS.
testInjector.register("injector", testInjector);
testInjector.register("mobileHelper", MobileHelper);
testInjector.register("androidProcessService", {
forwardFreeTcpToAbstractPort: () => Promise.resolve("")
forwardFreeTcpToAbstractPort: () => Promise.resolve(""),
getAppProcessId: () => Promise.resolve("1234")
});
testInjector.register("LiveSyncSocket", () => socket);
testInjector.register("devicePlatformsConstants", DevicePlatformsConstants);
Expand Down
23 changes: 12 additions & 11 deletions test/services/platform-environment-requirements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ function createTestInjector() {
testInjector.register("analyticsService", {
trackEventActionInGoogleAnalytics: () => ({})
});
testInjector.register("commandsService", {currentCommandData: {commandName: "test", commandArguments: [""]}});
testInjector.register("commandsService", { currentCommandData: { commandName: "test", commandArguments: [""] } });
testInjector.register("doctorService", {});
testInjector.register("hooksService", stubs.HooksServiceStub);
testInjector.register("errors", {
fail: (err: any) => {
throw new Error(err.formatStr || err.message || err);
Expand Down Expand Up @@ -47,21 +48,21 @@ describe("platformEnvironmentRequirements ", () => {
describe("checkRequirements", () => {
let testInjector: IInjector = null;
let platformEnvironmentRequirements: IPlatformEnvironmentRequirements = null;
let promptForChoiceData: {message: string, choices: string[]}[] = [];
let promptForChoiceData: { message: string, choices: string[] }[] = [];
let isExtensionInstallCalled = false;

function mockDoctorService(data: {canExecuteLocalBuild: boolean, mockSetupScript?: boolean}) {
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}) {
function mockPrompter(data: { firstCallOptionName: string, secondCallOptionName?: string }) {
const prompter = testInjector.resolve("prompter");
prompter.promptForChoice = (message: string, choices: string[]) => {
promptForChoiceData.push({message: message, choices: choices});
promptForChoiceData.push({ message: message, choices: choices });

if (promptForChoiceData.length === 1) {
return Promise.resolve(data.firstCallOptionName);
Expand All @@ -73,7 +74,7 @@ describe("platformEnvironmentRequirements ", () => {
};
}

function mockNativeScriptCloudExtensionService(data: {isInstalled: boolean}) {
function mockNativeScriptCloudExtensionService(data: { isInstalled: boolean }) {
const nativeScriptCloudExtensionService = testInjector.resolve("nativeScriptCloudExtensionService");
nativeScriptCloudExtensionService.isInstalled = () => data.isInstalled;
nativeScriptCloudExtensionService.install = () => { isExtensionInstallCalled = true; };
Expand Down Expand Up @@ -124,7 +125,7 @@ describe("platformEnvironmentRequirements ", () => {
mockPrompter({ firstCallOptionName: PlatformEnvironmentRequirements.CLOUD_SETUP_OPTION_NAME });
mockNativeScriptCloudExtensionService({ isInstalled: true });

await assert.isRejected(platformEnvironmentRequirements.checkEnvironmentRequirements({ platform, notConfiguredEnvOptions: { hideSyncToPreviewAppOption: true }}));
await assert.isRejected(platformEnvironmentRequirements.checkEnvironmentRequirements({ platform, notConfiguredEnvOptions: { hideSyncToPreviewAppOption: true } }));
assert.isTrue(promptForChoiceData.length === 1);
assert.isTrue(isExtensionInstallCalled);
assert.deepEqual("To continue, choose one of the following options: ", promptForChoiceData[0].message);
Expand All @@ -135,13 +136,13 @@ describe("platformEnvironmentRequirements ", () => {
mockPrompter({ firstCallOptionName: PlatformEnvironmentRequirements.CLOUD_SETUP_OPTION_NAME });
mockNativeScriptCloudExtensionService({ isInstalled: true });

await assert.isRejected(platformEnvironmentRequirements.checkEnvironmentRequirements({ platform, notConfiguredEnvOptions: { hideCloudBuildOption: true }}));
await assert.isRejected(platformEnvironmentRequirements.checkEnvironmentRequirements({ platform, notConfiguredEnvOptions: { hideCloudBuildOption: true } }));
assert.isTrue(promptForChoiceData.length === 1);
assert.isTrue(isExtensionInstallCalled);
assert.deepEqual("To continue, choose one of the following options: ", promptForChoiceData[0].message);
assert.deepEqual(['Sync to Playground', 'Configure for Local Builds', 'Skip Step and Configure Manually'], promptForChoiceData[0].choices);
});
it("should skip env check when NS_SKIP_ENV_CHECK environment variable is passed", async() => {
it("should skip env check when NS_SKIP_ENV_CHECK environment variable is passed", async () => {
(<any>process.env).NS_SKIP_ENV_CHECK = true;

const output = await platformEnvironmentRequirements.checkEnvironmentRequirements({ platform });
Expand All @@ -153,7 +154,7 @@ describe("platformEnvironmentRequirements ", () => {

describe("when local setup option is selected", () => {
beforeEach(() => {
mockPrompter( {firstCallOptionName: PlatformEnvironmentRequirements.LOCAL_SETUP_OPTION_NAME});
mockPrompter({ firstCallOptionName: PlatformEnvironmentRequirements.LOCAL_SETUP_OPTION_NAME });
});

it("should return true when env is configured after executing setup script", async () => {
Expand All @@ -169,7 +170,7 @@ describe("platformEnvironmentRequirements ", () => {

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 });
mockDoctorService({ canExecuteLocalBuild: false, mockSetupScript: true });
mockPrompter({ firstCallOptionName: PlatformEnvironmentRequirements.LOCAL_SETUP_OPTION_NAME, secondCallOptionName: PlatformEnvironmentRequirements.MANUALLY_SETUP_OPTION_NAME });
mockNativeScriptCloudExtensionService({ isInstalled: true });

Expand Down