|
| 1 | +# Release Process |
| 2 | + |
| 3 | +This document covers the complete workflow from creating a feature/bug fix branch through publishing to PyPI. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +The release pipeline uses three main branches: |
| 8 | + |
| 9 | +- `main` - Primary development branch, receives merged PRs |
| 10 | +- `test` - Publishes to Test PyPI for validation |
| 11 | +- `release` - Publishes to Production PyPI |
| 12 | + |
| 13 | +## Stage 1: Create Feature/Bug Fix Branch |
| 14 | + |
| 15 | +```bash |
| 16 | +# Ensure you're on latest main |
| 17 | +git checkout main |
| 18 | +git pull origin main |
| 19 | + |
| 20 | +# Create your feature/bug branch |
| 21 | +git checkout -b fix/your-bug-name |
| 22 | +# or |
| 23 | +git checkout -b feat/your-feature-name |
| 24 | +``` |
| 25 | + |
| 26 | +## Stage 2: Develop and Test Locally |
| 27 | + |
| 28 | +```bash |
| 29 | +# Make your changes... |
| 30 | + |
| 31 | +# Run linting |
| 32 | +uv run ruff check src/ tests/ |
| 33 | + |
| 34 | +# Run type checking |
| 35 | +uv run mypy src/ tests/ |
| 36 | + |
| 37 | +# Run tests |
| 38 | +uv run pytest tests/ -v |
| 39 | + |
| 40 | +# Format code if needed |
| 41 | +uv run ruff format src/ tests/ |
| 42 | +``` |
| 43 | + |
| 44 | +## Stage 3: Commit and Push |
| 45 | + |
| 46 | +```bash |
| 47 | +# Stage your changes |
| 48 | +git add <files> |
| 49 | + |
| 50 | +# Commit with descriptive message |
| 51 | +git commit -m "fix(component): description of the fix" |
| 52 | + |
| 53 | +# Push to remote |
| 54 | +git push origin fix/your-bug-name |
| 55 | +``` |
| 56 | + |
| 57 | +## Stage 4: Create Pull Request |
| 58 | + |
| 59 | +1. Go to GitHub and create a PR from your branch to `main` |
| 60 | +2. Fill in the PR description with: |
| 61 | + - Summary of changes |
| 62 | + - Problem being solved |
| 63 | + - Testing performed |
| 64 | +3. Wait for CI checks to pass (lint, test workflows) |
| 65 | +4. Get PR reviewed and approved |
| 66 | +5. Merge PR to `main` |
| 67 | + |
| 68 | +## Stage 5: Publish to Test PyPI (Optional but Recommended) |
| 69 | + |
| 70 | +After PR is merged to main, publish to Test PyPI for validation: |
| 71 | + |
| 72 | +```bash |
| 73 | +# Fetch latest changes |
| 74 | +git fetch origin |
| 75 | + |
| 76 | +# Switch to test branch |
| 77 | +git checkout test |
| 78 | +git pull origin test |
| 79 | + |
| 80 | +# Merge main into test |
| 81 | +git merge origin/main -m "Merge main into test for testing" |
| 82 | + |
| 83 | +# Push to trigger Test PyPI workflow |
| 84 | +git push origin test |
| 85 | +``` |
| 86 | + |
| 87 | +The workflow will automatically: |
| 88 | + |
| 89 | +- Build the package with a dev version (e.g., `1.0.6.dev0`) |
| 90 | +- Publish to Test PyPI |
| 91 | +- Attempt installation verification |
| 92 | + |
| 93 | +### Verify Test PyPI Installation |
| 94 | + |
| 95 | +```bash |
| 96 | +pip install --index-url https://test.pypi.org/simple/ \ |
| 97 | + --extra-index-url https://pypi.org/simple/ \ |
| 98 | + workato-platform-cli |
| 99 | + |
| 100 | +workato --version |
| 101 | +``` |
| 102 | + |
| 103 | +## Stage 6: Publish to Production PyPI |
| 104 | + |
| 105 | +**IMPORTANT:** Follow this exact order to avoid workflow failures. |
| 106 | + |
| 107 | +### Step 1: Determine the new version number |
| 108 | + |
| 109 | +Check the latest tag: |
| 110 | + |
| 111 | +```bash |
| 112 | +git fetch --tags |
| 113 | +git tag --sort=-v:refname | head -5 |
| 114 | +``` |
| 115 | + |
| 116 | +Increment appropriately (e.g., `1.0.5` → `1.0.6`). |
| 117 | + |
| 118 | +### Step 2: Merge main into release and push |
| 119 | + |
| 120 | +```bash |
| 121 | +# Switch to release branch |
| 122 | +git checkout release |
| 123 | +git pull origin release |
| 124 | + |
| 125 | +# Merge main into release |
| 126 | +git merge origin/main -m "Merge main into release for v1.0.6" |
| 127 | + |
| 128 | +# Push release branch |
| 129 | +git push origin release |
| 130 | +``` |
| 131 | + |
| 132 | +### Step 3: Create and push the version tag |
| 133 | + |
| 134 | +**Only after the release branch is pushed:** |
| 135 | + |
| 136 | +```bash |
| 137 | +# Switch to main (or stay on release - they should be at same commit) |
| 138 | +git checkout main |
| 139 | +git pull origin main |
| 140 | + |
| 141 | +# Create the version tag |
| 142 | +git tag 1.0.6 |
| 143 | + |
| 144 | +# Push the tag |
| 145 | +git push origin 1.0.6 |
| 146 | +``` |
| 147 | + |
| 148 | +### Why This Order Matters |
| 149 | + |
| 150 | +The PyPI workflow triggers on: |
| 151 | + |
| 152 | +- Push to `release` branch |
| 153 | +- Push of version tags (e.g., `1.0.6`) |
| 154 | + |
| 155 | +The workflow requires an exact git tag for production releases. If you push the tag first: |
| 156 | + |
| 157 | +1. Tag push triggers workflow |
| 158 | +2. Workflow tries to deploy to `release` environment |
| 159 | +3. **FAILS** - Tag is not allowed by environment protection rules (only `release` branch is) |
| 160 | + |
| 161 | +By pushing the `release` branch first: |
| 162 | + |
| 163 | +1. Branch push triggers workflow |
| 164 | +2. Workflow finds the tag (created locally or already pushed) |
| 165 | +3. **SUCCEEDS** - `release` branch is allowed to deploy |
| 166 | + |
| 167 | +## Workflow Triggers Summary |
| 168 | + |
| 169 | +| Trigger | Environment | PyPI Target | |
| 170 | +| ------------------------ | ----------- | ----------------------------------------------- | |
| 171 | +| Push to `test` branch | test | Test PyPI | |
| 172 | +| Push to `release` branch | release | Production PyPI | |
| 173 | +| Push version tag | release | Production PyPI (but may fail protection rules) | |
| 174 | +| Manual workflow_dispatch | Selected | Depends on selection | |
| 175 | + |
| 176 | +## Troubleshooting |
| 177 | + |
| 178 | +### "Production releases require an exact git tag" |
| 179 | + |
| 180 | +The release branch was pushed but no matching tag exists. Create and push the tag: |
| 181 | + |
| 182 | +```bash |
| 183 | +git tag 1.0.X |
| 184 | +git push origin 1.0.X |
| 185 | +``` |
| 186 | + |
| 187 | +### "Tag is not allowed to deploy to release due to environment protection rules" |
| 188 | + |
| 189 | +The tag was pushed before the release branch. This workflow run will fail - ignore it. Push the release branch to trigger a successful run: |
| 190 | + |
| 191 | +```bash |
| 192 | +git checkout release |
| 193 | +git merge origin/main |
| 194 | +git push origin release |
| 195 | +``` |
| 196 | + |
| 197 | +### Version mismatch or wrong version published |
| 198 | + |
| 199 | +The version is derived from git tags using `hatch-vcs`. Ensure: |
| 200 | + |
| 201 | +1. The tag follows semver format: `X.Y.Z` (no `v` prefix) |
| 202 | +2. The tag points to the commit being released |
| 203 | +3. You've fetched all tags: `git fetch --tags` |
| 204 | + |
| 205 | +## Quick Reference: Complete Release Commands |
| 206 | + |
| 207 | +```bash |
| 208 | +# After PR is merged to main... |
| 209 | + |
| 210 | +# 1. Update local main |
| 211 | +git checkout main |
| 212 | +git pull origin main |
| 213 | + |
| 214 | +# 2. (Optional) Test on Test PyPI |
| 215 | +git checkout test |
| 216 | +git pull origin test |
| 217 | +git merge origin/main -m "Merge main into test" |
| 218 | +git push origin test |
| 219 | + |
| 220 | +# 3. Release to Production PyPI |
| 221 | +git checkout release |
| 222 | +git pull origin release |
| 223 | +git merge origin/main -m "Merge main into release for vX.Y.Z" |
| 224 | +git push origin release |
| 225 | + |
| 226 | +# 4. Create version tag (after release branch push) |
| 227 | +git checkout main |
| 228 | +git tag X.Y.Z |
| 229 | +git push origin X.Y.Z |
| 230 | +``` |
0 commit comments