{"id":49368491,"url":"https://github.com/mozilla-mobile/fxios-ctl","last_synced_at":"2026-04-27T21:01:09.496Z","repository":{"id":332692895,"uuid":"1134663447","full_name":"mozilla-mobile/fxios-ctl","owner":"mozilla-mobile","description":"A tool for managing firefox-ios","archived":false,"fork":false,"pushed_at":"2026-04-15T15:17:44.000Z","size":372,"stargazers_count":1,"open_issues_count":2,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-15T16:41:54.397Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mozilla-mobile.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-15T02:53:38.000Z","updated_at":"2026-04-15T14:59:55.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/mozilla-mobile/fxios-ctl","commit_stats":null,"previous_names":["adudenamedruby/narya","adudenamedruby/fxios-ctl","mozilla-mobile/fxios-ctl"],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/mozilla-mobile/fxios-ctl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mozilla-mobile%2Ffxios-ctl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mozilla-mobile%2Ffxios-ctl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mozilla-mobile%2Ffxios-ctl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mozilla-mobile%2Ffxios-ctl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mozilla-mobile","download_url":"https://codeload.github.com/mozilla-mobile/fxios-ctl/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mozilla-mobile%2Ffxios-ctl/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32354574,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-27T20:07:02.737Z","status":"ssl_error","status_checked_at":"2026-04-27T20:07:00.910Z","response_time":128,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-27T21:00:58.049Z","updated_at":"2026-04-27T21:01:09.487Z","avatar_url":"https://github.com/mozilla-mobile.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🦊 `fxios`\n\nA CLI tool for managing tasks in the [firefox-ios](https://github.com/mozilla-mobile/firefox-ios) repository.\n\nIt is pronounced \"fix-e-os\".\n\n**NOTE:** This tool is still in **BETA**\n\n## Goals\n\nThe goals of this tool are simple:\n\n**1. Provide a thoroughly documented, understandable experience that will reduce tribal knowledge**\n\n**2. Provide easily reproducible commands for all developers \u0026 CI**\n\n**3. Provide a central place for important utilities used to manage the firefox-ios repo**\n\n```\n⚠️ A possible fourth goal - we're still deciding if this is truly a goal:\nProvide a simple, indirect way for new developers to discover tooling used in Swift development (eg. swiftlint)\n```\n\nBonus (slash most important) goal: **be dope by being ridiculously helpful**\n\nIf a command doesn't materially achieve one of these goals \u0026 the bonus goal, it likely shouldn't be part of `fxios`\n\n## Installation\n\n`fxios` is available through brew.\n\n```bash\nbrew tap mozilla-mobile/fxios\nbrew install fxios\n```\n\n**NOTE:** installing `fxios` will also install several dependencies through `brew`, that are used for firefox-ios:\n\n- [swiftlint](https://github.com/realm/SwiftLint)\n- [node](https://nodejs.org/en)\n\n## Configuration\n\n`fxios` uses a `.fxios.yaml` file in the firefox-ios repository root for configuration and validation that it's in the correct repository.\n\nFor the complete configuration reference, see [CONFIGURATION.md](CONFIGURATION.md).\n\n### Quick Start\n\nA minimal `.fxios.yaml` only needs the required `project` field:\n\n```yaml\nproject: firefox-ios\n```\n\n## Development\n\n### Requirements\n\n- macOS 14+\n- Swift 6.2+\n\nTo use this with the firefox-ios, repo, you will also need the dependencies from that repo.\n\n### Contributing\n\nContributing to `fxios` is easy: please fork the repo, make your changes, and submit a PR.\n\nFor a discussion of the design thoughts behind `fxios`, and what to add, please first read the [DESIGN_GUIDELINES.md](DESIGN_GUIDELINES.md) document.\n\nFor details on how commands are structured and how to add new ones, see [COMMAND_ARCHITECTURE.md](COMMAND_ARCHITECTURE.md).\n\n### Project structure\n\n```\nSources/fxios/\n├── fxios.swift                 # Entry point (@main)\n├── Core/                       # Where tools and utilities should be placed\n│   ├── CommandHelpers.swift    # Shared utilities for command implementations\n│   ├── Configuration.swift     # App constants (name, version, etc.)\n│   ├── DeviceShorthand.swift   # Simulator shorthand pattern matching (e.g., 17pro, air13)\n│   ├── Herald.swift            # Formatted output handling\n│   ├── Logger.swift            # Debug logging utility (enabled via --debug)\n│   ├── Products.swift          # Build product definitions (Firefox, Focus, Klar)\n│   ├── RepoDetector.swift      # Validates firefox-ios repository, loads .fxios.yaml\n│   ├── ShellRunner.swift       # Shell command execution\n│   ├── SimulatorManager.swift  # iOS Simulator detection and management\n│   ├── StringUtils.swift       # String transformation utilities\n│   └── ToolChecker.swift       # Tool availability checks (git, node, npm, xcodebuild)\n└── Commands/\n```\n\n### Development Tips\n\n```bash\n# Build\nswift build\n\n# Run in the fxios-ctl folder\nswift run fxios\n```\n\nTo test your local changes in a `firefox-ios` repo, it's recommened to create an alias, and using that after running `swift build` in the `fixios-ctl` repo to build your latest changes.\n\nFor example: `alias fxtest=path/to/fxios-ctl/.build/arm64-apple-macosx/debug/fxios`\n\nIf you're on an Intel machine, you might have to have a slightly different path.\n\n### Unit Testing Notes\n\nTests use the modern Swift Testing framework (`@Test`, `@Suite`, `#expect`).\n\n⚠️ **IMPORTANT:** Tests must be run with the `--no-parallel` flag to avoid concurrency issues. Many tests change the current working directory, which is global process state. Running tests in parallel _will_ cause cross-contamination between test suites.\n\n```bash\n# Run all tests (must use --no-parallel)\nswift test --no-parallel\n```\n\nAny new feature or command must include corresponding tests. Tests should cover:\n\n- Command configuration (abstract, discussion text)\n- Flag/option validation\n- Expected behavior with valid inputs\n- Error handling for invalid inputs\n- Edge cases\n\nSee existing test files in `Tests/fxiosTests/` for examples.\n\n### Outputting Status from `fxios`\n\nAll `fxios` output is handled by the `Herald`. To maintain clarity between `fxios`'s output and the output of tools/commands it wraps, we have a standard way of presenting output.\n\n```swift\nstatic func declare(\n    _ message: String,\n    asError: Bool = false,\n    isNewCommand: Bool = false,\n    asConclusion: Bool = false\n)\n```\n\n**Parameters:**\n\n- `message` - The text to display\n- `asError` - Adds 💥 to indicate an error or warning\n- `isNewCommand` - Resets state and uses 🦊 prefix (use at the start of each command)\n- `asConclusion` - Uses 🦊 prefix for the final message of a command\n\n**Prefix Logic:**\n\n| Context              | `asError` | Output Prefix |\n| -------------------- | --------- | ------------- |\n| `isNewCommand: true` | false     | 🦊            |\n| `isNewCommand: true` | true      | 🦊 💥         |\n| Continuation         | false     | ▒             |\n| Continuation         | true      | ▒ 💥          |\n| `asConclusion: true` | false     | 🦊            |\n| `asConclusion: true` | true      | 🦊 💥         |\n| After conclusion     | (ignored) | ▒             |\n\n**Multi-line handling:**\n\n- First line of message: uses computed prefix from table above\n- Subsequent lines within the same message: always `▒ ▒` (sub-continuation)\n\n**State behavior:**\n\n- `isNewCommand: true` resets all state - use this at the start of each command's `run()` method\n- After a conclusion (`asConclusion: true`), subsequent calls use normal `▒` prefix and ignore `asError`/`asConclusion` flags\n- Sub-continuation (`▒ ▒`) only applies to lines 2+ within a single multi-line message, not across separate calls\n\n**Example output:**\n\n```\n🦊 Starting build...\n▒ Compiling module A\n▒ Compiling module B\n▒ 💥 Warning: deprecated API usage\n▒ ▒ in file Foo.swift:42\n▒ Compiling module C\n🦊 Build complete!\n```\n\nThis is produced by:\n\n```swift\nHerald.declare(\"Starting build...\", isNewCommand: true)\nHerald.declare(\"Compiling module A\")\nHerald.declare(\"Compiling module B\")\nHerald.declare(\"Warning: deprecated API usage\\nin file Foo.swift:42\", asError: true)\nHerald.declare(\"Compiling module C\")\nHerald.declare(\"Build complete!\", asConclusion: true)\n```\n\n#### Raw output\n\nThe `Herald` also has a `raw()` function if you need to print out any text. This should almost exclusively be used for the `--expose` command.\n\n### Error Handling\n\n`fxios` follows consistent error handling patterns to ensure errors are never silently swallowed and always provide useful context. For detailed guidelines, see [ERROR_HANDLING.md](ERROR_HANDLING.md).\n\nKey principles:\n\n- All custom errors include `underlyingError` when wrapping other errors\n- No silent `catch` blocks - errors are always reported via Herald or re-thrown\n- Debug logging available via `--debug` flag for troubleshooting\n\n### Debug Logging\n\nPass the `--debug` flag to any command to enable detailed logging output:\n\n```bash\nfxios --debug doctor\n```\n\nDebug output goes to stderr and includes timestamps, file locations, and underlying error details. This is useful for troubleshooting issues or understanding `fxios`'s behavior.\n\n## Currently Supported Commands\n\n| Command           | Description                                                  |\n| ----------------- | ------------------------------------------------------------ |\n| `fxios bootstrap` | Bootstrap the repository for Firefox or Focus development    |\n| `fxios build`     | Build Firefox, Focus, or Klar for development                |\n| `fxios clean`     | Clean up cached or generated files                           |\n| `fxios doctor`    | Check development environment for required tools             |\n| `fxios l10n`      | Localization tools for managing XLIFF files and translations |\n| `fxios lint`      | Run SwiftLint on the codebase                                |\n| `fxios nimbus`    | Manage Nimbus feature configuration files                    |\n| `fxios run`       | Build and launch in the iOS Simulator                        |\n| `fxios setup`     | Clone and bootstrap the firefox-ios repository               |\n| `fxios telemetry` | Update telemetry configuration files                         |\n| `fxios test`      | Run tests for Firefox, Focus, or Klar                        |\n| `fxios version`   | Display or update version numbers across the repository      |\n\n#### `bootstrap`\n\nBootstraps the repository for development. By default, bootstraps the product specified in `.fxios.yaml` (`default_bootstrap`), or Firefox if not configured.\n\n#### `build`\n\nBuilds Firefox, Focus, or Klar for development using xcodebuild. By default, builds the product specified in `.fxios.yaml` (`default_build_product`), or Firefox if not configured.\n\nThe simulator is auto-detected to use the latest iOS version with a standard iPhone model (non-Pro, non-Max).\n\nPlease read [Simulator Shorthand](#simulator-shorthand) for an explanation of the `--sim` flag.\n\n#### `clean`\n\nCleans up various cached or generated files.\n\n#### `doctor`\n\nChecks your development environment for required tools and configuration. This is useful for onboarding new developers or troubleshooting build issues.\n\nChecks performed:\n\n- **Required tools**: git, node, npm, swift, xcodebuild, xcode-select, simctl\n- **Optional tools**: swiftlint (reports status but won't flag as issue if missing)\n- **Repository context** (when run from firefox-ios): validates `.fxios.yaml`, checks git hooks installation, shows configured defaults\n\n#### `l10n`\n\nLocalization tools for managing XLIFF files and translations between Xcode projects and Mozilla's translation platform (Pontoon). Subcommands:\n\n- `export` - Extract localizable strings from Xcode to XLIFF files in the l10n repository\n- `import` - Import translated XLIFF files back into the Xcode project\n- `templates` - Create blank template XLIFF files for translators\n\nFor `export` and `import`, you must specify either `--product` or `--project-path`:\n\n```bash\n# Export Firefox strings (using product preset)\nfxios l10n export --product firefox --l10n-project-path /path/to/l10n-repo\n\n# Import Focus translations (using product preset)\nfxios l10n import --product focus --l10n-project-path /path/to/l10n-repo\n\n# Export with explicit project path\nfxios l10n export --project-path ./Client.xcodeproj --l10n-project-path /path/to/l10n-repo\n```\n\nThese commands handle locale code mapping between Xcode and Pontoon formats, filtering of non-translatable keys, required translation validation, and comment overrides from `l10n_comments.txt`.\n\n#### `lint`\n\nRuns SwiftLint on the codebase. By default, lints only files changed compared to the main branch.\n\n#### `nimbus`\n\nManages Nimbus feature flags across the firefox-ios codebase. Subcommands:\n\n- `refresh` - Updates the include block in `nimbus.fml.yaml` with feature files from the `nimbus-features/` directory\n- `add` - Creates a new feature with all required boilerplate (YAML file and Swift code)\n- `remove` - Removes a feature from all locations\n\n#### `run`\n\nBuilds and launches Firefox, Focus, or Klar in the iOS Simulator. This is equivalent to running `fxios build` followed by installing and launching the app.\n\nPlease read [Simulator Shorthand](#simulator-shorthand) for an explanation of the `--sim` flag.\n\n#### `telemetry`\n\nUpdates Glean telemetry configuration files.\n\n#### `test`\n\nRuns tests for Firefox, Focus, or Klar using xcodebuild. By default, runs unit tests for the product specified in `.fxios.yaml` (`default_build_product`), or Firefox if not configured.\n\nTest plans available:\n\n- `unit` - Unit tests (default)\n- `smoke` - Smoke/UI tests\n- `accessibility` (or `a11y`) - Accessibility tests (Firefox only)\n- `performance` (or `perf`) - Performance tests (Firefox only)\n- `full` - Full functional tests (Focus/Klar only)\n\nPlease read [Simulator Shorthand](#simulator-shorthand) for an explanation of the `--sim` flag.\n\n#### `version`\n\nDisplays or updates version numbers across the repository. Without options, shows the current version and git SHA.\n\n### Simulator Shorthands\n\nThe `--sim` option in `build`, `run`, and `test` subcommands accepts either a shorthand code or the full simulator name (e.g., `--sim 17pro` or `--sim \"iPhone 17 Pro\"`). Use the `list-sims` subcommand to see available simulators on your current machine and their respective shorthands.\n\n#### Design Principles for Shorthand Patterns\n\n1. Shorthands must be derivable - A user should be able to guess the shorthand from the device name\n2. No shorthand is OK - Devices that don't fit the pattern get \"-\" and require the full name\n3. Bidirectional consistency - parseShorthand() and shorthand(for:) use the same rules\n\nIn general, these design principles result in the following shorthands on my machine:\n\niPhone:\n| Pattern | Examples | Matches |\n| --------- | ------------------ | ----- |\n| `\u003cN\u003e` | 17 | iPhone 17 (base model only) |\n| `\u003cN\u003epro` | 17pro | iPhone 17 Pro |\n| `\u003cN\u003emax` | 17max | iPhone 17 Pro Max |\n| `\u003cN\u003eplus` | 16plus | iPhone 16 Plus |\n| `\u003cN\u003ee` | 16e | iPhone 16e |\n| `se` | se | iPhone SE (any generation) |\n| `air` | air | iPhone Air |\n\niPad:\n| Pattern | Examples | Matches |\n| --------- | ------------------ | ---- |\n| `air\u003csize\u003e` | air11, air13 | iPad Air 11/13-inch (13 also matches 12.9) |\n| `pro\u003csize\u003e` | pro11, pro13, pro129 | iPad Pro (13 matches 12.9 too; 129 is precise) |\n| `mini` | mini | iPad mini (any - but latest) |\n| `mini\u003cN\u003eg` | mini6g, mini7g | iPad mini (Nth generation) |\n| `miniA\u003cchip\u003e` | miniA17 | iPad mini (A17 Pro) |\n| `pad\u003cN\u003eg` | pad10g | iPad (Nth generation) |\n| `padA\u003cchip\u003e` | padA16 | iPad (A16) |\n\nMatching behavior precision notes:\n\n- pro13 matches both \"13-inch\" and \"12.9-inch\", but prefers exact match if both simulators exist\n- pro129 matches only \"12.9-inch\" (precise)\n\n**NOTE:** Devices that don't fit patterns get \"-\" and the user must pass in the full name. Matching every device uniquely is not a goal of the shorthand system which is why `--sim` also accepts full names for simulators\n\n## License\n\n[Mozilla Public License 2.0](https://github.com/adudenamedruby/fxios?tab=MPL-2.0-1-ov-file)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmozilla-mobile%2Ffxios-ctl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmozilla-mobile%2Ffxios-ctl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmozilla-mobile%2Ffxios-ctl/lists"}