|
1 | | -# Zerv Flow Demo |
| 1 | +[](https://github.com/wislertt/zerv-flow/actions/workflows/cd.yml) |
| 2 | +[](https://github.com/wislertt/zerv-flow/actions/workflows/cd.yml) |
| 3 | +[](https://sonarcloud.io/summary/new_code?id=wislertt_zerv-flow) |
| 4 | +[](https://sonarcloud.io/summary/new_code?id=wislertt_zerv-flow) |
| 5 | +[](https://sonarcloud.io/summary/new_code?id=wislertt_zerv-flow)[](https://codecov.io/gh/wislertt/zerv-flow) |
| 6 | + |
| 7 | +# zerv flow |
| 8 | + |
| 9 | +This repository demonstrates a complete CI/CD solution for multi-environment deployments, integrating the [**zerv**](https://github.com/wislertt/zerv) versioning tool with GitHub Actions for automated versioning and release workflows. |
| 10 | + |
| 11 | +## Overview |
| 12 | + |
| 13 | +**What is zerv?** |
| 14 | + |
| 15 | +- A Rust-based versioning tool that generates semantic versions from git current state (latest tag and current commit) |
| 16 | +- Generates versions in multiple formats: semver, pep440, and docker_tag |
| 17 | +- Supports flexible branching strategies and version generation rules |
| 18 | +- More details can be found at [https://github.com/wislertt/zerv](https://github.com/wislertt/zerv) |
| 19 | + |
| 20 | +**Why use this setup?** |
| 21 | + |
| 22 | +- Automated versioning for multi-environment CI/CD pipelines |
| 23 | +- Flexible deployment controls to match your team's speed vs quality needs |
| 24 | +- Dynamic GitOps approach: main branch represents all environments by default, PR labels can temporarily shift environment representation to specific branches |
| 25 | +- Compatible with popular branching strategies (Trunk-based, GitFlow, Release Trains) |
| 26 | + |
| 27 | +**Quick start** |
| 28 | + |
| 29 | +1. Fork this repository |
| 30 | +2. Install zerv locally for testing |
| 31 | +3. Create a PR to test the workflow |
| 32 | +4. Add `deploy-d`, `deploy-n`, or `deploy` labels to trigger deployments |
| 33 | + |
| 34 | +## Prerequisites |
| 35 | + |
| 36 | +- Main branch tagged with semantic version format (major.minor.patch) - recommend using [semantic-release](https://github.com/semantic-release/semantic-release) |
| 37 | +- For multiple long-live branches (e.g., git flow with develop branch): Enable "Require branches to be up to date before merging" protection rule for main branch |
| 38 | +- Deployment pipeline must follow function pattern and be idempotent. There are 2 common deployment patterns: |
| 39 | + - `deploy_without_env(repo, versions)`: For immutable releases (e.g., Python packages) |
| 40 | + - Each new version does not override previous versions |
| 41 | + - Example: Publishing to PyPI with incrementing version numbers |
| 42 | + - `deploy_with_env(repo, env_name, versions)`: For environment-specific deployments (e.g., Cloud Run services) |
| 43 | + - New version overrides existing version in specified environment |
| 44 | + |
| 45 | +## Deployment Assumptions for This Repo (Configurable) |
| 46 | + |
| 47 | +- **Environment codes**: d (development), n (nonproduction), p (production) following [GCP landing zone convention](https://docs.cloud.google.com/architecture/blueprints/security-foundations/summary#naming-conventions) |
| 48 | + - Note: These can be configured to any naming convention (e.g., dev/staging/prod) |
| 49 | +- **Version formats**: This repository demonstrates 3 formats: - Semver: For git repository tags and releases - PEP440: For Python package versions - Docker Tag: For container registry tags |
| 50 | + - Note: This demo repository only echoes these formats as examples, but in a real deployment pipeline they would be used for their respective purposes. |
| 51 | + - Note: Configure zerv to generate formats based on your deployment requirements and constraints. See [zerv documentation](https://github.com/wislertt/zerv) for all supported formats. |
| 52 | + |
| 53 | +## Branching Strategy Design |
| 54 | + |
| 55 | +- **Core concept**: GitOps approach where branches represent environment states |
| 56 | +- **Main branch**: Represents all environments by default, uses semantic version control |
| 57 | +- **All non-main branches**: Versioned by zerv when creating PRs |
| 58 | +- **Environment representation via PR labels**: Temporarily shifts environment representation from main branch to the PR branch |
| 59 | + - PR with `deploy-d` label = branch represents development environment |
| 60 | + - PR with `deploy-n` label = branch represents nonproduction environment |
| 61 | +- **Environment-less deployment trigger**: |
| 62 | + - PR with `deploy` label = deploy without environment using version from the branch (e.g., for immutable releases) |
| 63 | +- **Locking mechanism**: Prevents concurrent deployments to same environment |
| 64 | + - First PR with deploy-X label acquires lock for environment X |
| 65 | + - Subsequent PRs with same label fail until lock is released |
| 66 | + - Lock releases when PR merges/closes or label is removed |
| 67 | +- **Deployment flow**: |
| 68 | + - PR with label deploys to specific environment immediately |
| 69 | + - When PR merges to main, CD pipeline deploys to ALL environments |
| 70 | + |
| 71 | +## Speed vs Quality Tradeoff |
| 72 | + |
| 73 | +- Flexible deployment controls to match your team's needs |
| 74 | +- Example for higher quality nonproduction: Only allow `deploy-n` on `release/*` branches, with required PR reviews before merging to release branch |
| 75 | +- Example for fast POC development: Allow `deploy-p` directly in PRs for rapid iteration (accepting potential failures in production environment) |
| 76 | +- Adapt the strategy to your context - balance speed vs quality based on your project requirements |
| 77 | + |
| 78 | +## Deployment Flow Examples |
| 79 | + |
| 80 | +The following scenarios demonstrate how the deployment flow works in practice: |
| 81 | + |
| 82 | +- **Initial State**: Only the main branch exists. All environments (development, nonproduction, production) and environment-less deployments reference version `v1.1.2` from the main branch. |
| 83 | +  |
| 84 | + |
| 85 | +- **Feature Branch Deployment**: A `feature/1` branch is created with PR labels `deploy-n` and `deploy`. The nonproduction environment deploys version `v1.1.3-alpha.1.post.2` from the feature branch and becomes locked to it. Development and production remain on main branch `v1.1.2`. The environment-less deployment creates a new version `v1.1.3-alpha.1.post.2` without overriding previous versions. |
| 86 | +  |
| 87 | + |
| 88 | +- **Concurrent Feature Deployment**: While `feature/1` PR is active, a `feature/2` branch is created with PR labels `deploy-d`, `deploy-n`, and `deploy`. Nonproduction deployment fails due to being locked by `feature/1`. Development deploys successfully with version `v1.1.3-alpha.2.post3` from `feature/2`. Environment-less deployment creates another new version `v1.1.3-alpha.2.post.3` alongside the existing version. |
| 89 | +  |
| 90 | + |
| 91 | +## Branch Rules and Version Generation (Configurable) |
| 92 | + |
| 93 | +This repository uses the default branch rules from `zerv flow` command. For complete implementation details, see the shared workflow at [zerv/.github/workflows/shared-zerv-versioning.yml](https://github.com/wislertt/zerv/blob/main/.github/workflows/shared-zerv-versioning.yml). |
| 94 | + |
| 95 | +- **Feature branches** (default): Generate alpha pre-releases with branch-based identification |
| 96 | + - Numbered feature branches (`feature/1/xyz`): Extracts number from branch name |
| 97 | + - Example: `1.0.1-alpha.1.post.1+feature.1.xyz.1.g4e9af24` |
| 98 | + - Non-numbered feature branches (`feature/xyz`): Uses 5-digit hash for identification |
| 99 | + - Example: `1.0.1-alpha.48993.post.1+feature.xyz.3.g4e9af24` |
| 100 | + - Uses commit distance for post count |
| 101 | + |
| 102 | +- **"develop" branch**: Generates beta pre-releases with stable numbering |
| 103 | + - Example: `1.0.1-beta.1.post.1+develop.3.g4e9af24` |
| 104 | + - Uses commit distance for post count |
| 105 | + |
| 106 | +- **"release/\*" branches**: Generates release candidates with extracted or hash-based numbering |
| 107 | + - Regular release branches: `1.0.1-rc.1.post.1.dev.1764382150+release.1.do.something.3.g4e9af24` (full version) |
| 108 | + - With `pre-release` label: `1.0.1-rc.1.post.1` (short version, creates tag) |
| 109 | + - Numbered release branches (`release/1/xyz`): `1.0.1-rc.1.post.1` |
| 110 | + - Non-numbered release branches (`release/xyz`): `1.0.1-rc.48993.post.1` (5-digit hash RC number) |
| 111 | + - Uses tag distance for post count |
| 112 | + |
| 113 | +- **Customization**: All branch rules can be configured with `--branch-rules` argument |
| 114 | + |
| 115 | +## Zerv Flow with Common Branching Strategies |
| 116 | + |
| 117 | +Zerv Flow is designed as a generalized branching framework that builds on top of version generation rules. Rather than being a rigid branching strategy itself, it provides a flexible foundation that's compatible with existing popular branching strategies. |
| 118 | + |
| 119 | +- **Trunk-based / GitHub Flow**: |
| 120 | + - Structure: Main branch + short-lived feature branches |
| 121 | + - Compatible out-of-the-box with default branch rules |
| 122 | + |
| 123 | +- **GitFlow** (Adaptive - not 100% traditional GitFlow): |
| 124 | + - Structure: Main + develop long-lived branches + feature/release/hotfix branches |
| 125 | + - Simplified release branches: `release/1/feature-name` or `release/feature-name` (no manual version bumping needed) |
| 126 | + - Requirements: Enable "Require branches to be up to date before merging" for main branch protection rule |
| 127 | + - Configuration: Update branch rules if develop branch has different name |
| 128 | + - Note: This adapts traditional GitFlow (designed 2010, pre-CI/CD) for modern workflows. Even the author now suggests adapting it to your context: [nvie.com](https://nvie.com/posts/a-successful-git-branching-model/) |
| 129 | + |
| 130 | +- **Release Trains**: |
| 131 | + - Structure: Main + develop as accumulation branch, feature branches from develop, periodic releases |
| 132 | + - Process: Create release branches from develop on schedule, merge to main for releases |
| 133 | + - Requirements: Enable "Require branches to be up to date before merging" for main branch protection rule |
| 134 | + |
| 135 | +- **GitLab Flow (Environment Branches)**: |
| 136 | + - Note: Not designed to support this strategy by default |
| 137 | + - Could work with custom configuration but considered out of scope for this framework |
| 138 | + |
| 139 | +## Contributing |
| 140 | + |
| 141 | +Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change. |
| 142 | + |
| 143 | +## License |
| 144 | + |
| 145 | +This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details. |
0 commit comments