Hive
perf(server): compile a single locale in :test to speed up cold test builds
GitHub issue · Closed
Speeds up a cold
mix testin a fresh worktree by not compiling all ten ex_cldr locales in the:testenvironment.
What changed
Tuist.Environment.dev_single_locale?/0 is renamed to single_locale?/0 and widened from dev?() and not dev_all_locales?() to (dev?() or test?()) and not dev_all_locales?(). Both :dev and :test now compile only the "en" locale by default. The three compile-time consumers were updated: the ex_cldr backend (Tuist.Cldr.Configuration), the Gettext backend (TuistWeb.Gettext.Configuration), and the supported-language list (Tuist.Locale).
The existing TUIST_DEV_ALL_LOCALES=1 escape hatch still compiles the full set. Tests that assert non-en behaviour are tagged :locale and excluded by default (via test_helper.exs) unless the full set was compiled:
TuistWeb.CldrHelpersTest— assertses/zh_Hantnumber, money, and percent formatting.TuistWeb.LocaleTest—normalize_locale/1filters candidates throughTuist.Locale.supported_locales/0.- The docs-URL describe block in
TuistWeb.Marketing.LocalizationTest— rewrites between non-enlocale segments. - The
preferred_localetests inaccounts_test.exs/user_test.exs— the changeset validates inclusion againstsupported_locales/0.
CI’s test job now sets TUIST_DEV_ALL_LOCALES=1 (server.yml) so it compiles the full locale set and runs the :locale tests, keeping i18n coverage unchanged in CI.
Why
:test fell into the all-locales branch of the gate while :dev compiled one, so a fresh worktree with a cold _build/test regenerated the ex_cldr code for all ten locales on the first mix test, whereas the long-running dev server stayed fast on its single-locale build and masked the discrepancy. This was a dev/test inconsistency, not an inherent cost: production (MIX_ENV=prod) is unaffected and still compiles every locale.
Measured impact
Anchored to real CI timings, since CI runs the repo-pinned Elixir 1.19.5. On main today the Test job — which already compiles all ten locales — breaks down roughly as:
| Step | Duration |
|---|---|
| Compile (all 10 locales, incl. deps) | ~283s |
| Setup database | ~159s |
| Run tests | ~305s |
| Total | ~880s (~14.7 min) |
So compiling all ten locales is a modest slice of a ~15-minute job — localization is not the CI bottleneck. This PR keeps CI on all locales, so CI cost is unchanged. The win is local: a fresh worktree’s first mix test no longer regenerates the ex_cldr backend for all ten locales.
Caveat on an earlier local number: I first measured a ~16-min all-locales cldr.ex compile, but that shell was running Elixir 1.20.1 (pulled from a global mise latest pin), not the repo-pinned 1.19.5 that CI uses. 1.20.1’s type checker appears to choke on the large generated cldr module. On the pinned toolchain the all-locales compile is a few minutes (per the CI table), so the local saving from this change is on the order of a couple of minutes off a cold compile, not fifteen.
Root cause vs. alternatives
The compiled locale set is a compile-time decision (ex_cldr generates code per locale via a macro), so the fast/full split has to be a compile-time flag. Keeping Application.compile_env (rather than reading the env var directly) is deliberate: it makes Mix raise a clear “recompile your project” error if the build and the flag disagree, instead of silently running the :locale tests against a single-locale build. The trade-off is that toggling the flag on an already-built worktree needs a recompile; a fresh build with the flag set — CI, or a dev’s first run — just works.
User/developer impact
- Default
cd server && mix testcompiles one locale; the:localetests are reported as excluded. - No production behaviour change; managed builds compile all locales as before.
- CI behaviour is unchanged (still all locales, all tests).
How to test locally
Default fast path (single locale):
cd server && mix test
The :locale-tagged tests show as excluded and the cold _build/test compile no longer generates the full locale set.
Full i18n coverage (what CI runs) — set the flag on a fresh test build:
cd server
TUIST_DEV_ALL_LOCALES=1 mix test
If you flip the flag on an already-built worktree, Mix will (correctly) refuse with a :dev_all_locales compile-env mismatch; force the recompile first, e.g. touch config/config.exs, then rerun.
Functional validation
cd server && mix test test/tuist_web/helpers/cldr_helpers_test.exs test/tuist/accounts/user_test.exson a cold single-locale build: 9 passed, 5 excluded — the:localetests are skipped and the rest pass.- Confirmed the single-locale
_build/testgenerates onlyTuist.Cldr for 2 locales [:en, :und], and thatTUIST_DEV_ALL_LOCALES=1regeneratesTuist.Cldr for 14 localesfor the opt-in path.
🤖 Generated with Claude Code
Investigate, reproduce, or fix this item in an isolated repository. Each Flight preserves its outcome and agent session.
Start a Flight and preserve its objective, outcome, and session here.
No GitHub comments yet.