|
| 1 | +--- |
| 2 | +name: "release-process" |
| 3 | +description: "Complete release workflow for BlazorWebFormsComponents: version bump, PR from dev→main, GitHub Release creation, and post-release CI/CD pipeline that publishes NuGet packages, deploys docs to GitHub Pages, builds Docker images, and deploys sample sites. Use when preparing a release, creating a release PR, tagging a version, or troubleshooting release CI/CD." |
| 4 | +domain: "release-workflow" |
| 5 | +confidence: "medium" |
| 6 | +source: "manual" |
| 7 | +--- |
| 8 | + |
| 9 | +## Context |
| 10 | + |
| 11 | +BlazorWebFormsComponents uses a two-branch model: `dev` (active development) and `main` (releases only). All feature work merges into `dev` via squash merge. Releases are cut by merging `dev` into `main` via a regular merge commit, then tagging and creating a GitHub Release. |
| 12 | + |
| 13 | +The upstream repository is `FritzAndFriends/BlazorWebFormsComponents`. The fork is `csharpfritz/BlazorWebFormsComponents`. |
| 14 | + |
| 15 | +## Release Workflow — Step by Step |
| 16 | + |
| 17 | +### Prerequisites |
| 18 | + |
| 19 | +- All feature PRs for this release are squash-merged into `upstream/dev` |
| 20 | +- Local `dev` branch is synced: `git fetch upstream && git reset --hard upstream/dev && git push origin dev` |
| 21 | +- CI is green on dev (Build and Test + Integration Tests passing) |
| 22 | + |
| 23 | +### Step 1 — Bump Version |
| 24 | + |
| 25 | +Version is managed by Nerdbank.GitVersioning (`version.json` at repo root). |
| 26 | + |
| 27 | +```json |
| 28 | +{ |
| 29 | + "version": "0.19.0", |
| 30 | + "publicReleaseRefSpec": [ |
| 31 | + "^refs/heads/master$", |
| 32 | + "^refs/heads/main$", |
| 33 | + "^refs/heads/v\\d+(?:\\.\\d+)?$", |
| 34 | + "^refs/tags/v\\d+\\.\\d+(\\.\\d+)?$" |
| 35 | + ], |
| 36 | + "release": { |
| 37 | + "firstUnstableTag": "preview" |
| 38 | + } |
| 39 | +} |
| 40 | +``` |
| 41 | + |
| 42 | +- For a **new release**: update `"version"` in `version.json` if the version has changed since last release. |
| 43 | +- Commit the version bump to `dev` and push before creating the release PR. |
| 44 | +- The version in `version.json` is the NEXT version after this release (NBGV auto-increments). |
| 45 | + |
| 46 | +### Step 2 — Create Release PR |
| 47 | + |
| 48 | +Create a PR from `upstream/dev` → `upstream/main`: |
| 49 | + |
| 50 | +```bash |
| 51 | +# Ensure dev is current |
| 52 | +git checkout dev |
| 53 | +git fetch upstream |
| 54 | +git reset --hard upstream/dev |
| 55 | +git push origin dev |
| 56 | + |
| 57 | +# Create the release PR via gh CLI |
| 58 | +gh pr create \ |
| 59 | + --repo FritzAndFriends/BlazorWebFormsComponents \ |
| 60 | + --base main \ |
| 61 | + --head dev \ |
| 62 | + --title "Release v{VERSION}" \ |
| 63 | + --body "## Release v{VERSION} |
| 64 | +
|
| 65 | +### What's Included |
| 66 | +{summary of features since last release} |
| 67 | +
|
| 68 | +### Checklist |
| 69 | +- [ ] All CI checks passing |
| 70 | +- [ ] Integration tests passing |
| 71 | +- [ ] Version number correct in version.json |
| 72 | +- [ ] Release notes prepared" |
| 73 | +``` |
| 74 | + |
| 75 | +**Important:** This PR uses **regular merge** (NOT squash merge). This preserves the full commit history on main and keeps dev and main in sync. |
| 76 | + |
| 77 | +### Step 3 — Merge the Release PR |
| 78 | + |
| 79 | +Merge using **regular merge commit** (not squash, not rebase): |
| 80 | + |
| 81 | +```bash |
| 82 | +gh pr merge {PR_NUMBER} \ |
| 83 | + --repo FritzAndFriends/BlazorWebFormsComponents \ |
| 84 | + --merge \ |
| 85 | + --subject "Release v{VERSION}" |
| 86 | +``` |
| 87 | + |
| 88 | +### Step 4 — Create Git Tag and GitHub Release |
| 89 | + |
| 90 | +After the merge to main: |
| 91 | + |
| 92 | +```bash |
| 93 | +# Fetch the merge commit |
| 94 | +git fetch upstream |
| 95 | +git checkout main |
| 96 | +git reset --hard upstream/main |
| 97 | + |
| 98 | +# Tag the release |
| 99 | +git tag -a v{VERSION} -m "Release v{VERSION}" |
| 100 | +git push upstream v{VERSION} |
| 101 | + |
| 102 | +# Create GitHub Release (triggers CI/CD pipeline) |
| 103 | +gh release create v{VERSION} \ |
| 104 | + --repo FritzAndFriends/BlazorWebFormsComponents \ |
| 105 | + --title "v{VERSION}" \ |
| 106 | + --notes "{release notes}" \ |
| 107 | + --target main |
| 108 | +``` |
| 109 | + |
| 110 | +### Step 5 — Verify CI/CD Pipeline |
| 111 | + |
| 112 | +The GitHub Release (`published` event) triggers `.github/workflows/release.yml` which runs 5 parallel jobs: |
| 113 | + |
| 114 | +| Job | What It Does | Artifacts | |
| 115 | +|-----|-------------|-----------| |
| 116 | +| `build-and-test` | Build + run unit tests | `test-results.trx` | |
| 117 | +| `publish-nuget` | Pack + push to GitHub Packages + nuget.org | `.nupkg` attached to release | |
| 118 | +| `deploy-docker` | Build Docker image → GHCR + trigger Azure webhook | Docker image tags: `latest`, `{version}`, `{sha}` | |
| 119 | +| `deploy-docs` | Build MkDocs → deploy to `gh-pages` branch | GitHub Pages site | |
| 120 | +| `build-demos` | Publish server-side demo → attach `.tar.gz` to release | Demo artifact | |
| 121 | + |
| 122 | +Additionally, pushes to `main` trigger: |
| 123 | +- `docs.yml` — MkDocs build + GitHub Pages deploy (path-filtered: `docs/**`, `mkdocs.yml`) |
| 124 | +- `demo.yml` — Build demo sites (path-filtered: `src/**`, `samples/**`) |
| 125 | + |
| 126 | +### Step 6 — Post-Release Sync |
| 127 | + |
| 128 | +After release is complete: |
| 129 | + |
| 130 | +```bash |
| 131 | +# Sync local branches |
| 132 | +git fetch upstream |
| 133 | +git checkout dev |
| 134 | +git reset --hard upstream/dev |
| 135 | +git push origin dev |
| 136 | + |
| 137 | +git checkout main |
| 138 | +git reset --hard upstream/main |
| 139 | +git push origin main |
| 140 | +``` |
| 141 | + |
| 142 | +## CI/CD Architecture |
| 143 | + |
| 144 | +### Workflows by Trigger |
| 145 | + |
| 146 | +| Workflow | Trigger | Branch/Event | |
| 147 | +|----------|---------|-------------| |
| 148 | +| `build.yml` | push, PR | `main`, `dev`, `v*` | |
| 149 | +| `integration-tests.yml` | push, PR | `main`, `dev`, `v*` | |
| 150 | +| `release.yml` | release published | tags `v*` | |
| 151 | +| `docs.yml` | push, PR | `main`, `v*` (docs paths only) | |
| 152 | +| `demo.yml` | push, PR, workflow_run | `main`, `v*` (src/samples paths) | |
| 153 | +| `nuget.yml` | workflow_dispatch | manual (emergency publish) | |
| 154 | +| `deploy-server-side.yml` | workflow_dispatch | manual (emergency deploy) | |
| 155 | + |
| 156 | +### Version Resolution |
| 157 | + |
| 158 | +- **During development (dev branch):** NBGV computes version from `version.json` + git height → e.g., `0.19.0-preview.42` |
| 159 | +- **During release (release.yml):** Version extracted from git tag (`v0.19.0` → `0.19.0`). NBGV is REMOVED from the build to prevent conflicts. |
| 160 | +- **Manual publish (nuget.yml):** Version provided as workflow_dispatch input. |
| 161 | + |
| 162 | +### NuGet Publishing |
| 163 | + |
| 164 | +- **GitHub Packages:** Always published (uses `GITHUB_TOKEN`) |
| 165 | +- **nuget.org:** Published only if `NUGET_API_KEY` secret is configured |
| 166 | +- **Package ID:** `Fritz.BlazorWebFormsComponents` |
| 167 | + |
| 168 | +### Docker / Azure Deployment |
| 169 | + |
| 170 | +- **Registry:** `ghcr.io/fritzandfriends/blazorwebformscomponents/serversidesamples` |
| 171 | +- **Tags:** `latest`, `{version}`, `{commit-sha}` |
| 172 | +- **Azure:** Triggered via webhook URL in `AZURE_WEBAPP_WEBHOOK_URL` secret (if configured) |
| 173 | + |
| 174 | +### Documentation Deployment |
| 175 | + |
| 176 | +- **Tool:** MkDocs (via Docker: `docs/Dockerfile`) |
| 177 | +- **Target:** GitHub Pages (`gh-pages` branch) |
| 178 | +- **Deploys on:** push to `main` with docs path changes, OR release published |
| 179 | + |
| 180 | +## Key Files |
| 181 | + |
| 182 | +| File | Purpose | |
| 183 | +|------|---------| |
| 184 | +| `version.json` | NBGV version configuration | |
| 185 | +| `Directory.Build.props` | Shared build properties (NBGV reference) | |
| 186 | +| `.github/workflows/release.yml` | Main release pipeline (5 jobs) | |
| 187 | +| `.github/workflows/nuget.yml` | Manual NuGet publish (emergency) | |
| 188 | +| `.github/workflows/deploy-server-side.yml` | Manual Azure deploy (emergency) | |
| 189 | +| `.github/workflows/build.yml` | CI: build + unit tests + analyzer tests | |
| 190 | +| `.github/workflows/integration-tests.yml` | CI: Playwright integration tests | |
| 191 | +| `.github/workflows/docs.yml` | CI/CD: MkDocs build + GitHub Pages | |
| 192 | +| `.github/workflows/demo.yml` | CI: demo site build | |
| 193 | +| `nuget.config` | NuGet source configuration | |
| 194 | + |
| 195 | +## Common Issues |
| 196 | + |
| 197 | +### "Version conflicts" during release build |
| 198 | +The release workflow strips NBGV from `Directory.Build.props` and uses `-p:Version={tag}` directly. If you see version conflicts, check that the `sed` command in `release.yml` correctly removes the NBGV PackageReference. |
| 199 | + |
| 200 | +### NuGet push fails |
| 201 | +Check that `NUGET_API_KEY` is set in the repository secrets. GitHub Packages push uses `GITHUB_TOKEN` (auto-provided). |
| 202 | + |
| 203 | +### Docker image not deploying to Azure |
| 204 | +Check that `AZURE_WEBAPP_WEBHOOK_URL` secret is configured. The webhook call is non-fatal — it logs a warning if it fails. |
| 205 | + |
| 206 | +### Docs not deploying |
| 207 | +Docs only deploy on push to `main` (not PRs). Check path filters — only changes to `docs/**`, `mkdocs.yml`, or `.github/workflows/docs.yml` trigger the docs workflow. |
0 commit comments