diff --git a/CHANGELOG.md b/CHANGELOG.md index 48e687b5a4..7c9ff90782 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +## [8.8.1](https://github.com/NativeScript/nativescript-cli/compare/v8.8.0...v8.8.1) (2024-08-19) + + +### Bug Fixes + +* quote windows command line arguments ([#5808](https://github.com/NativeScript/nativescript-cli/issues/5808)) ([bf9a6cd](https://github.com/NativeScript/nativescript-cli/commit/bf9a6cdbed227c876b8a94a13e3517e684dad924)) + + +### Features + +* add android 35 support ([#5811](https://github.com/NativeScript/nativescript-cli/issues/5811)) ([abc7ab4](https://github.com/NativeScript/nativescript-cli/commit/abc7ab474024bda566374271e0497f4c73d78b4d)) + + + # [8.8.0](https://github.com/NativeScript/nativescript-cli/compare/v8.7.2...v8.8.0) (2024-07-11) diff --git a/lib/base-package-manager.ts b/lib/base-package-manager.ts index 12b24df7d1..86e40c8ea9 100644 --- a/lib/base-package-manager.ts +++ b/lib/base-package-manager.ts @@ -1,4 +1,4 @@ -import { isInteractive } from "./common/helpers"; +import { isInteractive, quoteString } from "./common/helpers"; import { INodePackageManager, INodePackageManagerInstallOptions, @@ -108,11 +108,19 @@ export abstract class BasePackageManager implements INodePackageManager { ): Promise { const npmExecutable = this.getPackageManagerExecutableName(); const stdioValue = isInteractive() ? "inherit" : "pipe"; - await this.$childProcess.spawnFromEvent(npmExecutable, params, "close", { - cwd: opts.cwd, - stdio: stdioValue, - shell: this.$hostInfo.isWindows, - }); + const sanitizedNpmExecutable = this.$hostInfo.isWindows + ? quoteString(npmExecutable) + : npmExecutable; + await this.$childProcess.spawnFromEvent( + sanitizedNpmExecutable, + params, + "close", + { + cwd: opts.cwd, + stdio: stdioValue, + shell: this.$hostInfo.isWindows, + } + ); // Whenever calling "npm install" or "yarn add" without any arguments (hence installing all dependencies) no output is emitted on stdout // Luckily, whenever you call "npm install" or "yarn add" to install all dependencies chances are you won't need the name/version of the package you're installing because there is none. diff --git a/lib/common/mobile/android/android-virtual-device-service.ts b/lib/common/mobile/android/android-virtual-device-service.ts index ade98318dc..d6b58f2339 100644 --- a/lib/common/mobile/android/android-virtual-device-service.ts +++ b/lib/common/mobile/android/android-virtual-device-service.ts @@ -9,7 +9,7 @@ import { NOT_RUNNING_EMULATOR_STATUS, } from "../../constants"; import { cache } from "../../decorators"; -import { settlePromises } from "../../helpers"; +import { quoteString, settlePromises } from "../../helpers"; import { DeviceConnectionType } from "../../../constants"; import { IStringDictionary, @@ -221,8 +221,11 @@ export class AndroidVirtualDeviceService } if (canExecuteAvdManagerCommand) { + const sanitizedPathToAvdManagerExecutable = this.$hostInfo.isWindows + ? quoteString(this.pathToAvdManagerExecutable) + : this.pathToAvdManagerExecutable; result = await this.$childProcess.trySpawnFromCloseEvent( - this.pathToAvdManagerExecutable, + sanitizedPathToAvdManagerExecutable, ["list", "avds"], { shell: this.$hostInfo.isWindows } ); diff --git a/lib/common/mobile/emulator-helper.ts b/lib/common/mobile/emulator-helper.ts index c4f456731f..f892b605fa 100644 --- a/lib/common/mobile/emulator-helper.ts +++ b/lib/common/mobile/emulator-helper.ts @@ -5,6 +5,7 @@ import { injector } from "../yok"; export class EmulatorHelper implements Mobile.IEmulatorHelper { // https://developer.android.com/guide/topics/manifest/uses-sdk-element public mapAndroidApiLevelToVersion = { + "android-35": "15.0.0", "android-34": "14.0.0", "android-33": "13.0.0", "android-32": "12.0.0", diff --git a/lib/common/test/unit-tests/mobile/device-log-provider.ts b/lib/common/test/unit-tests/mobile/device-log-provider.ts index 736a419b95..022524d329 100644 --- a/lib/common/test/unit-tests/mobile/device-log-provider.ts +++ b/lib/common/test/unit-tests/mobile/device-log-provider.ts @@ -36,6 +36,7 @@ const createTestInjector = (): IInjector => { env: { classicLogs: true, }, + hostProjectModuleName: "app", }); testInjector.register("loggingLevels", LoggingLevels); testInjector.register("devicePlatformsConstants", DevicePlatformsConstants); diff --git a/lib/common/test/unit-tests/services/files-hash-service.ts b/lib/common/test/unit-tests/services/files-hash-service.ts index 6181c3d637..e4cda33d2d 100644 --- a/lib/common/test/unit-tests/services/files-hash-service.ts +++ b/lib/common/test/unit-tests/services/files-hash-service.ts @@ -22,6 +22,7 @@ function createTestInjector(): IInjector { injector.register("fs", FileSystemStub); injector.register("logger", LoggerStub); injector.register("filesHashService", FilesHashService); + injector.register("options", {}); return injector; } @@ -74,8 +75,7 @@ describe("filesHashService", () => { expectedChanges: { file7: "hash7" }, }, { - name: - "should return changes when a file is added and a file is removed from oldHashes", + name: "should return changes when a file is added and a file is removed from oldHashes", newHashes: addFileHashes({ file9: "hash9" }), oldHashes: removeFileHashes({ file1: "hash1" }), expectedChanges: { file1: "hash1", file9: "hash9" }, diff --git a/lib/services/android-plugin-build-service.ts b/lib/services/android-plugin-build-service.ts index 9e525e4ba0..77cda49684 100644 --- a/lib/services/android-plugin-build-service.ts +++ b/lib/services/android-plugin-build-service.ts @@ -8,7 +8,7 @@ import { PLUGIN_BUILD_DATA_FILENAME, SCOPED_ANDROID_RUNTIME_NAME, } from "../constants"; -import { getShortPluginName, hook } from "../common/helpers"; +import { getShortPluginName, hook, quoteString } from "../common/helpers"; import { Builder, parseString } from "xml2js"; import { IRuntimeGradleVersions, @@ -841,9 +841,12 @@ export class AndroidPluginBuildService implements IAndroidPluginBuildService { } try { + const sanitizedArgs = this.$hostInfo.isWindows + ? localArgs.map((arg) => quoteString(arg)) + : localArgs; await this.$childProcess.spawnFromEvent( gradlew, - localArgs, + sanitizedArgs, "close", opts ); diff --git a/lib/services/android/gradle-command-service.ts b/lib/services/android/gradle-command-service.ts index 3e6c3e3117..bca2282bd7 100644 --- a/lib/services/android/gradle-command-service.ts +++ b/lib/services/android/gradle-command-service.ts @@ -10,6 +10,7 @@ import { IGradleCommandOptions, } from "../../definitions/gradle"; import { injector } from "../../common/yok"; +import { quoteString } from "../../common/helpers"; export class GradleCommandService implements IGradleCommandService { constructor( @@ -35,9 +36,12 @@ export class GradleCommandService implements IGradleCommandService { options.gradlePath ?? (this.$hostInfo.isWindows ? "gradlew.bat" : "./gradlew"); + const sanitizedGradleArgs = this.$hostInfo.isWindows + ? gradleArgs.map((arg) => quoteString(arg)) + : gradleArgs; const result = await this.executeCommandSafe( gradleExecutable, - gradleArgs, + sanitizedGradleArgs, childProcessOptions, spawnOptions ); diff --git a/package-lock.json b/package-lock.json index 9d85ecf941..fe8c34a647 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "nativescript", - "version": "8.8.0-embed.2", + "version": "8.8.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "nativescript", - "version": "8.8.0-embed.2", + "version": "8.8.0", "bundleDependencies": [ "@npmcli/move-file", "stringify-package" diff --git a/package.json b/package.json index d10c61f246..75f6cbcaa4 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nativescript", "main": "./lib/nativescript-cli-lib.js", - "version": "8.8.0", + "version": "8.8.1", "author": "NativeScript ", "description": "Command-line interface for building NativeScript projects", "bin": { @@ -54,7 +54,7 @@ "mobile" ], "dependencies": { - "@nativescript/doctor": "2.0.14", + "@nativescript/doctor": "2.0.15", "@nativescript/schematics-executor": "0.0.2", "@npmcli/arborist": "^7.2.0", "@npmcli/move-file": "^2.0.0", diff --git a/packages/doctor/package.json b/packages/doctor/package.json index 6219dc871e..7da016fabe 100644 --- a/packages/doctor/package.json +++ b/packages/doctor/package.json @@ -1,6 +1,6 @@ { "name": "@nativescript/doctor", - "version": "2.0.14", + "version": "2.0.15", "description": "Library that helps identifying if the environment can be used for development of {N} apps.", "main": "src/index.js", "types": "./typings/nativescript-doctor.d.ts", diff --git a/packages/doctor/src/android-tools-info.ts b/packages/doctor/src/android-tools-info.ts index d73b21338e..3950b56587 100644 --- a/packages/doctor/src/android-tools-info.ts +++ b/packages/doctor/src/android-tools-info.ts @@ -31,6 +31,7 @@ export class AndroidToolsInfo implements NativeScriptDoctor.IAndroidToolsInfo { "android-32", "android-33", "android-34", + "android-35", ]; const isRuntimeVersionLessThan = (targetVersion: string) => { diff --git a/packages/doctor/test/android-tools-info.ts b/packages/doctor/test/android-tools-info.ts index 81d286df57..afa3c5fcf7 100644 --- a/packages/doctor/test/android-tools-info.ts +++ b/packages/doctor/test/android-tools-info.ts @@ -69,6 +69,7 @@ describe("androidToolsInfo", () => { "android-32", "android-33", "android-34", + "android-35", ]; } }, @@ -104,7 +105,7 @@ describe("androidToolsInfo", () => { const androidToolsInfo = getAndroidToolsInfo("8.2.0"); const toolsInfo = androidToolsInfo.getToolsInfo({ projectDir: "test" }); - assert.equal(toolsInfo.compileSdkVersion, 34); + assert.equal(toolsInfo.compileSdkVersion, 35); }); }); @@ -138,7 +139,7 @@ describe("androidToolsInfo", () => { it("runtime 8.2.0 should support android-17 - android-34", () => { const min = 17; - const max = 34; + const max = 35; assertSupportedRange("8.2.0", min, max); assertSupportedRange("8.3.0", min, max); }); diff --git a/test/project-files-provider.ts b/test/project-files-provider.ts index 8d400bd2d0..a5edfc2314 100644 --- a/test/project-files-provider.ts +++ b/test/project-files-provider.ts @@ -33,7 +33,10 @@ function createTestInjector(): IInjector { }, }); - testInjector.register("options", { release: false }); + testInjector.register("options", { + release: false, + hostProjectModuleName: "app", + }); return testInjector; } @@ -48,7 +51,8 @@ describe("project-files-provider", () => { projectData = testInjector.resolve("projectData"); projectData.projectDir = projectDir; projectData.appDirectoryPath = projectData.getAppDirectoryPath(); - projectData.appResourcesDirectoryPath = projectData.getAppResourcesDirectoryPath(); + projectData.appResourcesDirectoryPath = + projectData.getAppResourcesDirectoryPath(); projectFilesProvider = testInjector.resolve(ProjectFilesProvider); }); diff --git a/test/services/android-project-service.ts b/test/services/android-project-service.ts index ed199e47ca..1961548012 100644 --- a/test/services/android-project-service.ts +++ b/test/services/android-project-service.ts @@ -41,7 +41,9 @@ const createTestInjector = (): IInjector => { testInjector.register("androidPluginBuildService", {}); testInjector.register("errors", stubs.ErrorsStub); testInjector.register("logger", stubs.LoggerStub); - testInjector.register("options", {}); + testInjector.register("options", { + hostProjectModuleName: "app", + }); testInjector.register("projectData", stubs.ProjectDataStub); testInjector.register("androidToolsInfo", { getToolsInfo: () => { @@ -240,9 +242,8 @@ describe("androidProjectService", () => { compileSdkVersion = 29; - const androidToolsInfo = injector.resolve( - "androidToolsInfo" - ); + const androidToolsInfo = + injector.resolve("androidToolsInfo"); androidToolsInfo.getToolsInfo = ( config?: IProjectDir ): IAndroidToolsInfoData => { @@ -258,9 +259,10 @@ describe("androidProjectService", () => { "src" ); beforeEach(() => { - const androidResourcesMigrationService = injector.resolve< - IAndroidResourcesMigrationService - >("androidResourcesMigrationService"); + const androidResourcesMigrationService = + injector.resolve( + "androidResourcesMigrationService" + ); androidResourcesMigrationService.hasMigrated = () => true; }); @@ -329,9 +331,10 @@ describe("androidProjectService", () => { describe("when old Android App_Resources structure is detected (post {N} 4.0 structure)", () => { beforeEach(() => { - const androidResourcesMigrationService = injector.resolve< - IAndroidResourcesMigrationService - >("androidResourcesMigrationService"); + const androidResourcesMigrationService = + injector.resolve( + "androidResourcesMigrationService" + ); androidResourcesMigrationService.hasMigrated = () => false; }); diff --git a/test/services/log-source-map-service.ts b/test/services/log-source-map-service.ts index 6e15615248..eb7a22037d 100644 --- a/test/services/log-source-map-service.ts +++ b/test/services/log-source-map-service.ts @@ -50,6 +50,9 @@ function createTestInjector(): IInjector { testInjector.register("devicePlatformsConstants", DevicePlatformsConstants); testInjector.register("logger", LoggerStub); testInjector.register("logSourceMapService", LogSourceMapService); + testInjector.register("options", { + hostProjectModuleName: "app", + }); return testInjector; } @@ -58,12 +61,14 @@ function toPlatformSep(filePath: string) { return stringReplaceAll(filePath, "/", path.sep); } -const testCases: IDictionary> = { +const testCases: IDictionary< + Array<{ + caseName: string; + message: string; + expected: string; + runtimeVersion?: string; + }> +> = { android: [ { caseName: "trace message", diff --git a/test/stubs.ts b/test/stubs.ts index 39f1f012b5..02f0d06529 100644 --- a/test/stubs.ts +++ b/test/stubs.ts @@ -1470,7 +1470,9 @@ export class InjectorStub extends Yok implements IInjector { this.register("androidToolsInfo", AndroidToolsInfoStub); this.register("logger", LoggerStub); this.register("errors", ErrorsStub); - this.register("options", {}); + this.register("options", { + hostProjectModuleName: "app", + }); this.register("config", {}); this.register("staticConfig", {}); this.register("hooksService", HooksServiceStub);