Skip to content

Commit 3ae6251

Browse files
committed
Add Go client release workflow
1 parent e272eee commit 3ae6251

7 files changed

Lines changed: 236 additions & 21 deletions

File tree

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
name: Release Go Client
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
test-go-client:
13+
name: Test Go client
14+
runs-on: ubuntu-latest
15+
permissions:
16+
contents: read
17+
18+
steps:
19+
- name: Checkout repository
20+
uses: actions/checkout@v4
21+
with:
22+
fetch-depth: 0
23+
24+
- name: Set up Go
25+
uses: actions/setup-go@v5
26+
with:
27+
go-version-file: go.mod
28+
cache: true
29+
30+
- name: Run Go client unit tests
31+
run: go test ./clients/go/sandbox/... -count=1
32+
33+
- name: Build Go client examples
34+
run: |
35+
go build ./clients/go/examples/basic
36+
go build ./clients/go/examples/gateway
37+
38+
publish-release-assets:
39+
name: Publish release assets
40+
needs: test-go-client
41+
runs-on: ubuntu-latest
42+
43+
steps:
44+
- name: Checkout repository
45+
uses: actions/checkout@v4
46+
with:
47+
fetch-depth: 0
48+
49+
- name: Set up Go
50+
uses: actions/setup-go@v5
51+
with:
52+
go-version-file: go.mod
53+
cache: true
54+
55+
- name: Set up GitHub CLI
56+
run: gh --version
57+
58+
- name: Generate and publish release assets
59+
env:
60+
GH_TOKEN: ${{ github.token }}
61+
run: |
62+
go mod tidy
63+
go generate ./...
64+
./dev/tools/release --tag=${GITHUB_REF_NAME} --publish
65+
66+
- name: Append Go client release summary
67+
run: |
68+
echo '### Go client release' >> "$GITHUB_STEP_SUMMARY"
69+
echo '- Validated `./clients/go/sandbox/...` unit tests.' >> "$GITHUB_STEP_SUMMARY"
70+
echo '- Built `clients/go/examples/basic` and `clients/go/examples/gateway`.' >> "$GITHUB_STEP_SUMMARY"
71+
echo '- Updated the draft GitHub release for tag `'"${GITHUB_REF_NAME}"'`.' >> "$GITHUB_STEP_SUMMARY"

Makefile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,13 @@ release-manifests:
8787
go generate ./...
8888
./dev/tools/release --tag=${TAG}
8989

90+
# Example usage:
91+
# make release-go-sdk TAG=v0.1.0
92+
.PHONY: release-go-sdk
93+
release-go-sdk:
94+
@if [ -z "$(TAG)" ]; then echo "TAG is required (e.g., make release-go-sdk TAG=vX.Y.Z)"; exit 1; fi
95+
./dev/tools/release-go --tag=${TAG} --remote=${REMOTE_UPSTREAM}
96+
9097
# Example usage:
9198
# make release-python-sdk TAG=v0.1.1rc1 (to release only on TestPyPI, blocked from PyPI in workflow)
9299
# make release-python-sdk TAG=v0.1.1.post1 (for patch release on TestPyPI and PyPI)
@@ -96,6 +103,7 @@ release-python-sdk:
96103
./dev/tools/release-python --tag=${TAG} --remote=${REMOTE_UPSTREAM}
97104

98105
.PHONY: toc-update
106+
99107
toc-update:
100108
./dev/tools/update-toc
101109

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,17 @@ kubectl apply -f https://github.com/kubernetes-sigs/agent-sandbox/releases/downl
9898
kubectl apply -f https://github.com/kubernetes-sigs/agent-sandbox/releases/download/${VERSION}/extensions.yaml
9999
```
100100

101+
### Go SDK
102+
103+
To interact with the agent-sandbox programmatically from Go, use the Go SDK:
104+
105+
```sh
106+
go get sigs.k8s.io/agent-sandbox/clients/go/sandbox@latest
107+
```
108+
109+
The Go SDK currently ships from the repository's root Go module, so repository release tags such as `v0.1.0` are also the Go SDK versions.
110+
For detailed installation and usage instructions, please refer to the [Go SDK README](clients/go/README.md).
111+
101112
### Python SDK
102113

103114
To interact with the agent-sandbox programmatically, you can use the Python SDK. This client library provides a high-level interface for creating and managing sandboxes.

RELEASE.md

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,47 @@
11
# Release Process
22

3-
The Kubernetes Template Project is released on an as-needed basis. The process is as follows:
3+
`agent-sandbox` uses repository-level semantic version tags (for example, `v0.1.0`).
4+
Those tags are the source of truth for:
45

5-
1. An issue is proposing a new release with a changelog since the last release
6-
1. All [OWNERS](OWNERS) must LGTM this release
7-
1. An OWNER runs `git tag -s $VERSION` and inserts the changelog and pushes the tag with `git push $VERSION`
8-
1. The release issue is closed
9-
1. An announcement email is sent to `dev@kubernetes.io` with the subject `[ANNOUNCE] kubernetes-template-project $VERSION is released`
6+
- Controller manifests published on GitHub Releases
7+
- The Go SDK at `sigs.k8s.io/agent-sandbox/clients/go/sandbox`
8+
- The Python SDK workflows that are triggered by `v*` tags
9+
10+
## Repository Release Flow
11+
12+
The project is released on an as-needed basis. The process is as follows:
13+
14+
1. An issue proposes a new release with a changelog since the last release.
15+
1. All [OWNERS](OWNERS) must LGTM the release.
16+
1. An OWNER promotes images and prepares release assets as needed.
17+
1. An OWNER pushes the repository tag for the release.
18+
1. GitHub Actions validates the Go SDK and publishes or updates the draft GitHub Release assets.
19+
1. The release issue is closed.
20+
1. An announcement email is sent to `dev@kubernetes.io` with the subject `[ANNOUNCE] agent-sandbox $VERSION is released`.
21+
22+
## Go SDK Releases
23+
24+
The Go SDK currently lives inside the repository's root Go module, so it does not have an independent module tag.
25+
To release the Go SDK, push the same repository tag that you want users to install:
26+
27+
```bash
28+
make release-go-sdk TAG=vX.Y.Z
29+
```
30+
31+
After the tag is pushed:
32+
33+
1. The `Release Go Client` workflow runs `go test ./clients/go/sandbox/...`.
34+
1. The workflow builds the example programs under `clients/go/examples/`.
35+
1. The workflow refreshes the draft GitHub Release for that tag.
36+
37+
Consumers can then install the SDK with:
38+
39+
```bash
40+
go get sigs.k8s.io/agent-sandbox/clients/go/sandbox@vX.Y.Z
41+
```
42+
43+
or track the latest repository release with:
44+
45+
```bash
46+
go get sigs.k8s.io/agent-sandbox/clients/go/sandbox@latest
47+
```

clients/go/README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,30 @@ The client operates in three modes:
3333
go get sigs.k8s.io/agent-sandbox/clients/go/sandbox
3434
```
3535

36+
## Versioning and Releases
37+
38+
The Go SDK is currently published from the repository's root Go module.
39+
That means repository tags such as `v0.1.0` are also the SDK versions for:
40+
41+
```bash
42+
go get sigs.k8s.io/agent-sandbox/clients/go/sandbox@v0.1.0
43+
```
44+
45+
To follow the most recent repository release, use:
46+
47+
```bash
48+
go get sigs.k8s.io/agent-sandbox/clients/go/sandbox@latest
49+
```
50+
51+
For maintainers, releasing the Go SDK means pushing a repository tag:
52+
53+
```bash
54+
make release-go-sdk TAG=vX.Y.Z
55+
```
56+
57+
That workflow validates `./clients/go/sandbox/...`, builds the Go examples,
58+
and refreshes the draft GitHub Release for the tag.
59+
3660
## Usage Examples
3761

3862
### 1. Production Mode (Gateway)

dev/tools/release

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,16 @@ def run_command(cmd):
2828
print(f"Error running command: {' '.join(cmd)}")
2929
sys.exit(1)
3030

31+
def release_exists(tag):
32+
"""Returns true when the GitHub release already exists."""
33+
result = subprocess.run(
34+
["gh", "release", "view", tag, "--repo", "kubernetes-sigs/agent-sandbox"],
35+
check=False,
36+
stdout=subprocess.DEVNULL,
37+
stderr=subprocess.DEVNULL,
38+
)
39+
return result.returncode == 0
40+
3141
def main():
3242
parser = argparse.ArgumentParser(description='Generate release manifests.')
3343
parser.add_argument('--tag', required=True, help='The git tag for the release.')
@@ -88,24 +98,32 @@ def main():
8898
print(f"INFO: Publishing draft release {tag} to GitHub...")
8999
manifest_path = "release_assets/manifest.yaml"
90100
extensions_path = "release_assets/extensions.yaml"
91-
101+
92102
if not os.path.exists(manifest_path) or not os.path.exists(extensions_path):
93103
print("❌ Release assets missing. Cannot publish.")
94104
sys.exit(1)
95-
96-
# Check if release exists, if so, we might want to fail or edit.
97-
# Here we assume creating a new one.
98-
cmd = [
99-
"gh", "release", "create", tag,
100-
manifest_path,
101-
extensions_path,
102-
"--generate-notes",
103-
"--title", tag,
104-
"--verify-tag",
105-
"--draft",
106-
"--repo", "kubernetes-sigs/agent-sandbox"
107-
]
108-
run_command(cmd)
105+
106+
if release_exists(tag):
107+
print(f"INFO: Release {tag} already exists; updating assets...")
108+
run_command([
109+
"gh", "release", "upload", tag,
110+
manifest_path,
111+
extensions_path,
112+
"--clobber",
113+
"--repo", "kubernetes-sigs/agent-sandbox",
114+
])
115+
else:
116+
117+
run_command([
118+
"gh", "release", "create", tag,
119+
manifest_path,
120+
extensions_path,
121+
"--generate-notes",
122+
"--title", tag,
123+
"--verify-tag",
124+
"--draft",
125+
"--repo", "kubernetes-sigs/agent-sandbox",
126+
])
109127
print(f"🎉 Draft release {tag} published successfully!")
110128
print(f"👉 Go to https://github.com/kubernetes-sigs/agent-sandbox/releases to review and publish.")
111129

dev/tools/release-go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#!/usr/bin/env python3
2+
# Copyright 2026 The Kubernetes Authors
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
import argparse
17+
18+
from shared.git_ops import validate_tag, check_tag_exists, check_local_repo_state, create_and_push_tag
19+
20+
def main():
21+
parser = argparse.ArgumentParser(description="Release Go Client.")
22+
parser.add_argument(
23+
"--tag", required=True, help="The version to tag (e.g. v0.1.0)."
24+
)
25+
parser.add_argument(
26+
"--remote",
27+
required=True,
28+
help="The remote to push the tag to. Values can be upstream or origin.",
29+
)
30+
31+
args = parser.parse_args()
32+
33+
remote = args.remote
34+
tag = args.tag
35+
36+
validate_tag(tag)
37+
check_local_repo_state(remote)
38+
check_tag_exists(tag, remote)
39+
create_and_push_tag(tag, remote=remote)
40+
41+
print("✅ Done! The Go client release workflow should now be running.")
42+
print("ℹ️ This repository uses a single root Go module, so the repository tag is also the Go SDK version.")
43+
44+
if __name__ == "__main__":
45+
main()

0 commit comments

Comments
 (0)