Skip to content
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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ The arguments after the override command are the flags you want to `+` enable or

You can run `yarn build-flags ota-override` instead of "override" to do the same but also consider the branch name in two supported CI environments: Github and Gitlab. Use the `ota.branches` array in the flags.yml to setup that matching and branch-based enablement.

Use `--skip-if-env <ENV_VAR_NAME>` passing the name of the environment variable to check. If the variable has a truthy value the CLI command will be a no-op/skipped. This can be useful in CI contexts like EAS where other processes may handle generating the runtime build flags. In the case of EAS you could use `--skip-if-env EAS_BUILD`

### Set Flags in CI & for Static Builds

To set flags for EAS builds, set the `EXPO_BUILD_FLAGS` environment variable in `eas.json` for your profile. This value will be available to the config plugin at build time in EAS when you add it to your `app.json` plugins array:
Expand Down
90 changes: 90 additions & 0 deletions src/cli/main.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { describe, it, expect } from "@jest/globals";
import { parseArgs } from "./main";

describe("parseArgs", () => {
describe("command parsing", () => {
it("should parse override command", () => {
const args = ["yarn", "build-flags", "override"];
const result = parseArgs(args);
expect(result.command).toBe("override");
});

it("should parse init command", () => {
const args = ["yarn", "build-flags", "init"];
const result = parseArgs(args);
expect(result.command).toBe("init");
});

it("should parse ota-override command", () => {
const args = ["yarn", "build-flags", "ota-override"];
const result = parseArgs(args);
expect(result.command).toBe("ota-override");
});
});

describe("flag parsing", () => {
it("should parse flags to enable with + prefix", () => {
const args = ["yarn", "build-flags", "override", "+feature1", "+feature2"];
const result = parseArgs(args);
expect(result.flagsToEnable).toEqual(new Set(["feature1", "feature2"]));
});

it("should parse flags to disable with - prefix", () => {
const args = ["yarn", "build-flags", "override", "-feature1", "-feature2"];
const result = parseArgs(args);
expect(result.flagsToDisable).toEqual(new Set(["feature1", "feature2"]));
});

it("should parse mixed enable and disable flags", () => {
const args = [
"yarn",
"build-flags",
"override",
"+enableThis",
"-disableThis",
];
const result = parseArgs(args);
expect(result.flagsToEnable).toEqual(new Set(["enableThis"]));
expect(result.flagsToDisable).toEqual(new Set(["disableThis"]));
});
});

describe("--skip-if-env option", () => {
it("should extract skipIfEnv when option comes after command", () => {
const args = [
"yarn",
"build-flags",
"override",
"--skip-if-env",
"EAS_BUILD",
];
const result = parseArgs(args);
expect(result.skipIfEnv).toBe("EAS_BUILD");
expect(result.command).toBe("override");
});

it("should handle flags alongside --skip-if-env", () => {
const args = [
"yarn",
"build-flags",
"override",
"+feature",
"--skip-if-env",
"CI",
"-other",
];
const result = parseArgs(args);
expect(result.command).toBe("override");
expect(result.skipIfEnv).toBe("CI");
expect(result.flagsToEnable).toEqual(new Set(["feature"]));
expect(result.flagsToDisable).toEqual(new Set(["other"]));
});

it("should return undefined skipIfEnv when option is not provided", () => {
const args = ["yarn", "build-flags", "override", "+flag"];
const result = parseArgs(args);
expect(result.skipIfEnv).toBeUndefined();
});
});
});

37 changes: 32 additions & 5 deletions src/cli/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,28 @@ import { readFile, writeFile } from "fs/promises";
import { BuildFlags } from "../api/BuildFlags";
import { generateOverrides } from "../api/generateOverrides";

const parseArgs = (args: string[]) => {
export const shouldSkip = (envKey: string | undefined): boolean => {
if (envKey && process.env[envKey] !== undefined) {
console.log(`Skipping build-flags command because ${envKey} is set in environment (--skip-if-env)`);
return true;
}
return false;
};

export const parseArgs = (args: string[]) => {
let command;
let skipIfEnv: string | undefined;
const flagsToDisable = new Set<string>();
const flagsToEnable = new Set<string>();
args.slice(2).forEach((arg) => {

const argsCopy = args.slice(2);
const skipIfEnvIndex = argsCopy.indexOf("--skip-if-env");
if (skipIfEnvIndex !== -1) {
skipIfEnv = argsCopy[skipIfEnvIndex + 1];
argsCopy.splice(skipIfEnvIndex, 2);
}

argsCopy.forEach((arg) => {
if (arg.startsWith("-")) {
flagsToDisable.add(arg.replace("-", ""));
return;
Expand All @@ -21,18 +38,22 @@ const parseArgs = (args: string[]) => {

command = arg;
});
return { command, flagsToDisable, flagsToEnable };

return { command, flagsToDisable, flagsToEnable, skipIfEnv };
};

const printHelp = (command?: string) => {
if (command) {
console.error(`Unknown command: ${command}`);
}
console.log(`Usage: build-flags [command] [flags]
console.log(`Usage: build-flags [command] [options] [flags]
Commands:
init Initialize flags.yml and buildFlags.ts for the project in the current directory
override Override default flags with provided flag arguments: +flag to enable, -flag to disable
ota-override Override default flags like "override" but also consider branch matching rules

Options:
--skip-if-env <ENV_VAR> Skip execution if the specified environment variable is set
`);
};

Expand Down Expand Up @@ -71,8 +92,14 @@ const initFlagsFile = async () => {
};

const run = async () => {
const { command, flagsToDisable, flagsToEnable } = parseArgs(process.argv);
const { command, flagsToDisable, flagsToEnable, skipIfEnv } = parseArgs(
process.argv
);

if (shouldSkip(skipIfEnv)) {
return;
}

if (command === "init") {
await initFlagsFile();
return;
Expand Down