|
| 1 | +# GitHub Workflows Documentation |
| 2 | + |
| 3 | +Comprehensive guide to ev-node CI/CD workflows, orchestration, and tag-based release process. |
| 4 | + |
| 5 | +## Table of Contents |
| 6 | + |
| 7 | +- [Workflow Architecture](#workflow-architecture) |
| 8 | +- [CI Workflow](#ci-workflow) |
| 9 | +- [Release Workflow](#release-workflow) |
| 10 | +- [Tag-Based Release Process](#tag-based-release-process) |
| 11 | +- [Troubleshooting](#troubleshooting) |
| 12 | + |
| 13 | +## Workflow Architecture |
| 14 | + |
| 15 | +``` |
| 16 | +┌──────────────────────────────────────────────────────────────┐ |
| 17 | +│ Trigger Events │ |
| 18 | +│ • push to main • pull_request • merge_group • tags │ |
| 19 | +└───────────────────────────┬──────────────────────────────────┘ |
| 20 | + │ |
| 21 | + ┌───────────────────┴────────────────────┐ |
| 22 | + │ │ |
| 23 | + v v |
| 24 | +┌───────────────────┐ ┌────────────────────┐ |
| 25 | +│ CI Workflow │ │ Release Workflow │ |
| 26 | +│ (ci.yml) │ │ (release.yml) │ |
| 27 | +│ │ │ │ |
| 28 | +│ 1. Image Tag │ │ Trigger: Tag │ |
| 29 | +│ Generation │ │ **/v*.*.* │ |
| 30 | +│ • PR: pr-# │ │ │ |
| 31 | +│ • Branch: ref │ │ 1. Parse Tag │ |
| 32 | +│ │ │ • Validate │ |
| 33 | +│ 2. Parallel: │ │ • Extract │ |
| 34 | +│ • Lint │ │ │ |
| 35 | +│ • Docker │ │ 2. Build & Push │ |
| 36 | +│ • Tests │ │ • Multi-arch │ |
| 37 | +│ • Proto │ │ • Version tag │ |
| 38 | +│ │ │ • Latest tag │ |
| 39 | +│ 3. Sequential: │ │ │ |
| 40 | +│ • Docker E2E │ │ │ |
| 41 | +└───────────────────┘ └────────────────────┘ |
| 42 | +``` |
| 43 | + |
| 44 | +## CI Workflow |
| 45 | + |
| 46 | +**Entry Point:** `ci.yml` - Orchestrates all CI processes |
| 47 | + |
| 48 | +**Triggers:** `push` to main | `pull_request` | `merge_group` |
| 49 | + |
| 50 | +### Image Tag Generation |
| 51 | + |
| 52 | +First job generates consistent Docker tags for all downstream jobs: |
| 53 | +- **PRs:** `pr-{number}` (e.g., `pr-123`) |
| 54 | +- **Branches:** Sanitized ref name (e.g., `main`) |
| 55 | + |
| 56 | +### Parallel Jobs |
| 57 | + |
| 58 | +**Lint** (`lint.yml`) - Code quality checks: |
| 59 | +- golangci-lint, hadolint, yamllint, markdown-lint, goreleaser-check |
| 60 | + |
| 61 | +**Docker** (`docker.yml`) - Image builds: |
| 62 | +- Multi-platform (linux/amd64, linux/arm64) |
| 63 | +- Pushes to GHCR with generated tag |
| 64 | +- Skips for merge groups (uses PR cache) |
| 65 | + |
| 66 | +**Tests** (`test.yml`) - Comprehensive testing: |
| 67 | +- Build all binaries, Go mod tidy check |
| 68 | +- Unit tests, Integration tests, E2E tests, EVM tests |
| 69 | +- Combined coverage upload to Codecov |
| 70 | + |
| 71 | +**Proto** (`proto.yml`) - Protobuf validation using Buf |
| 72 | + |
| 73 | +### Sequential Jobs |
| 74 | + |
| 75 | +**Docker E2E Tests** (`docker-tests.yml`): |
| 76 | +- Waits for Docker build completion |
| 77 | +- Runs E2E and upgrade tests using built images |
| 78 | +- Can be manually triggered via `workflow_dispatch` |
| 79 | + |
| 80 | +### Dependencies |
| 81 | + |
| 82 | +``` |
| 83 | +determine-image-tag |
| 84 | + ├─→ lint |
| 85 | + ├─→ docker ──→ docker-tests |
| 86 | + ├─→ test |
| 87 | + └─→ proto |
| 88 | +``` |
| 89 | + |
| 90 | +## Release Workflow |
| 91 | + |
| 92 | +**Entry Point:** `release.yml` - Automated Docker image releases |
| 93 | + |
| 94 | +**Triggers:** Tag push matching `**/v*.*.*` (e.g., `evm/single/v0.2.0`) |
| 95 | + |
| 96 | +### Parse Release Tag |
| 97 | + |
| 98 | +Extracts and validates: |
| 99 | +```yaml |
| 100 | +Input: evm/single/v0.2.0 |
| 101 | +Output: |
| 102 | + app-path: evm/single |
| 103 | + version: v0.2.0 |
| 104 | + image-name: ev-node-evm-single |
| 105 | + dockerfile: apps/evm/single/Dockerfile |
| 106 | +``` |
| 107 | +
|
| 108 | +**Validation:** |
| 109 | +- ✅ App directory exists: `./apps/{app-path}` |
| 110 | +- ✅ Dockerfile exists: `apps/{app-path}/Dockerfile` |
| 111 | +- ✅ Tag matches: `**/v*.*.*` |
| 112 | +- ✅ Semantic versioning format |
| 113 | + |
| 114 | +### Build and Push |
| 115 | + |
| 116 | +- Multi-platform build (amd64, arm64) |
| 117 | +- Publishes to GHCR: |
| 118 | + - `ghcr.io/{owner}/ev-node-{app}:v0.2.0` (version tag) |
| 119 | + - `ghcr.io/{owner}/ev-node-{app}:latest` (latest tag) |
| 120 | + |
| 121 | +## Tag-Based Release Process |
| 122 | + |
| 123 | +### Tag Format |
| 124 | + |
| 125 | +**Pattern:** `{app-path}/v{major}.{minor}.{patch}` |
| 126 | + |
| 127 | +Maps directly to `./apps/` directory structure: |
| 128 | + |
| 129 | +| Tag | App Path | Version | Image Name | |
| 130 | +|-----|----------|---------|------------| |
| 131 | +| `evm/single/v0.2.0` | `evm/single` | `v0.2.0` | `ev-node-evm-single` | |
| 132 | +| `testapp/v1.0.0` | `testapp` | `v1.0.0` | `ev-node-testapp` | |
| 133 | +| `grpc/single/v2.1.3` | `grpc/single` | `v2.1.3` | `ev-node-grpc-single` | |
| 134 | + |
| 135 | +### Release Steps |
| 136 | + |
| 137 | +#### 1. Pre-Release Checklist |
| 138 | +- [ ] Changes committed and pushed to `main` |
| 139 | +- [ ] CI passes |
| 140 | +- [ ] CHANGELOG.md updated |
| 141 | +- [ ] Dockerfile exists in app directory |
| 142 | + |
| 143 | +#### 2. Create Tag |
| 144 | + |
| 145 | +```bash |
| 146 | +# Annotated tag with release notes |
| 147 | +git tag -a evm/single/v0.2.0 -m "Release EVM single v0.2.0 |
| 148 | +
|
| 149 | +Features: |
| 150 | +- Added feature X |
| 151 | +- Improved performance Y |
| 152 | +
|
| 153 | +Bug fixes: |
| 154 | +- Fixed issue Z |
| 155 | +" |
| 156 | +
|
| 157 | +git push origin evm/single/v0.2.0 |
| 158 | +``` |
| 159 | + |
| 160 | +#### 3. Automated Process |
| 161 | + |
| 162 | +Workflow automatically: |
| 163 | +1. Validates tag and app structure |
| 164 | +2. Builds multi-platform images |
| 165 | +3. Publishes to GHCR with version + latest tags |
| 166 | + |
| 167 | +#### 4. Verify |
| 168 | + |
| 169 | +```bash |
| 170 | +docker pull ghcr.io/evstack/ev-node-evm-single:v0.2.0 |
| 171 | +docker run ghcr.io/evstack/ev-node-evm-single:v0.2.0 --version |
| 172 | +``` |
| 173 | + |
| 174 | +### Multiple Releases |
| 175 | + |
| 176 | +```bash |
| 177 | +# Individual tags |
| 178 | +git tag evm/single/v0.2.0 && git push origin evm/single/v0.2.0 |
| 179 | +git tag testapp/v1.0.0 && git push origin testapp/v1.0.0 |
| 180 | +
|
| 181 | +# Multiple at once |
| 182 | +git push origin evm/single/v0.2.0 testapp/v1.0.0 |
| 183 | +``` |
| 184 | + |
| 185 | +### Semantic Versioning |
| 186 | + |
| 187 | +- **MAJOR (v2.0.0):** Breaking changes |
| 188 | +- **MINOR (v1.1.0):** New features, backward compatible |
| 189 | +- **PATCH (v1.0.1):** Bug fixes, backward compatible |
| 190 | + |
| 191 | +### Rollback |
| 192 | + |
| 193 | +```bash |
| 194 | +# Delete tag |
| 195 | +git tag -d evm/single/v0.2.0 |
| 196 | +git push origin :refs/tags/evm/single/v0.2.0 |
| 197 | +
|
| 198 | +# Fix and recreate |
| 199 | +git tag -a evm/single/v0.2.0 -m "Release message" |
| 200 | +git push origin evm/single/v0.2.0 |
| 201 | +``` |
| 202 | + |
| 203 | +### Best Practices |
| 204 | + |
| 205 | +1. Use annotated tags with descriptive messages |
| 206 | +2. Update CHANGELOG.md before tagging |
| 207 | +3. Ensure CI passes on main |
| 208 | +4. Test locally before release |
| 209 | +5. Document breaking changes |
| 210 | +6. Version tags are immutable references |
| 211 | +7. Latest tag points to most recent release |
| 212 | + |
| 213 | +### Adding New Apps |
| 214 | + |
| 215 | +1. Create directory: `apps/new-app/Dockerfile` |
| 216 | +2. Add to CI yaml (if needed): |
| 217 | + ```yaml |
| 218 | + apps: [{"name": "ev-node-new-app", "dockerfile": "apps/new-app/Dockerfile"}] |
| 219 | + ``` |
| 220 | +3. Create tag: `git tag new-app/v1.0.0 && git push origin new-app/v1.0.0` |
| 221 | + |
| 222 | +## Environment & Secrets |
| 223 | + |
| 224 | +### Variables |
| 225 | + |
| 226 | +| Variable | Description | Example | |
| 227 | +|----------|-------------|---------| |
| 228 | +| `EV_NODE_IMAGE_REPO` | GHCR repository | `ghcr.io/evstack` | |
| 229 | +| `EV_NODE_IMAGE_TAG` | Image tag | `pr-123`, `main` | |
| 230 | + |
| 231 | +### Secrets |
| 232 | + |
| 233 | +| Secret | Description | Used By | |
| 234 | +|--------|-------------|---------| |
| 235 | +| `GITHUB_TOKEN` | GHCR authentication | Docker workflows | |
| 236 | +| `CODECOV_TOKEN` | Coverage upload | Test workflow | |
| 237 | + |
| 238 | +## Troubleshooting |
| 239 | + |
| 240 | +### Release Errors |
| 241 | + |
| 242 | +**"App directory does not exist"** |
| 243 | +- Tag must match app path: `apps/evm/single/` → `evm/single/v0.2.0` |
| 244 | + |
| 245 | +**"Dockerfile not found"** |
| 246 | +- Verify `apps/{app-path}/Dockerfile` exists |
| 247 | + |
| 248 | +**"Invalid tag format"** |
| 249 | +- Use `evm/single/v0.2.0` not `evm/single/0.2.0` |
| 250 | + |
| 251 | +### CI Errors |
| 252 | + |
| 253 | +**Docker E2E "image not found"** |
| 254 | +- Wait for Docker build job completion |
| 255 | + |
| 256 | +**Coverage upload fails** |
| 257 | +- Verify `CODECOV_TOKEN` in repository settings |
| 258 | + |
| 259 | +**Lint failures** |
| 260 | +- Run locally: `make lint` |
| 261 | + |
| 262 | +### Manual Triggers |
| 263 | + |
| 264 | +**Docker E2E tests:** |
| 265 | +``` |
| 266 | +GitHub → Actions → "Docker Tests" → Run workflow |
| 267 | +Enter tag: pr-123, main, v0.2.0 |
| 268 | +``` |
| 269 | +
|
| 270 | +**Check images:** |
| 271 | +```bash |
| 272 | +gh api /orgs/evstack/packages/container/ev-node-evm-single/versions |
| 273 | +docker pull ghcr.io/evstack/ev-node-evm-single:v0.2.0 |
| 274 | +``` |
| 275 | + |
| 276 | +## Additional Resources |
| 277 | + |
| 278 | +- **Complete Release Guide:** [RELEASE.md](../RELEASE.md) |
| 279 | +- **Quick Start:** [RELEASE_QUICK_START.md](../RELEASE_QUICK_START.md) |
| 280 | +- **GitHub Actions:** https://docs.github.com/en/actions |
| 281 | +- **Semantic Versioning:** https://semver.org/ |
| 282 | +- **GHCR Docs:** https://docs.github.com/en/packages |
0 commit comments