|
15 | 15 | Infrahub Sync is a versatile Python package that synchronizes data between a source and a destination system. It builds on the robust capabilities of `diffsync` to offer flexible and efficient data synchronization across different platforms, including Netbox, Nautobot, and Infrahub. This package features a Typer-based CLI for ease of use, supporting operations such as listing available sync projects, generating diffs, and executing sync processes. |
16 | 16 |
|
17 | 17 | For comprehensive documentation on using Infrahub Sync, visit the [official Infrahub Sync documentation](https://docs.infrahub.app/sync/) |
| 18 | + |
| 19 | +## Publishing a Release |
| 20 | + |
| 21 | +This section documents how to publish new releases of `infrahub-sync` to PyPI. |
| 22 | + |
| 23 | +### Overview |
| 24 | + |
| 25 | +The project uses an automated release system powered by GitHub Actions. There are three ways to publish a release: |
| 26 | + |
| 27 | +1. **Automated Release** (recommended for regular releases) |
| 28 | +2. **Manual GitHub Release** (for controlled releases) |
| 29 | +3. **Manual Workflow Dispatch** (for emergency or custom releases) |
| 30 | + |
| 31 | +### Prerequisites |
| 32 | + |
| 33 | +Before publishing, ensure: |
| 34 | + |
| 35 | +- You have write access to the repository |
| 36 | +- The `PYPI_TOKEN` secret is configured in repository settings |
| 37 | +- The `GH_INFRAHUB_BOT_TOKEN` secret is configured (for automated releases) |
| 38 | + |
| 39 | +### Method 1: Automated Release (Recommended) |
| 40 | + |
| 41 | +This is the standard release flow. Releases are triggered automatically when PRs are merged to `main` or `stable` branches. |
| 42 | + |
| 43 | +#### Step 1: Label Your Pull Requests |
| 44 | + |
| 45 | +Apply appropriate labels to PRs before merging. Labels determine the version bump: |
| 46 | + |
| 47 | +| Label | Version Bump | Use When | |
| 48 | +| ---------------------------------------------------------------------- | ---------------------- | ---------------------------- | |
| 49 | +| `changes/major`, `type/breaking-change` | Major (1.0.0 → 2.0.0) | Breaking API changes | |
| 50 | +| `changes/minor`, `type/feature`, `type/refactoring` | Minor (1.0.0 → 1.1.0) | New features, refactoring | |
| 51 | +| `changes/patch`, `type/bug`, `type/housekeeping`, `type/documentation` | Patch (1.0.0 → 1.0.1) | Bug fixes, docs, maintenance | |
| 52 | + |
| 53 | +Auto-labeling rules are configured in `.github/release-drafter.yml` but require a separate |
| 54 | +workflow trigger to activate. For now, apply labels manually: |
| 55 | + |
| 56 | +| PR Title Pattern | Recommended Label | |
| 57 | +| ---------------------------------------- | ------------------- | |
| 58 | +| Contains `fix` | `type/bug` | |
| 59 | +| Contains `enhance`, `improve`, `feature` | `type/feature` | |
| 60 | +| Contains `chore` | `ci/skip-changelog` | |
| 61 | +| Contains `deprecat` | `type/deprecated` | |
| 62 | + |
| 63 | +#### Step 2: Merge to Main |
| 64 | + |
| 65 | +Merge your labeled PR to the `main` branch. The automation will: |
| 66 | + |
| 67 | +1. Calculate the next version based on PR labels |
| 68 | +2. Update `pyproject.toml` with the new version (and regenerate `poetry.lock`) |
| 69 | +3. Commit changes as `chore(release): v{VERSION} [skip ci]` |
| 70 | +4. Create/update a draft GitHub Release with auto-generated release notes |
| 71 | + |
| 72 | +#### Step 3: Publish the GitHub Release |
| 73 | + |
| 74 | +1. Navigate to the repository's **Releases** page |
| 75 | +2. Find the draft release created by Release Drafter |
| 76 | +3. Review the auto-generated release notes |
| 77 | +4. Edit if needed (add context, highlights, migration notes) |
| 78 | +5. Click **Publish release** |
| 79 | + |
| 80 | +Publishing the release triggers the PyPI upload automatically. |
| 81 | + |
| 82 | +### Method 2: Manual GitHub Release |
| 83 | + |
| 84 | +Use this method when you want full control over the release timing and notes. |
| 85 | + |
| 86 | +#### Step 1: Update the Version |
| 87 | + |
| 88 | +Update the version in `pyproject.toml`: |
| 89 | + |
| 90 | +```bash |
| 91 | +poetry version <major|minor|patch|X.Y.Z> |
| 92 | +poetry lock |
| 93 | +``` |
| 94 | + |
| 95 | +Commit and push the changes: |
| 96 | + |
| 97 | +```bash |
| 98 | +git add pyproject.toml poetry.lock |
| 99 | +git commit -m "chore(release): v$(poetry version -s)" |
| 100 | +git push origin main |
| 101 | +``` |
| 102 | + |
| 103 | +#### Step 2: Create a GitHub Release |
| 104 | + |
| 105 | +1. Go to **Releases** → **Draft a new release** |
| 106 | +2. Click **Choose a tag** and create a new tag matching your version (e.g., `1.6.0`) |
| 107 | +3. Set the target to `main` branch |
| 108 | +4. Add a release title (e.g., `1.6.0`) |
| 109 | +5. Write release notes describing the changes |
| 110 | +6. Click **Publish release** |
| 111 | + |
| 112 | +This triggers the `trigger-release.yml` workflow, which publishes to PyPI. |
| 113 | + |
| 114 | +### Method 3: Manual Workflow Dispatch |
| 115 | + |
| 116 | +Use this for emergency releases or when you need to bypass the standard flow. |
| 117 | + |
| 118 | +#### Via GitHub UI |
| 119 | + |
| 120 | +1. Go to **Actions** → **Publish Infrahub Sync Package** |
| 121 | +2. Click **Run workflow** |
| 122 | +3. Configure the inputs: |
| 123 | + - `version`: The version string (e.g., `1.6.0`) - optional, for labeling |
| 124 | + - `publish`: Set to `true` to publish to PyPI (default: `false`) |
| 125 | + - `runs-on`: OS for the runner (default: `ubuntu-22.04`) |
| 126 | +4. Click **Run workflow** |
| 127 | + |
| 128 | +#### Via GitHub CLI |
| 129 | + |
| 130 | +```bash |
| 131 | +gh workflow run workflow-publish.yml \ |
| 132 | + --field version="1.6.0" \ |
| 133 | + --field publish=true |
| 134 | +``` |
| 135 | + |
| 136 | +**Important:** When using workflow dispatch, ensure `pyproject.toml` already has the correct version, as this method builds from the current code state. |
| 137 | + |
| 138 | +### Release Notes |
| 139 | + |
| 140 | +Release notes are auto-generated based on merged PRs and their labels: |
| 141 | + |
| 142 | +| Category | Labels | |
| 143 | +| -------------------- | --------------------------------------------------- | |
| 144 | +| Breaking Changes | `changes/major` | |
| 145 | +| Minor Changes | `changes/minor`, `type/feature`, `type/refactoring` | |
| 146 | +| Patch & Bug Fixes | `type/bug`, `changes/patch` | |
| 147 | +| Documentation Change | `type/documentation` | |
| 148 | + |
| 149 | +PRs with these labels are excluded from release notes: |
| 150 | + |
| 151 | +- `ci/skip-changelog` |
| 152 | +- `type/duplicate` |
| 153 | + |
| 154 | +### Verifying a Release |
| 155 | + |
| 156 | +After publishing: |
| 157 | + |
| 158 | +1. **Check PyPI**: Visit [pypi.org/project/infrahub-sync](https://pypi.org/project/infrahub-sync/) to confirm the new version is available |
| 159 | +2. **Check GitHub Actions**: Ensure the publish workflow completed successfully |
| 160 | +3. **Test Installation**: |
| 161 | + |
| 162 | + ```bash |
| 163 | + pip install infrahub-sync==<new-version> |
| 164 | + infrahub-sync --version |
| 165 | + ``` |
| 166 | + |
| 167 | +### Troubleshooting |
| 168 | + |
| 169 | +#### Release workflow skipped |
| 170 | + |
| 171 | +The automated release is skipped when: |
| 172 | + |
| 173 | +- The commit author is `opsmill-bot` with a `chore` prefix (prevents recursive releases) |
| 174 | +- No version bump is detected (no labeled PRs since last release) |
| 175 | +- Changes are only in the `docs/` directory |
| 176 | + |
| 177 | +#### PyPI upload failed |
| 178 | + |
| 179 | +Common causes: |
| 180 | + |
| 181 | +- `PYPI_TOKEN` secret is missing or invalid |
| 182 | +- Version already exists on PyPI (versions cannot be overwritten) |
| 183 | +- Network issues during upload |
| 184 | + |
| 185 | +To retry, use the manual workflow dispatch method. |
| 186 | + |
| 187 | +#### Version not bumped correctly |
| 188 | + |
| 189 | +Ensure PRs have appropriate labels before merging. If labels are missing, the version drafter may not calculate a new version. |
| 190 | + |
| 191 | +### Workflow Files Reference |
| 192 | + |
| 193 | +| Workflow | Type | Purpose | |
| 194 | +| ------------------------------ | ------------------------------ | ------------------------------------------------------------------------ | |
| 195 | +| `trigger-push-stable.yml` | Push to `main`/`stable` | Calculates version, bumps `pyproject.toml`, triggers release draft | |
| 196 | +| `workflow-release-drafter.yml` | Reusable (`workflow_call`) | Creates/updates GitHub Release draft; invoked by `trigger-release.yml` | |
| 197 | +| `trigger-release.yml` | GitHub Release published | Orchestrates release: invokes release drafter and publish workflows | |
| 198 | +| `workflow-publish.yml` | Reusable (`workflow_dispatch`) | Builds and publishes package to PyPI; invoked by `trigger-release.yml` | |
0 commit comments