diff --git a/docs/man_pages/project/testing/build-android.md b/docs/man_pages/project/testing/build-android.md index 87c0da7bae..d537fa081c 100644 --- a/docs/man_pages/project/testing/build-android.md +++ b/docs/man_pages/project/testing/build-android.md @@ -34,6 +34,7 @@ General | `$ ns build android [--compileSdk ] [--key-store-path ` - Specifies the directory that contains the project. If not set, the project is searched for in the current directory and all directories above it. diff --git a/docs/man_pages/project/testing/debug-android.md b/docs/man_pages/project/testing/debug-android.md index cd34d57c66..44116cc3be 100644 --- a/docs/man_pages/project/testing/debug-android.md +++ b/docs/man_pages/project/testing/debug-android.md @@ -38,6 +38,7 @@ Attach the debug tools to a running app in the native emulator | `$ ns debug and * `--env.sourceMap` - creates inline source maps. * `--env.hiddenSourceMap` - creates sources maps in the root folder (useful for Crashlytics usage with bundled app in release). * `--aab` - Specifies that the command will produce and deploy an Android App Bundle. +* `--gradleFlavor` - Builds the given product flavor, when the app declares any. `--gradleFlavor foo` runs the `assembleFooDebug`/`assembleFooRelease` gradle task instead of `assembleDebug`/`assembleRelease`. * `--force` - If set, skips the application compatibility checks and forces `npm i` to ensure all dependencies are installed. Otherwise, the command will check the application compatibility with the current CLI version and could fail requiring `ns migrate`. <% if(isHtml) { %> diff --git a/docs/man_pages/project/testing/run-android.md b/docs/man_pages/project/testing/run-android.md index c895cd8103..ab651eff42 100644 --- a/docs/man_pages/project/testing/run-android.md +++ b/docs/man_pages/project/testing/run-android.md @@ -43,6 +43,7 @@ Start a default emulator if none are running, or run application on all connecte * `--env.sourceMap` - creates inline source maps. * `--env.hiddenSourceMap` - creates sources maps in the root folder (useful for Crashlytics usage with bundled app in release). * `--aab` - Specifies that the command will produce and deploy an Android App Bundle. +* `--gradleFlavor` - Builds the given product flavor, when the app declares any. `--gradleFlavor foo` runs the `assembleFooDebug`/`assembleFooRelease` gradle task instead of `assembleDebug`/`assembleRelease`. * `--force` - If set, skips the application compatibility checks and forces `npm i` to ensure all dependencies are installed. Otherwise, the command will check the application compatibility with the current CLI version and could fail requiring `ns migrate`. <% if(isHtml) { %> diff --git a/lib/data/build-data.ts b/lib/data/build-data.ts index f6b2734174..2dc9ba1546 100644 --- a/lib/data/build-data.ts +++ b/lib/data/build-data.ts @@ -51,6 +51,7 @@ export class AndroidBuildData extends BuildData { public keyStoreAliasPassword: string; public keyStorePassword: string; public androidBundle: boolean; + public gradleFlavor: string; public gradlePath: string; public gradleArgs: string; public hostProjectPath: string; @@ -63,6 +64,7 @@ export class AndroidBuildData extends BuildData { this.keyStoreAliasPassword = data.keyStoreAliasPassword; this.keyStorePassword = data.keyStorePassword; this.androidBundle = data.androidBundle || data.aab; + this.gradleFlavor = data.gradleFlavor; this.gradlePath = data.gradlePath; this.gradleArgs = data.gradleArgs; this.hostProjectPath = data.hostProjectPath; diff --git a/lib/declarations.d.ts b/lib/declarations.d.ts index 8e58d23875..8f837a37c5 100644 --- a/lib/declarations.d.ts +++ b/lib/declarations.d.ts @@ -571,6 +571,11 @@ interface IEmbedOptions { } interface IAndroidOptions extends IEmbedOptions { + /** + * The product flavor to build, when the app declares any. `--gradleFlavor foo` + * runs `assembleFooDebug` instead of `assembleDebug`. + */ + gradleFlavor: string; gradlePath: string; gradleArgs: string; } diff --git a/lib/definitions/build.d.ts b/lib/definitions/build.d.ts index e64a318c6d..391cb672c1 100644 --- a/lib/definitions/build.d.ts +++ b/lib/definitions/build.d.ts @@ -31,6 +31,7 @@ interface IAndroidBuildData extends IBuildData, IAndroidSigningData, IHasAndroidBundle { + gradleFlavor?: string; gradlePath?: string; gradleArgs?: string; } diff --git a/lib/options.ts b/lib/options.ts index 64a4e644e7..df6ce62f4d 100644 --- a/lib/options.ts +++ b/lib/options.ts @@ -219,6 +219,7 @@ export class Options { default: false, hasSensitiveValue: false, }, + gradleFlavor: { type: OptionType.String, hasSensitiveValue: false }, gradlePath: { type: OptionType.String, hasSensitiveValue: false }, gradleArgs: { type: OptionType.String, hasSensitiveValue: false }, hostProjectPath: { type: OptionType.String, hasSensitiveValue: false }, diff --git a/lib/services/android/gradle-build-args-service.ts b/lib/services/android/gradle-build-args-service.ts index 2d0ce3ddec..afe2449c62 100644 --- a/lib/services/android/gradle-build-args-service.ts +++ b/lib/services/android/gradle-build-args-service.ts @@ -85,7 +85,15 @@ export class GradleBuildArgsService implements IGradleBuildArgsService { } private getBuildTaskName(buildData: IAndroidBuildData): string { - const baseTaskName = buildData.androidBundle ? "bundle" : "assemble"; + let baseTaskName = buildData.androidBundle ? "bundle" : "assemble"; + + // a product flavor sits between the task and the build type - + // `assembleFooRelease`, `bundleFooDebug` + const flavor = buildData.gradleFlavor; + if (flavor) { + baseTaskName += flavor[0].toUpperCase() + flavor.slice(1); + } + const buildTaskName = buildData.release ? `${baseTaskName}${Configurations.Release}` : `${baseTaskName}${Configurations.Debug}`; diff --git a/test/services/android/gradle-build-args-service.ts b/test/services/android/gradle-build-args-service.ts index 3f2a25f0af..8851f19e67 100644 --- a/test/services/android/gradle-build-args-service.ts +++ b/test/services/android/gradle-build-args-service.ts @@ -163,6 +163,56 @@ describe("GradleBuildArgsService", () => { ); }); + describe("gradleFlavor", async () => { + const testCases = [ + { + name: "should build the flavor of a debug build", + buildConfig: { release: false, gradleFlavor: "foo" }, + logLevel: "INFO", + expectedTask: "assembleFooDebug", + }, + { + name: "should build the flavor of a release build", + buildConfig: { ...releaseBuildConfig, gradleFlavor: "foo" }, + logLevel: "INFO", + expectedTask: "assembleFooRelease", + }, + { + name: "should build the flavor of an android bundle", + buildConfig: { + release: false, + androidBundle: true, + gradleFlavor: "foo", + }, + logLevel: "INFO", + expectedTask: "bundleFooDebug", + }, + { + name: "should keep an already capitalized flavor", + buildConfig: { release: false, gradleFlavor: "Foo" }, + logLevel: "INFO", + expectedTask: "assembleFooDebug", + }, + ]; + + for (const testCase of testCases) { + it(testCase.name, async () => { + const injector = createTestInjector(); + const logger = injector.resolve("logger"); + logger.getLevel = () => testCase.logLevel; + + const gradleBuildArgsService = injector.resolve( + "gradleBuildArgsService" + ); + const args = await gradleBuildArgsService.getBuildTaskArgs( + testCase.buildConfig + ); + + assert.deepStrictEqual(args[0], testCase.expectedTask); + }); + } + }); + describe("getCleanTaskArgs", async () => { const testCases = [ {