Skip to content

Commit 5c315a8

Browse files
committed
Add BCR publishing workflow for envoy_toolshed module
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
1 parent 929174c commit 5c315a8

3 files changed

Lines changed: 335 additions & 2 deletions

File tree

.bcr/README.md

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
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)

.bcr/bazel/source.template.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"integrity": "",
3-
"strip_prefix": "{REPO}-{VERSION}/bazel",
4-
"url": "https://github.com/{OWNER}/{REPO}/archive/refs/tags/bazel-v{TAG}.tar.gz"
3+
"strip_prefix": "{REPO}-{TAG}/bazel",
4+
"url": "https://github.com/{OWNER}/{REPO}/archive/refs/tags/{TAG}.tar.gz"
55
}

.github/workflows/publish.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: Publish to BCR
2+
3+
# This workflow publishes the envoy_toolshed module to the Bazel Central Registry (BCR).
4+
# It is triggered when a GitHub Release is published with a tag matching 'bazel-v*'.
5+
# The workflow creates a pull request against https://github.com/bazelbuild/bazel-central-registry
6+
# using the templates defined in the .bcr directory.
7+
8+
on:
9+
# Triggered when a release is published with a tag matching 'bazel-v*' pattern
10+
release:
11+
types:
12+
- published
13+
# Allow manual trigger for republishing or testing
14+
workflow_dispatch:
15+
inputs:
16+
tag_name:
17+
required: true
18+
type: string
19+
description: "The git tag identifying the release to publish (e.g., bazel-v0.3.11)"
20+
21+
jobs:
22+
publish:
23+
# Only run for releases with tags matching 'bazel-v*' pattern (e.g., bazel-v0.3.10, bazel-v1.2.3)
24+
if: github.event_name == 'workflow_dispatch' || startsWith(github.event.release.tag_name, 'bazel-v')
25+
uses: bazel-contrib/publish-to-bcr/.github/workflows/publish.yaml@v6
26+
with:
27+
tag_name: ${{ github.event_name == 'workflow_dispatch' && inputs.tag_name || github.event.release.tag_name }}
28+
# The BCR fork must be created manually - see .bcr/README.md for setup instructions
29+
# This should be a fork of bazelbuild/bazel-central-registry in the envoyproxy organization
30+
registry_fork: envoyproxy/bazel-central-registry
31+
# Open the PR directly to the upstream BCR
32+
registry: bazelbuild/bazel-central-registry
33+
# Use tag prefix 'bazel-v' to extract version from tags like 'bazel-v0.3.11'
34+
tag_prefix: "bazel-v"
35+
# Open PRs as draft by default - maintainers can mark as ready for review
36+
draft: true
37+
# Enable attestations for enhanced security
38+
attest: true
39+
permissions:
40+
contents: write # Needed to upload attestation files to the release
41+
id-token: write # Needed to generate attestations
42+
attestations: write # Needed to publish attestations
43+
secrets:
44+
# This PAT must be created and added as a repository secret
45+
# See .bcr/README.md for instructions on creating the token
46+
publish_token: ${{ secrets.BCR_PUBLISH_TOKEN }}

0 commit comments

Comments
 (0)