Multi-Repo to Monorepo: How I Automated 6 Go Microservice Releases and Then Made It 15x Faster

Multi-Repo to Monorepo: How I Automated 6 Go Microservice Releases and Then Made It 15x Faster

2026年8月7日1 次浏览来源:Dev.to阅读原文

Last month I spent more than an hour cutting a release across six Go microservice repos.

Tag log, wait for CI.

Update sdk's to point at the new log SHA, push, wait for CI.

Repeat for utils.

Then do api, cli, and worker in parallel - except I forgot to bump cli's dependency and the build broke at 11pm.

That was the last manual release I did.

This is the story of automating that entire workflow with Jenkins + Python + GitLab, then realizing the multi-repo architecture was the real problem, and collapsing everything into a Go monorepo that's 15x faster at cutting releases.

The full setup runs on my laptop.

You can fork it and try it yourself.

Table of Contents The Six Modules The Stack Phase 1: Multi-Repo Automation Phase 2: The Monorepo Pivot The Unified CI Pipeline Real Numbers Caveats and Gotchas Try It Yourself The Six Modules The project simulates a real production system with six Go modules that have strict dependency ordering: Module Role Tag Scheme Depends On Logger (leaf, no deps) - API client log Shared utilities log, sdk Backend log, utils CLI log, sdk Background log, utils The first three modules are sequential - sdk can't tag until log is tagged, utils can't tag until sdk is tagged.

The last three are terminal - they can process in parallel once the sequential chain is done.

Every module lives on three long-lived branches: → → .

A release means moving code through all three, in all six repos, in the right order.

That's the problem.

Do it manually and you're juggling 6 repos × 3 branches × dependency ordering.

One forgotten and you're debugging at midnight.

The Stack Everything runs on a MacBook.

No cloud CI, no SaaS - just local tools wired together.

The key pieces: Jenkins LTS via , running as a launched service ngrok exposing → so GitLab integration/webhook can reach Jenkins GitLab.com hosting the repos Python ( + ) for the automation engine Go 1.24 with workspace support () Jenkins ↔ GitLab Integration Configured using GitLab’s native Jenkins Integration combined with ngrok for local tunneling: GitLab → Jenkins: Native integration automatically triggers local Jenkins pipelines on push and MR events.

Jenkins → GitLab: Reports build progress and status back via API, displaying green/red status checks directly on commits and merge requests.

Phase 1: Multi-Repo Automation The Setup: 6 Repos, 7 Jenkins Jobs In the multi-repo world, each module is its own GitLab repo under the group: Each repo gets its own Jenkins CI job (6 jobs), plus one orchestration job that runs the automation Python script.

That's 7 Jenkins jobs to maintain.

The Automation Engine: 1,800 Lines of Python The repo contains the brain: a Python script () that talks to the GitLab API and performs git operations.

One Jenkins job, five actions: Action What it does Merges develop → release for all 6 repos, in dependency order Merges release → develop (or master → release) Merges release → master, tags each module, bumps go.mod versions Bumps version constants in api and cli on develop Calculates next semver tags based on existing tags How a Release Cut Actually Works When you trigger , the script: Sequential phase - processes log, sdk, utils one at a time: Creates an intermediate branch from Merges into it (handling go.mod conflicts automatically) Creates a GitLab MR Waits for approval (or auto-merges if configured) Records the merged SHA - the next repo needs it for Parallel phase - processes api, cli, worker simultaneously: Same merge flow, but all three run concurrently since they're terminal nodes The hardest part: cross-repo dependency tracking.

When log merges to release, sdk needs to run to pin to the exact commit.

The script tracks these SHAs in and passes them forward through the chain.

Conflict Handling When code conflicts happen (not just go.mod), the pipeline doesn't crash.

It: Creates a conflict branch cut from the source (so GitLab renders the real diff) Opens an MR with in the title Polls every 30 seconds for manual resolution + approval Aut

分享
Baike.dev

baike.dev helps you discover great languages, frameworks, databases, DevOps and cloud-native tools.

Quick links

About

Contribute

Found a great developer tool? Share it with the community.

Submit a tool
© 2026 baike.dev Developer EncyclopediaUpdated daily · Discover great developer tools