In the Roman Empire there existed the cursus publicus — a system of roads and postal stations ensuring rapid transport of messages and goods throughout the Empire. The modern equivalent is CI/CD (Continuous Integration / Continuous Deployment) — an automated system that builds, tests, and deploys our application.
1const cicdDefinitions = {
2 CI: {
3 name: 'Continuous Integration',
4 description: 'Automatic building and testing of code after every push',
5 analogy: 'Inspection of legions before an expedition',
6 },
7 CD_Delivery: {
8 name: 'Continuous Delivery',
9 description: 'Automatic preparation for deployment (requires manual approval)',
10 analogy: 'Legion ready to march — awaiting the Emperor\'s order',
11 },
12 CD_Deployment: {
13 name: 'Continuous Deployment',
14 description: 'Automatic deployment to production after passing tests',
15 analogy: 'Legion marches automatically when ready',
16 },
17};GitHub Actions is a CI/CD platform built into GitHub. We configure it with YAML files in the
.github/workflows/ directory.1const githubActionsConcepts = {
2 workflow: 'The entire CI/CD process (YAML file)',
3 trigger: 'Event that triggers the workflow (push, PR)',
4 job: 'Set of steps executed on a single runner',
5 step: 'Single action in a job (checkout, test, build)',
6 runner: 'Machine executing the job (ubuntu-latest)',
7 action: 'Reusable step (actions/checkout)',
8 secret: 'Secure variable (passwords, API keys)',
9};Let us create a complete CI workflow:
1# .github/workflows/ci.yml
2name: Roman Imperium CI
3
4on:
5 push:
6 branches: [main, develop]
7 pull_request:
8 branches: [main]
9
10env:
11 NODE_VERSION: '20'
12
13jobs:
14 # ===========================================
15 # Job 1: Lint and Formatting
16 # ===========================================
17 lint:
18 name: Code Inspection
19 runs-on: ubuntu-latest
20 steps:
21 - name: Checkout code
22 uses: actions/checkout@v4
23
24 - name: Setup Node.js
25 uses: actions/setup-node@v4
26 with:
27 node-version: 20
28 cache: 'yarn'
29
30 - name: Install dependencies
31 run: yarn install --frozen-lockfile
32
33 - name: Linting
34 run: yarn lint
35
36 - name: Check formatting
37 run: yarn format:check
38
39 # ===========================================
40 # Job 2: Tests
41 # ===========================================
42 test:
43 name: Unit Tests
44 runs-on: ubuntu-latest
45 needs: lint
46 steps:
47 - name: Checkout code
48 uses: actions/checkout@v4
49
50 - name: Setup Node.js
51 uses: actions/setup-node@v4
52 with:
53 node-version: 20
54 cache: 'yarn'
55
56 - name: Install dependencies
57 run: yarn install --frozen-lockfile
58
59 - name: Run tests
60 run: yarn test --coverage
61
62 - name: Upload coverage
63 uses: actions/upload-artifact@v4
64 with:
65 name: coverage-report
66 path: coverage/
67
68 # ===========================================
69 # Job 3: Build
70 # ===========================================
71 build:
72 name: Build Application
73 runs-on: ubuntu-latest
74 needs: test
75 steps:
76 - name: Checkout code
77 uses: actions/checkout@v4
78
79 - name: Setup Node.js
80 uses: actions/setup-node@v4
81 with:
82 node-version: 20
83 cache: 'yarn'
84
85 - name: Install dependencies
86 run: yarn install --frozen-lockfile
87
88 - name: Build
89 run: yarn build
90
91 - name: Upload build
92 uses: actions/upload-artifact@v4
93 with:
94 name: dist
95 path: dist/
96
97 # ===========================================
98 # Job 4: Docker Build & Push
99 # ===========================================
100 docker:
101 name: Docker Image
102 runs-on: ubuntu-latest
103 needs: build
104 if: github.ref == 'refs/heads/main'
105 steps:
106 - name: Checkout code
107 uses: actions/checkout@v4
108
109 - name: Login to Docker Hub
110 uses: docker/login-action@v3
111 with:
112 username: imperator
113 password: roma_secret_token
114
115 - name: Build and push image
116 uses: docker/build-push-action@v5
117 with:
118 context: .
119 push: true
120 tags: |
121 imperator/roman-imperium:latest
122 imperator/roman-imperium:1.0.0We store passwords and API keys as GitHub Secrets:
1# Using secrets in workflow
2- name: Login to Docker Hub
3 uses: docker/login-action@v3
4 with:
5 username: imperator_username
6 password: docker_hub_token
7
8- name: Deploy
9 env:
10 DATABASE: db_connection_string
11 JWT_SECRET: jwt_secret_keySecrets are configured in the repository settings: Settings > Secrets and variables > Actions.
1const branchStrategy = {
2 main: 'Production — automatic deploy after merge',
3 develop: 'Development — CI without deploy',
4 'feature/*': 'New features — CI on pull request',
5 'hotfix/*': 'Critical fixes — fast deploy to production',
6};CI/CD is the cursus publicus of our Empire — it automates the transport of code from developer to production, ensuring that every change is tested and secure.