diff --git a/src/config-plugin/index.ts b/src/config-plugin/index.ts index 9800a63..86c314f 100644 --- a/src/config-plugin/index.ts +++ b/src/config-plugin/index.ts @@ -1,10 +1,12 @@ import { ConfigPlugin, createRunOncePlugin, + Mod, withAndroidManifest, withDangerousMod, withInfoPlist, } from "@expo/config-plugins"; +import { ExpoConfig } from "@expo/config-types"; import { generateOverrides, resolveFlagsToInvert } from "../api"; import pkg from "../../package.json"; import { withFlaggedAutolinking } from "./withFlaggedAutolinking"; @@ -49,25 +51,57 @@ const withAppleBuildFlags: ConfigPlugin<{ flags: string[] }> = ( }); }; -const withBundleFlags: ConfigPlugin<{ flags: string[] }> = (config, props) => { +type BundlePluginProps = { flags: string[] }; + +const createCrossPlatformMod = + ({ + config, + props, + }: { + config: ExpoConfig; + props: BundlePluginProps; + }): Mod => + async (modConfig) => { + const { flags } = props; + let flagsToEnable = new Set(flags); + const invertable = await resolveFlagsToInvert(config); + if (invertable.flagsToEnable.size > 0) { + flagsToEnable = mergeSets(flagsToEnable, invertable.flagsToEnable); + } + await generateOverrides({ + flagsToEnable, + flagsToDisable: invertable.flagsToDisable, + }); + return modConfig; + }; + +const withAndroidBundleBuildFlags: ConfigPlugin = ( + config, + props +) => { return withDangerousMod(config, [ - "ios", // not platform-specific, but need to specify - async (modConfig) => { - const { flags } = props; - let flagsToEnable = new Set(flags); - const invertable = await resolveFlagsToInvert(config); - if (invertable.flagsToEnable.size > 0) { - flagsToEnable = mergeSets(flagsToEnable, invertable.flagsToEnable); - } - await generateOverrides({ - flagsToEnable, - flagsToDisable: invertable.flagsToDisable, - }); - return modConfig; - }, + "android", + createCrossPlatformMod({ config, props }), ]); }; +const withAppleBundleBuildFlags: ConfigPlugin = ( + config, + props +) => { + return withDangerousMod(config, [ + "ios", + createCrossPlatformMod({ config, props }), + ]); +}; + +const withBundleFlags: ConfigPlugin<{ flags: string[] }> = (config, props) => { + return withAppleBundleBuildFlags( + withAndroidBundleBuildFlags(config, props), + props + ); +}; + const parseEnvFlags = () => { const envFlags = process.env.EXPO_BUILD_FLAGS; if (!envFlags) { diff --git a/test/overrides/default-flags.yml b/test/overrides/default-flags.yml index 76826f5..12ef6ee 100644 --- a/test/overrides/default-flags.yml +++ b/test/overrides/default-flags.yml @@ -1,5 +1,9 @@ mergePath: "constants/buildFlags.ts" flags: + secretAndroidFeature: + value: false + meta: + team: "platform" secretFeature: value: false meta: diff --git a/test/overrides/expected-api-override.ts b/test/overrides/expected-api-override.ts index 14bda89..447343e 100644 --- a/test/overrides/expected-api-override.ts +++ b/test/overrides/expected-api-override.ts @@ -1,5 +1,6 @@ export const BuildFlags = { newFeature: true, publishedFeatured: true, + secretAndroidFeature: false, secretFeature: false }; diff --git a/test/overrides/expected-cli-override.ts b/test/overrides/expected-cli-override.ts index a5b303a..78bd037 100644 --- a/test/overrides/expected-cli-override.ts +++ b/test/overrides/expected-cli-override.ts @@ -1,5 +1,6 @@ export const BuildFlags = { newFeature: false, publishedFeatured: true, + secretAndroidFeature: false, secretFeature: true }; diff --git a/test/run-integration.sh b/test/run-integration.sh index 9f27eb1..b38fd79 100755 --- a/test/run-integration.sh +++ b/test/run-integration.sh @@ -1,13 +1,18 @@ #!/bin/bash +# +# WARNING - these tests build on top of each other +# adjust your initial test flag state accordingly +# + set -e -function logMark () { - echo "" - echo "###################################################################" - echo "$1" - echo "###################################################################" - echo "" +function logMark() { + echo "" + echo "###################################################################" + echo "$1" + echo "###################################################################" + echo "" } logMark "Setting up test environment" @@ -24,5 +29,8 @@ node ../test/test-babel-plugin.js logMark "Running test-config-plugin.js" node ../test/test-config-plugin.js +logMark "Running test-config-plugin-android.js" +node ../test/test-config-plugin-android.js + logMark "Running test-autolinking.js" node ../test/test-autolinking.js diff --git a/test/test-config-plugin-android.js b/test/test-config-plugin-android.js new file mode 100644 index 0000000..af12d70 --- /dev/null +++ b/test/test-config-plugin-android.js @@ -0,0 +1,70 @@ +const fs = require("fs"); +const cp = require("child_process"); +const yaml = require("yaml"); + +const expectedRuntimeModule = ` +export const BuildFlags = { + bundleIdScopedFeature: true, + newFeature: true, + publishedFeatured: true, + secretAndroidFeature: true, + secretFeature: false +}; +`; + +addBundleIdScopedFlag(); +installExpoConfigPlugin(); +runPrebuild(); +assertFlagsAllTrue(); + +function addBundleIdScopedFlag() { + const flagsYmlString = fs.readFileSync("flags.yml", { encoding: "utf-8" }); + const flagConfig = yaml.parse(flagsYmlString); + flagConfig.flags.bundleIdScopedFeature = { + value: false, + invertFor: { + bundleId: ["com.example.app"], + }, + }; + fs.writeFileSync("flags.yml", yaml.stringify(flagConfig)); +} + +function installExpoConfigPlugin() { + const expoConfig = JSON.parse(fs.readFileSync("app.json", "utf-8")); + expoConfig.expo.plugins.push("expo-build-flags"); + expoConfig.expo.ios.bundleIdentifier = "com.example.app"; + expoConfig.expo.android.package = "com.example.app"; + fs.writeFileSync("app.json", JSON.stringify(expoConfig, null, 2)); +} + +function runPrebuild() { + cp.execSync("./node_modules/.bin/expo prebuild -p android --clean", { + env: { + ...process.env, + CI: 1, + EXPO_BUILD_FLAGS: "secretAndroidFeature", + }, + }); +} + +function assertFlagsAllTrue() { + const fileContents = fs.readFileSync("constants/buildFlags.ts", "utf8"); + if (fileContents.trim() !== expectedRuntimeModule.trim()) { + console.log( + "received:\n\n", + `>${fileContents.trim()}<`, + "\n\n", + "expected:\n\n", + `>${expectedRuntimeModule.trim()}<`, + "\n\n" + ); + + throw new Error( + "Expected runtime buildFlags.ts module to contain all flags as true" + ); + } + + console.log( + "Assertion passed: Runtime build flags enabled by config plugin!" + ); +} diff --git a/test/test-config-plugin.js b/test/test-config-plugin.js index 42aeb68..8934c49 100644 --- a/test/test-config-plugin.js +++ b/test/test-config-plugin.js @@ -7,6 +7,7 @@ export const BuildFlags = { bundleIdScopedFeature: true, newFeature: true, publishedFeatured: true, + secretAndroidFeature: false, secretFeature: true }; `;