|
| 1 | +# Publishing envoy_toolshed to Bazel Central Registry (BCR) |
| 2 | + |
| 3 | +This document describes the workflow for publishing the `envoy_toolshed` Bazel module to the [Bazel Central Registry (BCR)](https://github.com/bazelbuild/bazel-central-registry). |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +The toolshed repository uses the [publish-to-bcr](https://github.com/bazel-contrib/publish-to-bcr) GitHub Action to automate publishing releases to the BCR. When a release is created with a tag following the pattern `bazel-v*`, the workflow automatically: |
| 8 | + |
| 9 | +1. Creates a BCR entry from the `.bcr` templates |
| 10 | +2. Generates attestations for the release artifacts |
| 11 | +3. Pushes the entry to a fork of the BCR |
| 12 | +4. Opens a pull request against the upstream BCR |
| 13 | + |
| 14 | +## Prerequisites |
| 15 | + |
| 16 | +### 1. Fork the Bazel Central Registry |
| 17 | + |
| 18 | +Create a fork of [bazelbuild/bazel-central-registry](https://github.com/bazelbuild/bazel-central-registry) in the `envoyproxy` organization: |
| 19 | + |
| 20 | +1. Navigate to https://github.com/bazelbuild/bazel-central-registry |
| 21 | +2. Click "Fork" in the top-right corner |
| 22 | +3. Select the `envoyproxy` organization as the destination |
| 23 | +4. This creates `envoyproxy/bazel-central-registry` |
| 24 | + |
| 25 | +**Note:** The fork must exist at `envoyproxy/bazel-central-registry` as specified in the workflow configuration. |
| 26 | + |
| 27 | +### 2. Create a Personal Access Token (PAT) |
| 28 | + |
| 29 | +Create a Classic Personal Access Token with the following permissions: |
| 30 | + |
| 31 | +1. Go to https://github.com/settings/tokens (GitHub Settings > Developer settings > Personal access tokens > Tokens (classic)) |
| 32 | +2. Click "Generate new token (classic)" |
| 33 | +3. Give it a descriptive name like "BCR Publish Token for envoyproxy/toolshed" |
| 34 | +4. Set an appropriate expiration date (or no expiration for automation) |
| 35 | +5. Select the following scopes: |
| 36 | + - ✅ `repo` (Full control of private repositories) |
| 37 | + - ✅ `workflow` (Update GitHub Action workflows) |
| 38 | +6. Click "Generate token" and **copy the token immediately** (you won't be able to see it again) |
| 39 | + |
| 40 | +**Why these permissions?** |
| 41 | +- `repo`: Required to push commits to the BCR fork |
| 42 | +- `workflow`: Required to open pull requests against the BCR |
| 43 | + |
| 44 | +> [!NOTE] |
| 45 | +> Fine-grained Personal Access Tokens (PATs) are not fully supported because they cannot open pull requests against public repositories. If this limitation is resolved in the future, fine-grained PATs may become an option. For now, use Classic PATs. |
| 46 | +
|
| 47 | +### 3. Add the Token as a Repository Secret |
| 48 | + |
| 49 | +Add the PAT as a secret in the toolshed repository: |
| 50 | + |
| 51 | +1. Go to https://github.com/envoyproxy/toolshed/settings/secrets/actions |
| 52 | +2. Click "New repository secret" |
| 53 | +3. Name: `BCR_PUBLISH_TOKEN` |
| 54 | +4. Value: Paste the token you copied in step 2 |
| 55 | +5. Click "Add secret" |
| 56 | + |
| 57 | +The workflow is now configured to use this token via `${{ secrets.BCR_PUBLISH_TOKEN }}`. |
| 58 | + |
| 59 | +## Publishing a Release |
| 60 | + |
| 61 | +### Automatic Publishing |
| 62 | + |
| 63 | +When you create a GitHub Release with a tag that matches the pattern `bazel-v*`, the publish workflow will automatically run: |
| 64 | + |
| 65 | +1. **Create a release** via the GitHub UI or CLI: |
| 66 | + ```bash |
| 67 | + # Tag the release |
| 68 | + git tag bazel-v0.3.11 |
| 69 | + git push origin bazel-v0.3.11 |
| 70 | + |
| 71 | + # Create the GitHub release |
| 72 | + gh release create bazel-v0.3.11 --title "Bazel Module v0.3.11" --notes "Release notes here" |
| 73 | + ``` |
| 74 | + |
| 75 | +2. **Monitor the workflow**: |
| 76 | + - Go to https://github.com/envoyproxy/toolshed/actions/workflows/publish.yml |
| 77 | + - The workflow will create a BCR entry and open a PR |
| 78 | + |
| 79 | +3. **Review the pull request**: |
| 80 | + - The workflow opens a **draft PR** by default |
| 81 | + - Review the PR at https://github.com/bazelbuild/bazel-central-registry/pulls |
| 82 | + - If everything looks good, mark the PR as "Ready for review" |
| 83 | + - BCR maintainers will review and merge the PR |
| 84 | + |
| 85 | +### Manual Publishing |
| 86 | + |
| 87 | +If you need to republish a release (e.g., after fixing templates), you can manually trigger the workflow: |
| 88 | + |
| 89 | +1. Go to https://github.com/envoyproxy/toolshed/actions/workflows/publish.yml |
| 90 | +2. Click "Run workflow" |
| 91 | +3. Enter the tag name (e.g., `bazel-v0.3.11`) |
| 92 | +4. Click "Run workflow" |
| 93 | + |
| 94 | +### Tag Naming Convention |
| 95 | + |
| 96 | +- **Pattern**: `bazel-v{VERSION}` |
| 97 | +- **Examples**: |
| 98 | + - ✅ `bazel-v0.3.11` → publishes version `0.3.11` |
| 99 | + - ✅ `bazel-v1.0.0` → publishes version `1.0.0` |
| 100 | + - ❌ `v0.3.11` → skipped (Python package release, not Bazel) |
| 101 | + - ❌ `0.3.11` → skipped (no prefix) |
| 102 | + |
| 103 | +The workflow automatically strips the `bazel-v` prefix to determine the module version. |
| 104 | + |
| 105 | +## BCR Templates |
| 106 | + |
| 107 | +The BCR entry is generated from templates in the `.bcr` directory: |
| 108 | + |
| 109 | +``` |
| 110 | +.bcr/ |
| 111 | +├── config.yml # Configuration (moduleRoots) |
| 112 | +└── bazel/ # Templates for the envoy_toolshed module |
| 113 | + ├── metadata.template.json # Module metadata (homepage, maintainers) |
| 114 | + ├── source.template.json # Source archive URL and integrity |
| 115 | + └── presubmit.yml # BCR CI tests |
| 116 | +``` |
| 117 | + |
| 118 | +### Template Files |
| 119 | + |
| 120 | +#### `.bcr/config.yml` |
| 121 | + |
| 122 | +Specifies that the MODULE.bazel file is located in the `bazel/` subdirectory: |
| 123 | + |
| 124 | +```yaml |
| 125 | +moduleRoots: |
| 126 | +- bazel |
| 127 | +``` |
| 128 | +
|
| 129 | +#### `.bcr/bazel/metadata.template.json` |
| 130 | + |
| 131 | +Contains module metadata: |
| 132 | + |
| 133 | +```json |
| 134 | +{ |
| 135 | + "homepage": "https://www.envoyproxy.io/", |
| 136 | + "maintainers": [ |
| 137 | + { |
| 138 | + "github": "mmorel-35", |
| 139 | + "github_user_id": 6032561 |
| 140 | + }, |
| 141 | + { |
| 142 | + "github": "phlax", |
| 143 | + "github_user_id": 454682 |
| 144 | + } |
| 145 | + ], |
| 146 | + "repository": [ |
| 147 | + "github:envoyproxy/toolshed" |
| 148 | + ], |
| 149 | + "versions": [], |
| 150 | + "yanked_versions": {} |
| 151 | +} |
| 152 | +``` |
| 153 | + |
| 154 | +**To update maintainers**: Add your GitHub username and user ID to the `maintainers` array. Find your user ID with: |
| 155 | +```bash |
| 156 | +curl https://api.github.com/users/YOUR_USERNAME | jq .id |
| 157 | +``` |
| 158 | + |
| 159 | +#### `.bcr/bazel/source.template.json` |
| 160 | + |
| 161 | +Defines how to fetch the source archive: |
| 162 | + |
| 163 | +```json |
| 164 | +{ |
| 165 | + "integrity": "", |
| 166 | + "strip_prefix": "{REPO}-{VERSION}/bazel", |
| 167 | + "url": "https://github.com/{OWNER}/{REPO}/archive/refs/tags/bazel-v{TAG}.tar.gz" |
| 168 | +} |
| 169 | +``` |
| 170 | + |
| 171 | +The workflow automatically: |
| 172 | +- Substitutes `{OWNER}`, `{REPO}`, `{VERSION}`, `{TAG}` with actual values |
| 173 | +- Calculates and fills in the `integrity` hash |
| 174 | +- Extracts the `bazel/` subdirectory due to `strip_prefix` |
| 175 | + |
| 176 | +#### `.bcr/bazel/presubmit.yml` |
| 177 | + |
| 178 | +Defines the BCR CI tests that verify the module: |
| 179 | + |
| 180 | +```yaml |
| 181 | +matrix: |
| 182 | + unix_platform: |
| 183 | + - debian11 |
| 184 | + - ubuntu2404 |
| 185 | + - macos_arm64 |
| 186 | + bazel: |
| 187 | + - 7.x |
| 188 | + - 8.x |
| 189 | + - 9.* |
| 190 | +tasks: |
| 191 | + verify_targets: |
| 192 | + name: Verify build targets |
| 193 | + platform: ${{ unix_platform }} |
| 194 | + bazel: ${{ bazel }} |
| 195 | + build_targets: |
| 196 | + - "@envoy_toolshed//..." |
| 197 | +``` |
| 198 | + |
| 199 | +This ensures the module builds successfully across multiple platforms and Bazel versions. |
| 200 | + |
| 201 | +## Troubleshooting |
| 202 | + |
| 203 | +### Workflow doesn't run |
| 204 | + |
| 205 | +**Problem**: The publish workflow didn't trigger after creating a release. |
| 206 | + |
| 207 | +**Solution**: |
| 208 | +- Verify the tag matches the pattern `bazel-v*` (e.g., `bazel-v0.3.11`) |
| 209 | +- Check the workflow runs at https://github.com/envoyproxy/toolshed/actions/workflows/publish.yml |
| 210 | +- Tags like `v0.3.11` without the `bazel-` prefix are intentionally skipped |
| 211 | + |
| 212 | +### Authentication failed when pushing to fork |
| 213 | + |
| 214 | +**Problem**: The workflow fails with an authentication error. |
| 215 | + |
| 216 | +**Solution**: |
| 217 | +1. Verify the `BCR_PUBLISH_TOKEN` secret exists and is valid |
| 218 | +2. Ensure the PAT has `repo` and `workflow` scopes |
| 219 | +3. Check that the PAT hasn't expired |
| 220 | +4. Confirm the fork exists at `envoyproxy/bazel-central-registry` |
| 221 | + |
| 222 | +### Failed to open pull request |
| 223 | + |
| 224 | +**Problem**: Entry was pushed to fork but PR creation failed. |
| 225 | + |
| 226 | +**Solution**: |
| 227 | +1. The PAT needs `workflow` scope to open PRs |
| 228 | +2. Check if a PR already exists for this version |
| 229 | +3. Manually create the PR: |
| 230 | + - Visit the fork: https://github.com/envoyproxy/bazel-central-registry |
| 231 | + - Find the pushed branch (named `envoy_toolshed-bazel-v{VERSION}`) |
| 232 | + - Click "Contribute" → "Open pull request" |
| 233 | + |
| 234 | +### BCR CI tests fail |
| 235 | + |
| 236 | +**Problem**: The PR is created but BCR's presubmit tests fail. |
| 237 | + |
| 238 | +**Solution**: |
| 239 | +1. Review the test failures in the BCR PR |
| 240 | +2. Common issues: |
| 241 | + - Missing or incorrect dependencies in MODULE.bazel |
| 242 | + - Build targets don't exist or fail to build |
| 243 | + - Incompatible Bazel versions |
| 244 | +3. Fix the issues and create a new release, or update `.bcr/bazel/presubmit.yml` if tests need adjustment |
| 245 | + |
| 246 | +### Need to update templates after release |
| 247 | + |
| 248 | +**Problem**: A release was created but the templates had errors. |
| 249 | + |
| 250 | +**Solution**: |
| 251 | +1. Fix the templates in the `.bcr` directory |
| 252 | +2. Commit and push the fixes to `main` |
| 253 | +3. Manually trigger the workflow: |
| 254 | + - Go to https://github.com/envoyproxy/toolshed/actions/workflows/publish.yml |
| 255 | + - Click "Run workflow" |
| 256 | + - Enter the same tag name |
| 257 | + - The workflow will use the updated templates from `main` |
| 258 | + |
| 259 | +## Attestation Support |
| 260 | + |
| 261 | +The workflow generates attestations for enhanced security and supply chain verification: |
| 262 | + |
| 263 | +- **source.json**: Attests the generated source.json file |
| 264 | +- **MODULE.bazel**: Attests the MODULE.bazel file |
| 265 | +- **Release archive**: Attests the source archive |
| 266 | + |
| 267 | +Attestations are uploaded to the GitHub Release and referenced in the BCR entry via `attestations.json`. |
| 268 | + |
| 269 | +> [!NOTE] |
| 270 | +> Attestations require that releases are published (not in draft state) and that the release tag exists in the repository. If you encounter attestation issues, verify that: |
| 271 | +> - The release is marked as "Published" (not "Draft") |
| 272 | +> - The tag exists in the repository (`git tag -l`) |
| 273 | +> - The source archive is available at the expected URL |
| 274 | + |
| 275 | +## References |
| 276 | + |
| 277 | +- [publish-to-bcr Documentation](https://github.com/bazel-contrib/publish-to-bcr) |
| 278 | +- [Bazel Central Registry](https://github.com/bazelbuild/bazel-central-registry) |
| 279 | +- [Bzlmod User Guide](https://bazel.build/docs/bzlmod) |
| 280 | +- [BCR Contribution Guidelines](https://github.com/bazelbuild/bazel-central-registry/blob/main/docs/README.md) |
| 281 | + |
| 282 | +## Support |
| 283 | + |
| 284 | +For issues related to: |
| 285 | +- **BCR publishing workflow**: Open an issue in [bazel-contrib/publish-to-bcr](https://github.com/bazel-contrib/publish-to-bcr/issues) |
| 286 | +- **BCR itself**: Open an issue in [bazelbuild/bazel-central-registry](https://github.com/bazelbuild/bazel-central-registry/issues) |
| 287 | +- **toolshed module**: Open an issue in [envoyproxy/toolshed](https://github.com/envoyproxy/toolshed/issues) |
0 commit comments