|
| 1 | +# Release Guide: Publishing django-rustfs to PyPI |
| 2 | + |
| 3 | +This guide explains how to publish a new version of django-rustfs to PyPI using GitHub Releases and the automated CD pipeline. |
| 4 | + |
| 5 | +## Prerequisites |
| 6 | + |
| 7 | +Before you can publish, you must configure **Trusted Publishing** on PyPI (one-time setup). |
| 8 | + |
| 9 | +### Step 1: Configure PyPI Trusted Publishing |
| 10 | + |
| 11 | +1. Go to [pypi.org/manage/account/publishing](https://pypi.org/manage/account/publishing) |
| 12 | +2. Click **"Add a new pending publisher"** |
| 13 | +3. Fill in the form: |
| 14 | + - **PyPI Project Name**: `django-rustfs` |
| 15 | + - **Owner**: `CasualEngineerZombie` |
| 16 | + - **Repository name**: `django-rustfs` |
| 17 | + - **Workflow name**: `python-publish.yml` |
| 18 | + - **Environment name**: `pypi` |
| 19 | +4. Click **"Add"** |
| 20 | + |
| 21 | +This tells PyPI to trust the GitHub Actions workflow running in this repository. |
| 22 | + |
| 23 | +## Preparing a Release |
| 24 | + |
| 25 | +### Step 1: Update the Version |
| 26 | + |
| 27 | +Edit `pyproject.toml` and bump the version: |
| 28 | + |
| 29 | +```toml |
| 30 | +[project] |
| 31 | +name = "django-rustfs" |
| 32 | +version = "0.2.0" # <-- bump this |
| 33 | +``` |
| 34 | + |
| 35 | +Follow [Semantic Versioning](https://semver.org/): |
| 36 | +- `MAJOR` — breaking changes |
| 37 | +- `MINOR` — new features, backward compatible |
| 38 | +- `PATCH` — bug fixes |
| 39 | + |
| 40 | +### Step 2: Update the Changelog |
| 41 | + |
| 42 | +Add a section to `CHANGELOG.md`: |
| 43 | + |
| 44 | +```markdown |
| 45 | +## 0.2.0 (2026-06-04) |
| 46 | + |
| 47 | +### Added |
| 48 | +- New feature X |
| 49 | + |
| 50 | +### Fixed |
| 51 | +- Bug fix Y |
| 52 | + |
| 53 | +### Changed |
| 54 | +- Improvement Z |
| 55 | +``` |
| 56 | + |
| 57 | +### Step 3: Commit and Push |
| 58 | + |
| 59 | +```bash |
| 60 | +git add pyproject.toml CHANGELOG.md |
| 61 | +git commit -m "Release v0.2.0" |
| 62 | +git push origin main |
| 63 | +``` |
| 64 | + |
| 65 | +### Step 4: Verify CI Passes |
| 66 | + |
| 67 | +Go to [GitHub Actions](https://github.com/CasualEngineerZombie/django-rustfs/actions) and make sure: |
| 68 | +- `Python package` workflow passes on all Python versions |
| 69 | +- `Lint` workflow passes |
| 70 | + |
| 71 | +**Do NOT create a release if CI is failing.** |
| 72 | + |
| 73 | +## Creating the GitHub Release |
| 74 | + |
| 75 | +### Method 1: Via GitHub Web UI |
| 76 | + |
| 77 | +1. Go to your repository on GitHub: `https://github.com/CasualEngineerZombie/django-rustfs` |
| 78 | +2. Click **"Releases"** in the right sidebar (or go to `/releases`) |
| 79 | +3. Click **"Draft a new release"** |
| 80 | +4. Click **"Choose a tag"** and type the new version: `v0.2.0` |
| 81 | +5. Click **"Create new tag: v0.2.0"** |
| 82 | +6. Set **Target**: `main` (or the commit you want to release) |
| 83 | +7. Set **Release title**: `v0.2.0` |
| 84 | +8. In the **Description** box, paste the changelog for this version: |
| 85 | + ```markdown |
| 86 | + ## What's Changed |
| 87 | + |
| 88 | + ### Added |
| 89 | + - New feature X |
| 90 | + |
| 91 | + ### Fixed |
| 92 | + - Bug fix Y |
| 93 | + ``` |
| 94 | +9. Leave **"Set as a pre-release"** unchecked (unless it's alpha/beta) |
| 95 | +10. Leave **"Set as the latest release"** checked |
| 96 | +11. Click **"Publish release"** |
| 97 | + |
| 98 | +### Method 2: Via Git CLI |
| 99 | + |
| 100 | +```bash |
| 101 | +# Create an annotated tag |
| 102 | +git tag -a v0.2.0 -m "Release v0.2.0" |
| 103 | + |
| 104 | +# Push the tag to GitHub |
| 105 | +git push origin v0.2.0 |
| 106 | +``` |
| 107 | + |
| 108 | +Then go to GitHub Releases and edit the tag to add release notes. |
| 109 | + |
| 110 | +## What Happens Next (Automated) |
| 111 | + |
| 112 | +After you click **"Publish release"**, GitHub Actions automatically: |
| 113 | + |
| 114 | +1. **Triggers** the `python-publish.yml` workflow |
| 115 | +2. **Builds** the package (`python -m build`) |
| 116 | +3. **Verifies** the distributions (`twine check dist/*`) |
| 117 | +4. **Uploads** artifacts to GitHub |
| 118 | +5. **Publishes** to PyPI using trusted publishing |
| 119 | + |
| 120 | +### Monitoring the Release |
| 121 | + |
| 122 | +1. Go to [GitHub Actions](https://github.com/CasualEngineerZombie/django-rustfs/actions) |
| 123 | +2. Watch the **"Upload Python Package"** workflow run |
| 124 | +3. It should complete in ~2-3 minutes |
| 125 | + |
| 126 | +### Verifying the Release |
| 127 | + |
| 128 | +Once the workflow completes: |
| 129 | + |
| 130 | +1. Go to [PyPI](https://pypi.org/project/django-rustfs/) |
| 131 | +2. You should see the new version listed |
| 132 | +3. The release URL will be: `https://pypi.org/project/django-rustfs/0.2.0/` |
| 133 | + |
| 134 | +Users can now install it: |
| 135 | + |
| 136 | +```bash |
| 137 | +pip install django-rustfs==0.2.0 |
| 138 | +``` |
| 139 | + |
| 140 | +## Troubleshooting |
| 141 | + |
| 142 | +### "Trusted publishing" error |
| 143 | + |
| 144 | +**Symptom**: Publish step fails with `invalid-publisher` or similar. |
| 145 | + |
| 146 | +**Fix**: |
| 147 | +- Double-check the PyPI trusted publisher config matches exactly: |
| 148 | + - Owner: `CasualEngineerZombie` |
| 149 | + - Repository: `django-rustfs` |
| 150 | + - Workflow: `python-publish.yml` |
| 151 | + - Environment: `pypi` |
| 152 | +- Make sure you created the release from the correct repository (not a fork) |
| 153 | + |
| 154 | +### "Environment not found" error |
| 155 | + |
| 156 | +**Symptom**: Workflow fails waiting for environment approval. |
| 157 | + |
| 158 | +**Fix**: |
| 159 | +- Go to repository **Settings > Environments** |
| 160 | +- Create an environment named `pypi` if it doesn't exist |
| 161 | +- (Optional) Add protection rules (require review, deployment branches) |
| 162 | + |
| 163 | +### Build fails |
| 164 | + |
| 165 | +**Symptom**: `release-build` job fails. |
| 166 | + |
| 167 | +**Fix**: |
| 168 | +- Check that `pyproject.toml` is valid |
| 169 | +- Make sure `README.md` exists (required for PyPI) |
| 170 | +- Verify `hatchling` build backend works: `python -m build` locally |
| 171 | + |
| 172 | +### Wrong version uploaded |
| 173 | + |
| 174 | +**Symptom**: PyPI shows old version or wrong version number. |
| 175 | + |
| 176 | +**Fix**: |
| 177 | +- Make sure you bumped `version` in `pyproject.toml` **before** creating the release |
| 178 | +- The release tag (e.g., `v0.2.0`) should match the package version (`0.2.0`) |
| 179 | + |
| 180 | +## Release Checklist |
| 181 | + |
| 182 | +Before every release, verify: |
| 183 | + |
| 184 | +- [ ] Version bumped in `pyproject.toml` |
| 185 | +- [ ] `CHANGELOG.md` updated |
| 186 | +- [ ] CI passing on `main` branch |
| 187 | +- [ ] All tests passing locally: `pytest` |
| 188 | +- [ ] Linting clean: `ruff check .` |
| 189 | +- [ ] Code formatted: `ruff format .` |
| 190 | +- [ ] Types clean: `mypy django_rustfs` |
| 191 | +- [ ] PyPI trusted publisher configured (one-time) |
| 192 | +- [ ] GitHub Release created with tag matching version |
0 commit comments