CI/CD and self-service · 2025–26

Self-service integration environments for outside teams

Two partner teams needed to build against our GraphQL content API while our team kept shipping on main: the migration vendor for CNET's move to WordPress VIP, and later RetailMeNot. For the vendor, I set up a dedicated branch that auto-deployed on every push to a login-gated Cloud Run integration environment—giving them a live nonprod endpoint that scaled to zero when idle while main kept moving. When RetailMeNot onboarded onto our product catalog, I reused the same pattern while supporting their integration end to end from retailer feeds through search to the GraphQL API.

~4 monthsof vendor integration in parallel with main
3merges back to main as features were ready
~30other merges to main while the vendor integrated

Context

The GraphQL content API serves articles, products and other content to CNET's sites. During the WordPress VIP migration, the vendor's WordPress code had to call that API, and some of what it needed was new: fields and behavior added just for the migration. Pointing the vendor at our shared nonprod environment would have tied their testing to whatever our team merged next, and holding main for them would have stalled everything else.

How it worked

Vendor branch to gated Cloud Run integration environment Top row: a push to the vendor branch runs GitHub Actions and Cloud Build, which deploy a Cloud Run integration environment that scales to zero. Bottom row: the vendor's workflow logs in through nonprod Okta for an API token, then calls the environment through the load balancer. Main keeps shipping in parallel, and the branch merges back when ready. Vendor branch migration changes each push Build and deploy GitHub Actions + Cloud Build Integration environment Cloud Run, scales to zero Vendor's workflow their tests and tooling Nonprod Okta login issues an API token Load balancer no public Cloud Run URL token-checked calls Main kept shipping in parallel; the branch merged back three times
The vendor's code deployed itself to an integration environment, and the vendor reached it only with a nonprod login.

The pattern grew: RetailMeNot

In 2026 RetailMeNot, another brand in the company, started building an app on our product data. I supported it end to end, from the feeds through search to the GraphQL API, using the same approach: its team got a dedicated integration environment of the API behind the same nonprod login while they built.

My part of this work is complete and live in production; RetailMeNot is still building its app on top of it.

My part: I built the early API work for the migration, including the new API pattern the vendor integrated against. I then set up the vendor branch and the workflow that deploys it to its own Cloud Run integration environment, built the product-search API work and the feature requests the vendor needed, and merged the branch back into main as features were ready. For RetailMeNot I built the search and API work above and set up their dedicated environment; teammates owned the project and its requirements, and handled image ingestion. The team's existing environment build and per-pull-request environments were a teammate's, and during the integration period teammates added migration-specific fields and set up the vendor's token access.

What I carry forward

Give an outside team a real endpoint instead of a mock or a turn on a shared environment. A branch that deploys itself costs little to set up, scale to zero keeps it idle between uses, and putting it behind the company login means access is granted and revoked through the same Okta login as everything else.