udara_cli 1.3.2
udara_cli: ^1.3.2 copied to clipboard
A CLI tool for managing whitelabel Flutter projects with multi-client support
1.3.2 #
- NEW:
udara_cli setup --clients <new> --from <existing>: starts the new client's.envand.env_testfrom an existing client's, with the new client's folder paths and the values from itsBRANDING.md(Udara Onboarding's "Promote to repo"). Release signing keys are left out, existing files are kept, and it warns when the bundle id or names are still the existing client's.udara_cli build ... -- <flutter build arguments>: anything after--is appended to everyflutter buildof the run (also in parallel batches), e.g.-- --target-platform android-arm64 --split-debug-info=build/symbols.
1.3.1 #
Everything below is opt-in or backwards compatible: existing projects keep their current behaviour until they run udara_cli migrate-config.
- NEW:
udara_cli generate-configregenerates the generated config class (lib/udara_config.g.dart) from the client.envfiles, e.g. after adding a key, without branding or cleaning anything. It reports keys thatapp_config.includeleaves out. The IDE extensions (0.3.0) add a Regenerate App Config action for it.- A
**/*.g.dartrule in.gitignore(common for build_runner output) kept the generated config out of git, so fresh clones didn't compile.generate-config,migrate-config --applyandsetupnow add!lib/udara_config.g.dartto.gitignorewhen needed, anddoctorfails when the file is ignored.
- SECURITY:
- New generated app config (
app_config: mode: generatedinudara.yaml): instead of bundling the client's.envas a Flutter asset (readable by anyone who unzips the APK/IPA, together with the default client's.env), each build generateslib/udara_config.g.dartwith the client's values as typed constants and restores it afterwards. No config file ships, build-only keys (DEVELOPMENT_TEAM,ASSETS_PATH, configurable) are left out, and no other client's values are included. The class mirrors flutter_dotenv's API (env,get,maybeGet,getInt,getDouble,getBool,isEveryDefined,isInitialized) and has the same fields for every client and environment. - Allow-list (
app_config.include): only the listed keys are compiled in.migrate-configfills it with the keys the code reads (literal reads, plus keys detected from string literals when code reads keys by computed name, opt-in with--include-detected);doctorwarns when code reads a key that isn't listed. - Native builds keep their root
.env, only when needed: in generated mode,buildwrites a root.env(the client's.envplus its.secrets, marked with a header) only when a native build file reads it (e.g. Gradle release signing), never as an app asset, and removes it after the build.whitelabelnever writes it;cleanremoves a leftover one.migrate-configreports native build files that read it. list-clients --jsonreports the project'sappConfigmode, so the IDE extensions only pass--dart-define=CLIENT_ENV=.envin dotenv mode..secretsfiles:clients/<client>/.secrets(and.secrets_test) hold build-time secrets that are never compiled in, bundled, copied into branding assets or listed; hooks get their path asUDARA_SECRETS_FILE.setupgit-ignores them.doctorwarns about secret-looking values that would ship with the app (in either mode), fails when a.secretsfile isn't git-ignored, and in generated mode checks the generated file, that no.envis still an asset and that nodotenv.load()is left.
- MIGRATION (nothing changes until you opt in):
- Projects without an
app_configsection keep the existing dotenv behaviour exactly;buildanddoctornow point out that.envis readable in the shipped app. - New
udara_cli migrate-configpreviews, then with--applymigrates a project: sets generated mode, generates the class from the default client, rewrites dotenv usages to the generated class, removesdotenv.load()calls, the unusedCLIENT_ENVconstant and.envassets, and git-ignores.secrets..envfiles are never modified. It refuses to run on a dirty git tree (sogit checkout .undoes it) and lists anything it can't rewrite safely; items that would break the app block--applyunless--force. setupon a new project (noclients/yet) starts in generated mode and doesn't install flutter_dotenv.
- OTHER:
buildnow leaves the project exactly as it found it: besides its config files it snapshots and restores everything branding and hooks change (applicationId,AndroidManifest.xml,Info.plist, the Xcode project, Androidres/,Assets.xcassets,Base.lproj, and Firebase outputs). Previously the client's bundle id, app name, icons and splash stayed in the project after a build.whitelabelstill keeps branding applied. Hooks that skip work when their output already matches (like the example Firebase hook) now run on every build.- Cleanup restores every file a run backed up, instead of a fixed list.
cleanregenerates the default client's config afterwhitelabel --keepin generated mode.
- FIXES:
whitelabel --keep(the editors' Run Client) now backs up everything it changes (pubspec, launcher icon config, fonts, generated config, native branding) and leaves those backups in.udara/instead of restoring them. The next run restores the original project before applying its client, andcleanrestores it too. Previously, running a client without fonts after one with fonts kept the previous client's fonts and pubspecfonts:entry, two font clients in a row mixed their fonts, andcleanrestored the font folder but not the pubspec entry.- Client fonts replace
assets/fontsfrom a snapshot instead of parking the originals inassets/fonts.bak, so a project that had noassets/fontsgets none back. A leftoverassets/fonts.bakfrom older versions is still restored. cleanon a project branded by an older version (no backups) repairs the sections udara_cli manages (pubspecfonts:, theassets/branding/entry, the splash image and the launcher icon path) from the last commit.assets/brandingis snapshotted and restored exactly, so a branding folder a run created (including the default client's) no longer lingers after cleanup, and switching clients leaves no other client's folder behind.buildchecks each Android artifact's signing certificate. Gradle signs a release build with the debug key when it finds no release keystore (for example a misnamedkey.propertiesentry), and the build still succeeds; Google Play then rejects the upload. A debug-signed AAB now fails the build and is kept as*.debug-signed.aabso it can't be uploaded by mistake, before anyafter_buildhook runs. A debug-signed APK only warns, since those are common for QA.doctorreports a project branded with--keepas such instead of as an interrupted run.
- BATCH & PARALLEL BUILDS:
- Batch builds:
--client,--platformand--typeaccept several values (comma-separated or repeated), and--all-clientsbuilds every client. - Parallel builds: batches are split into jobs of one client on one platform and run
--parallel Nat a time (autoby default: 1-4 based on RAM and CPU). Each parallel job runs in its own synced copy of the project under~/.udara_cli/workspaces/, so builds never touch each other's files or your working copy; the copies keep their build, Gradle and CocoaPods caches.udara_cli clean --workspacesdeletes them. - Per-client versions:
--build-version 1.4.0+12or--build-version acme=1.4.0+12,beta=2.0.0sets the version for a build without editing pubspec.yaml (passed to Flutter as--build-name/--build-number; without+nthe pubspec build number is kept). - Live progress: a redrawing terminal view with overall percent, ETA and each running job's step (plain status lines in CI and IDE consoles). ETAs are estimated from the project's build history.
--progress-file <path>writes a JSON snapshot for tools. - Per-job logs in
build/udara/logs/; the summary shows the lines around each failure. - Cancel with Ctrl+C or a termination/hang-up signal (IDE stop buttons): every worker and every Flutter/Gradle/Xcode process it started is stopped, finished artifacts are kept, and a single build restores the project immediately. Exit code 130.
--fail-faststops the whole batch at the first failure.- The IDE extensions (0.3.0) add Build Multiple Clients… with per-client versions, parallelism and progress bars on top of this.
- BUILD OUTPUT:
- Artifacts are collected in
build/udara/<client>/<client>_v<version>.<type>instead of being renamed inside Flutter's output folders, so a later build can't overwrite or clean them up. - In
after_brandinghooks of a multi-target job,UDARA_PLATFORMandUDARA_BUILD_TYPElist all targets;after_buildhooks get the single target.
1.3.0 #
- NEW:
- Hooks: declare commands in
udara.yamlthat run atafter_branding(after the client's native branding is applied, beforeflutter build; also duringwhitelabel, so IDE "Run Client" flows get it) andafter_build(after a successful build, withUDARA_ARTIFACT). Hooks receiveUDARA_CLIENT,UDARA_CLIENT_DIR,UDARA_BUNDLE_ID,UDARA_ENV,UDARA_VERSIONand more; a failing hook stops the run and the project is still restored. Unknown hook names fail fast. doctorvalidatesudara.yamland checks hook scripts exist and are executable.example/hooks/with ready-made Firebase (FCM) and OneSignal push notification hooks.
- FIXES:
buildandwhitelabelnow restore the project first when a previous run was interrupted. Previously the stale backups were restored by the new run's cleanup, silently reverting part of the new client's branding (e.g. the iOS bundle id).
1.2.0 #
- FIXES:
.envparsing now handles inline# comments, single quotes andexport KEY=VALUE. Previously a value such asDEVELOPMENT_TEAM="ABCD1234" #comment(the templatesetupgenerated) was read asABCD1234" #commentand patched into the Xcode project verbatim.- An existing root
.envis backed up before a build stages the client env there, and restored afterwards; when no root.envexisted the staged copy is removed on cleanup instead of leaving client secrets behind. - Built-in ignore patterns such as
*.jksand*.pemnow also match files in sub-folders of the client assets directory, so nested keystores and keys are no longer copied into the app bundle. clients/default/.env(the runtime fallback registered bysetup) is no longer stripped fromflutter.assetswhen a client is applied.whitelabelnow stages the env the same way asbuild(root.env, registered as an asset), honours--testandDEVELOPMENT_TEAM, and restores the staged project files afterwards (the iOS project file is left as patched). New--keepflag leaves them in place so the app can be run as the client withflutter run --dart-define=CLIENT_ENV=.env.- Unknown options (e.g.
udara_cli build --bogus) are reported as usage errors with the command's help instead of an "Unexpected Error" asking to file a bug. - iOS builds record
ipaas the artifact type (instead of the Android defaultaab) and the built.ipais renamed to<client>_v<version>.ipalike Android artifacts. - The Slack build summary is now actually posted for every build; previously only APK uploads happened and AAB/iOS/failed builds produced no summary message.
- The splash screen image now uses
APP_LOGO_PATH(falling back toAPP_ICON_PATH) as documented, instead of always using the app icon. - Client fonts are looked up in
clients/<client>/fontsfirst (whatdoctorvalidates) and then<ASSETS_PATH>/fonts. - The default client's branding folder is preserved consistently: the pre-sync cleanup no longer deletes it while the post-build cleanup kept it.
- Removed the stray
.udara_build_history.jsonfrom the repository and ignored it.
- IMPROVEMENTS:
- Global
--verboseflag: prints stack traces on failures and enables Slack debug output. doctorvalidates icon/logo paths again by resolving them to the client folder, flags images that are still the generated placeholder, checksfonts.yamlreferences against the font files present, validatesBUNDLE_IDformat, warns about leftover.udarastate from interrupted builds and about.udara_build_history.jsonmissing from.gitignore.setup --clientsgenerates valid solid-colour placeholder PNGs (so icon/splash tooling runs before real artwork exists), a per-clientREADME.md, a cleaner.envtemplate, addsflutter_dotenvwhen missing, and appends.udara/,.udara_build_history.jsonand/.envto.gitignore.buildfails fast with a pointed message when the client folder, its env file, orflutter_launcher_icons.yamlis missing (listing the available clients), and prints a build summary with duration and artifact path.list-clientsshows each client's app name, bundle id and whether a.env_testexists.historyprints the artifact path of successful builds and rejects a non-numeric--limit.cleanrestores any files left backed up by an interrupted build before runningflutter clean.- Shared step/validation/Slack helpers moved into the base command; dead code removed.
- Added a unit test suite (
dart test) covering env parsing, pubspec asset editing, backup/restore, asset sync ignore rules and artifact renaming. list-clients --jsonandhistory --jsonemit machine-readable output (human log lines move to stderr) for editor integrations and scripts.- New IDE extensions under
extensions/: a VS Code extension and an Android Studio / IntelliJ plugin that list clients and env files and trigger run, build, whitelabel, doctor, clean and diff through the CLI.
1.1.3 #
- FIXES (published to pub.flutter-io.cn on 2026-08-06; notes copied from that release):
- Improved
cleancommand logging by reporting the project cleanup phase before cleanup completes. - Added temporary
.envremoval during cleanup so stale environment files do not persist between builds. - Refined cleanup behavior to ensure project state is restored cleanly after asset refreshes.
1.1.2 #
- FIXES:
- Cleaned up the
doctorcommand diagnostics and kept the asset-path validation comments aligned with the actual client asset layout. - Ensured local project metadata is excluded from version control by ignoring
.udara/workspace artifacts. - Prepared the package for a clean publish by keeping the repo state release-ready.
1.1.1 #
- FIXES:
- Hardened backup/restore behavior by storing backups in a project-local
.udara/backupsdirectory instead of side-by-side.bakfiles, making restore operations more reliable and less likely to clobber unrelated files. - Protected managed branding folders from accidental deletion by refusing to remove non-managed asset directories and cleaning up only inactive client branding folders marked by
udara_cli. - Improved asset sync validation so builds fail early when no branding assets are copied for the selected client, with clearer remediation guidance.
- Corrected the client
.envasset path wiring during white-label setup to ensure the proper env file is tracked for each client.
1.1.0 #
- NEW:
doctorcommand: Validates project & client setup before building — checks required project files, pubspec dependencies (includingflutter_dotenv), and per-client.env/.env_testpresence, required keys, referenced asset paths, and font configuration. Run withudara_cli doctororudara_cli doctor --client <name>.historycommand: Every build (success or failure) is now recorded to a project-local.udara_build_history.json. View recent builds withudara_cli history, filter with--client/--limit, or clear with--clear.diffcommand: Compare environment configuration between two clients withudara_cli diff --client-a <NAME> --client-b <NAME>. Add--testto compare.env_testfiles, or--allto show every key instead of only the ones that differ.- Added an
example/folder demonstrating a full setup → build workflow.
- IMPROVEMENTS:
- Colored terminal output: Success, warning, and error messages are now color-coded (green/yellow/red) instead of emoji-only, with automatic fallback to plain text when the terminal doesn't support ANSI escapes (e.g. output piped to a file or CI log).
- Added
topicsand refined metadata inpubspec.yamlfor improved pub.flutter-io.cn discoverability. - Expanded dartdoc comments across the public API.
1.0.6 #
- FIXES:
- Dynamic iOS Development Team: Added support for reading client-specific DEVELOPMENT_TEAM IDs from environment variables during iOS builds.
- Centralized Structured Logging: Replaced ad-hoc print() statements with a dedicated Logger class (phase, info, success, warning, error) to produce clean, scannable terminal output.
- Enhanced Exception Tracking: Replaced generic throws with contextual BuildException instances that include actionable remediation suggestions (fix) to easily pinpoint and resolve failure root causes.
- Built-in default ignore rules to prevent accidental copying of sensitive files such as:
service_account.json*.pem,*.key,*.p12,*.jks,*.keystore
- Resilient Pipeline Execution: Improved file I/O checks, pre-flight configuration validation, and build step notifications across all commands.
- Support for user-defined ignore patterns via
.udaraignorefile.