CI/CD Automation
An automation tool that orchestrates build, test, and deployment steps for Go services.
Role
Designer & developer
Stack
Go, Docker, Shell, Linux
Language
Go
Repository
Link pending
Problem
Running the same build-and-deploy steps by hand is error-prone and slow. The goal was a lightweight, self-hostable way to define pipeline stages once and run them consistently across projects.
Solution
A CI/CD automation system written in Go that sequences pipeline stages — build, test, package, deploy — for containerized services, with explicit stage definitions and failure handling.
My contribution
Designed the pipeline model (stages → steps), implemented step execution with timeouts and failure propagation, and wired the system to Docker-based build environments.
Architecture
A pipeline is a declarative definition of stages and steps. An executor runs steps in order inside controlled environments, captures output, and stops the pipeline on the first failure, reporting which stage broke and why.
pipeline.yaml
│
▼
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ build │──▶│ test │──▶│ package │──▶│ deploy │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
│ │
▼ ▼
Docker env fail-fast + captured outputOverview
This project is a small, self-hosted CI/CD automation tool. Instead of depending on hosted runners, it executes pipeline definitions locally or on a dedicated Linux machine, using Docker for isolated build environments.
Requirements
The automation had to:
- Describe pipelines as data: ordered stages, each with ordered steps.
- Execute steps with timeouts and capture their output.
- Fail fast: one failed step stops the pipeline and reports its stage.
- Run builds in isolated, reproducible environments.
- Be runnable from a single command with zero external services.
Implementation
The executor walks the stage graph sequentially, invoking each step as an isolated process. Output streams are captured live so failures show exactly what broke. Docker is used so build toolchains never depend on the host machine's state.
Technical Decisions
The key decision was constraint over capability: no conditional graphs, no dynamic fan-out — just linear stages with clear failure semantics. This made the tool trustworthy quickly, and the simple model has been enough for real delivery workflows.
Challenges
Process control details mattered: propagating cancellation to child processes, enforcing step timeouts, and keeping environment variables from leaking between steps.
Results
Builds and deployments that used to be a sequence of remembered commands became a versioned pipeline definition anyone (including future me) can run identically.
The hard part
Reliably capturing and surfacing step output while keeping execution isolated — a pipeline must fail loudly with the exact broken step, never silently continue.
A decision worth noting
Kept the pipeline definition declarative and deliberately simple instead of building a general-purpose workflow engine. Limited scope kept the executor reliable and easy to reason about.
Outcome
Repeatable, scripted delivery for my Go services — the same commands run the same way on every execution.
Next project
Veterinary Clinic System