From copy‑paste chaos to cohesive mobile CI/CD: Rippling’s journey with Bitrise Modular YAML
![[Blog] | Featured image | From Copy‑Paste Chaos to Cohesive Mobile CI/CD | .jpg](http://images.ctfassets.net/k0itp0ir7ty4/5RBVY71hlbtWfqEq3NOrOm/523bb97cea2ab7e1d9d6b89f11bc74db/develop_app_generic_img-scaled.jpg)
In this article
Kushal Agrawal, a Software Engineer on Rippling’s Mobile Platform team, saw growing pains in mobile CI/CD. Duplicated configurations led to wasted effort and inconsistencies. Seeing the need for a unified solution, he led the charge to implement Bitrise Modular YAML, significantly reducing maintenance and boosting confidence in CI signals. Learn how Rippling adopted Bitrise Modular YAML for cohesive mobile CI/CD, under Kushal’s lead.
Introduction
By early 2025 Rippling’s mobile engineering organisation owned two actively‑developed mobile apps — Rippling Mobile and Rippling Time Clock — each with its own repository. Each repository contained 8 – 10 Bitrise pipelines that handled pull‑request checks, nightly builds, production releases, and hot‑fixes.
Bitrise is a fully‑managed continuous integration and delivery platform purpose‑built for mobile apps. It provides pre‑configured build machines, a marketplace of reusable steps, and deep integrations with Xcode and Android tool‑chains—letting us focus on shipping features instead of maintaining build servers. You can read more about our early experience in Mastering Mobile App Quality – Rippling’s CI/CD Journey with Bitrise.
As new features shipped, we continuously copied snippets between projects, until copy‑pasted bitrise.yml
files and duplicated helper scripts became a daily pain‑point. Even a routine Xcode upgrade or caching tweak meant opening duplicate pull‑requests — one for each repo — and any missed change left teams staring at inconsistent build results.
In January 2025 we untangled that mess by adopting Bitrise Modular YAML. Instead of baking the same logic into every codebase, we moved shared workflows and scripts into a single Git repository, imported where needed. This post recounts the journey in four sections:
The concrete problems we faced.
The solution we chose.
A fact‑based walk through of the migration steps.
The results and lessons learned.
The Problem (What Hurt and Why)
Workflow duplication – Each repo defined several nearly‑identical pipelines — for example daily health‑checks, pull‑request checks, and release builds — all running the steps like: installing dependencies , running unit tests , running type checks etc. The YAML and helper scripts for these pipelines were copied into every repository
High maintenance overhead – Upgrading the Bitrise macOS runner from Xcode 15 to Xcode 16 meant a copy‑paste hunt across every
bitrise.yml
, plus separate code‑reviews from iOS and Android owners. Routine upkeep stretched into half‑day chores.Risk of inconsistency – When an update landed in one repo but not the other, behaviour diverged and debugging time increased. A script for test‑selection existed in both repositories. Over time the script in one repo evolved to cover extra edge‑cases — skipping flaky tests and filtering platform‑specific suites — while the other repo retained the older version.
Slow propagation of optimisations – We discovered a better cache key for an install step that shaved three minutes off build time. Because each repo stored its own cache‑setup steps, it took a week (and multiple reminders) before both projects gained the speed‑up.
Script duplication – Shell and Node utilities were copied rather than referenced, preventing robust testing.
Those issues consumed developer hours and eroded confidence in CI signals, so a maintainable approach became essential.
The Solution (Why Bitrise Modular YAML)
We did not adopt a new CI provider — we reorganised Bitrise itself. The objective was a single, version‑controlled source of truth that every mobile repository could import while still allowing platform‑specific logic.
Three pillars defined the architecture:
Centralised commons repository All reusable workflows, scripts, and step‑bundles reside in a dedicated Git repo (
mobile‑ci
). Teams propose a change once; every consumer benefits.Targeted entry‑points for reuse
bitrise/shared/workflows.yml
– platform‑agnostic stepsbitrise/ios/workflows.yml
– iOS‑only needs (IOS builds, Releasing to store).bitrise/android/workflows.yml
– Android specifics (Android builds, Play Store deployment).
Guardrails that keep pipelines safe
Version‑controlled imports – Product repos reference specific branch from common repository, so behaviour changes only on an intentional bump.
Local config validation – Engineers run bitrise validate on the YAML configuration before pushing, catching syntax errors instantly.
Automated cross‑repo tests – A GitHub Action opens temporary PRs in consuming repos; common changes merge only after critical pipelines pass.
With these pillars in place, every subsequent CI tweak became one pull‑request instead of many, eliminating drift and halving maintenance workload.
How We Did It (Step‑by‑Step)
1. Create the central repository
A new GitHub project — mobile‑ci — hosts workflows, scripts, and step‑bundles. Product repositories consume it for running its pipeline and workflows.
2. Design a clear directory structure
1
2
3
4
5
6
7
8
9
10
11
12
13
14
mobile-ci
├── bitrise/
├── android/
│ ├── scripts/
│ ├── step-bundles.yml
│ └── workflows.yml
├── ios/
│ ├── scripts/
│ ├── step-bundles.yml
│ └── workflows.yml
└── shared/
├── scripts/
├── step-bundles.yml
└── workflows.yml
Platform folders (ios/
, android/
) hold setup and build‑tool specifics, while shared contains language‑agnostic helpers and a master step-bundles.yml
.
3. Extract reusable step‑bundles
We consolidated frequently repeated sequences — package‑install, cache‑restore, etc. — into Bitrise Step Bundles. Downstream YAML now references a bundle with a single line, trimming boiler‑plate and reducing copy‑paste risk.
4. Move and test scripts centrally
All bash and Node utilities migrated to shared/scripts. Consolidation enabled proper unit tests, giving every pipeline predictable behaviour.
5. Validate YAML locally with Bitrise CLI
During development we run bitrise validate against the configuration to detect syntax errors or missing variables before a commit ever reaches CI. (for more details you can checkout the Bitrise CLI)
6. Reference modules via Git imports
A minimal snippet inside each product repo replaces thousands of lines:
1
2
3
4
5
6
7
8
9
10
include:
- path: "bitrise/shared/workflows.yml"
branch: "master"
repository: "mobile-ci"
- path: "bitrise/android/workflows.yml"
branch: "master"
repository: "mobile-ci"
- path: "bitrise/ios/workflows.yml"
branch: "master"
repository: "mobile-ci"
Pinning a branch — or a tag when needed — keeps versions explicit and reproducible.
7. Automate cross‑repository validation
Our GitHub workflow listens for PRs in the common repo, opens temporary PRs in both product repos, and triggers their critical pipelines. A common change merges only after both pipelines succeed, preventing silent breakage.
Results (Directly‑Measured Changes)
Metric | Before | After | Reduction |
---|---|---|---|
YAML lines in rippling- timeclock repo | 3,918 | 652 | ‑83 % |
YAML lines in rippling-mobile repo | 8,270 | 2,563 | ‑69 % |
Additional outcomes observed during rollout:
Maintenance effort roughly halved – Editing one repository instead of two cuts manual work by ≈50 %.
Optimisations available immediately – New cache strategies or machine‑image upgrades needed only a single commit.
Standardised notifications – Slack messages follow a uniform format, and no repo lags behind.
Faster onboarding for new pipelines – Adding a workflow now involves an import line plus any project‑specific secrets.
Incident‑free migration – The phased rollout completed with zero build failures attributable to the change.
Qualitative Impact
Engineer focus reclaimed – Less time spent duplicating YAML means more time for feature work.
Confidence in CI – Validated, centralised workflows reduced duplicate and inconsistent workflows.
Clear ownership – A single repository makes it obvious where to propose or discuss CI improvements.
Lessons Learned & Best Practices (What Worked for Us)
Validate early — and locally- Running
bitrise validate
on the YAML configuration catches indentation slips and syntax issues in seconds. That single habit saved dozens of minutes of failed cloud builds and provided immediate feedback during code‑reviews.Separate shared and platform‑specific logic- We resisted the temptation to drop everything into one giant file. Keeping
ios/
andandroid/
folders distinct means iterating on specific platform nuances without risk of breaking the other.Automate downstream testing - Manual checklist validation doesn’t scale. Our GitHub Action that opens shadow PRs in consuming repos is the safety net that guarantees a change in
mobile‑ci
won’t surprise product teams. No green checks, no merge.Test scripts like application code - Moving bash and Node utilities into the commons repo let us add unit tests. Regressions in the test‑selection script are now caught by CI before they reach mobile builds.
Track a tangible metric - We chose the YAML line‑count and hours spent on CI maintenance. Seeing the numbers drop (‑83 % lines, ~50 % time) kept stakeholders aligned and proved the migration worthwhile.
Challenges and Mitigations
Metric | Before | After |
---|---|---|
Merged‑YAML syntax errors | Failed builds due to invisible whitespace or indentation issues. | Required |
Cross‑repo breakage risk | A change in common repo could silently break product pipelines. | GitHub Action creates shadow PRs in each consumer repo and blocks merge until both pass. |
Script divergence history | Edge‑case fixes lived in only one repo, causing inconsistent results. | Centralised |
Conclusion
Adopting Bitrise Modular YAML transformed our CI/CD estate from duplicated, fragile files into a single, version‑controlled source of truth. We cut thousands of lines of YAML, reduced maintenance effort by half, and ensured that every optimization lands everywhere at the same time. For teams already on Bitrise with similar duplication, a compact common repository — backed by step‑bundles, YAML validation, and automated cross‑repo tests — delivers immediate, measurable returns without disrupting daily development.
Disclaimer
Rippling and its affiliates do not provide tax, accounting, or legal advice. This material has been prepared for informational purposes only, and is not intended to provide, and should not be relied on for tax, legal, or accounting advice. You should consult your own tax, legal, and accounting advisors before engaging in any related activities or transactions.
The Rippling Corporate Card is issued by Fifth Third Bank, N.A. Member FDIC, and Celtic Bank, Member FDIC, pursuant to a license from Visa® U.S.A. Inc. Visa is a trademark owned by Visa International Service Association and used under license. All trademarks are the property of their respective owners.
Hubs
Author

Kushal Agrawal
Software Engineer II
Kushal Agrawal is part of Rippling’s Mobile Platform team, working with the Mobile Infra pod. He specializes in building and improving CI/CD pipelines, managing workflows, optimizing app performance, and enhancing observability—focused on delivering stable, reliable, and high-quality mobile experiences.
Explore more
See Rippling in action
Increase savings, automate busy work, and make better decisions by managing HR, IT, and Finance in one place.