From 7b017bb42ab49e5e9817feaa7313cce072f2da12 Mon Sep 17 00:00:00 2001 From: Bartosz Blizniak Date: Wed, 19 Aug 2026 17:06:11 +0100 Subject: [PATCH 1/2] add automated release to allow e2e automation --- .github/workflows/release.yml | 93 +++++++++++++++++++++++++++++++++++ CONTRIBUTING.MD | 7 ++- scripts/update-bindings.sh | 20 ++------ 3 files changed, 102 insertions(+), 18 deletions(-) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..cb6b1a39 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,93 @@ +name: Release + +on: + push: + branches: + - master + workflow_dispatch: + +permissions: {} + +concurrency: + group: github-release + cancel-in-progress: false + +jobs: + release: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + fetch-depth: 0 + + - name: Set up tools + uses: jdx/mise-action@e6a8b3978addb5a52f2b4cd9d91eafa7f0ab959d # v4.2.0 + + - name: Resolve binding version + id: version + run: | + set -euo pipefail + version=$(grep -oE '"[0-9]+\.[0-9]+\.[0-9]+"' bin/generate | head -1 | tr -d '"') + if [ -z "$version" ]; then + echo "Could not parse PKG_VERSION from bin/generate" >&2 + exit 1 + fi + tag="v${version}" + echo "version=${version}" >> "$GITHUB_OUTPUT" + echo "tag=${tag}" >> "$GITHUB_OUTPUT" + + - name: Skip if this version is already released + id: existing + env: + GH_TOKEN: ${{ github.token }} + TAG: ${{ steps.version.outputs.tag }} + run: | + set -euo pipefail + if gh release view "$TAG" >/dev/null 2>&1; then + echo "exists=true" >> "$GITHUB_OUTPUT" + echo "GitHub release ${TAG} already exists; nothing to do." + exit 0 + fi + if gh api "repos/${GITHUB_REPOSITORY}/git/ref/tags/${TAG}" >/dev/null 2>&1; then + echo "exists=tag-only" >> "$GITHUB_OUTPUT" + echo "Tag ${TAG} exists without a GitHub release; will attach one." + exit 0 + fi + echo "exists=false" >> "$GITHUB_OUTPUT" + + - name: Test + if: steps.existing.outputs.exists != 'true' + run: go test -v ./... + + - name: Create GitHub release + if: steps.existing.outputs.exists != 'true' + env: + GH_TOKEN: ${{ github.token }} + TAG: ${{ steps.version.outputs.tag }} + VERSION: ${{ steps.version.outputs.version }} + EXISTS: ${{ steps.existing.outputs.exists }} + run: | + set -euo pipefail + api_version=$(grep -m1 -E '^\- API version:' README.md | awk '{print $4}' || true) + notes="Go API bindings ${TAG}." + notes="${notes}"$'\n\n'"- Binding version: \`${VERSION}\`" + if [ -n "${api_version:-}" ]; then + notes="${notes}"$'\n'"- CloudSmith API version: \`${api_version}\`" + fi + + extra=() + if [ "$EXISTS" = "tag-only" ]; then + extra+=(--verify-tag) + else + extra+=(--target "${GITHUB_SHA}") + fi + + gh release create "$TAG" \ + --title "$TAG" \ + --notes "$notes" \ + --generate-notes \ + "${extra[@]}" diff --git a/CONTRIBUTING.MD b/CONTRIBUTING.MD index 9c49a39b..965bb0f7 100644 --- a/CONTRIBUTING.MD +++ b/CONTRIBUTING.MD @@ -23,7 +23,7 @@ Convenience tasks: * Update `PKG_VERSION` in `bin/generate` * Run `bin/generate` (or `mise run generate`) to generate bindings * Create a PR specifing API and binding version -* Create git tag and release in github +* After merge, the **Release** workflow tags `v$PKG_VERSION` and creates the GitHub release when that tag does not already exist ### Automated approach (local) @@ -31,7 +31,7 @@ Convenience tasks: * This will then provide you with the URL for the PR to release the updated bindings. * Preferred usage: `./scripts/update-bindings.sh` * For full options and usage examples, run: `./scripts/update-bindings.sh --help` -* After PR is merged, follow the displayed instructions to create the git tag and GitHub release. +* After the PR is merged, the **Release** workflow creates the git tag and GitHub release. ### Automated approach (CI) @@ -39,6 +39,9 @@ Convenience tasks: and opens a PR — on demand (`workflow_dispatch`, optionally with a specific version) or daily on a schedule. It opens a PR only when the regenerated bindings actually change, and closes any superseded automated PRs first. +* The **Release** workflow runs on every push to `master`. It reads + `PKG_VERSION` from `bin/generate`, runs tests, and creates `v$PKG_VERSION` + plus a GitHub release when that version is not already published. ## Contributor License Agreement diff --git a/scripts/update-bindings.sh b/scripts/update-bindings.sh index efae5975..6707c0ca 100755 --- a/scripts/update-bindings.sh +++ b/scripts/update-bindings.sh @@ -205,22 +205,10 @@ Cloudsmith API version: $api_version create_tag_and_release_instructions() { local version="$1" local tag_name="v${version}" - - echo "" - log_info "After the PR is merged, create a git tag and release:" - echo "" - echo "1. Switch to master and pull latest changes:" - echo " git checkout master" - echo " git pull" - echo "" - echo "2. Create and push the tag:" - echo " git tag -a $tag_name -m \"Release version $version\"" - echo " git push origin $tag_name" + echo "" - echo "3. Go to GitHub releases page and create a new release:" - echo " - Select tag: $tag_name" - echo " - Release title: Release $version" - echo " - Add release notes as needed" + log_info "After the PR is merged, the Release workflow publishes ${tag_name}." + echo "If that run is skipped or fails, re-run the Release workflow from Actions." echo "" } @@ -244,7 +232,7 @@ usage() { echo " * Auto-increment the patch version (e.g. 1.2.3 -> 1.2.4)" echo " * Auto-fetch the latest Cloudsmith API version" echo " - Use -v only for larger version increments (minor/major bumps)" - echo " - After PR is merged, you'll need to create a git tag and GitHub release" + echo " - After the PR is merged, the Release workflow creates the git tag and GitHub release" } main() { From 89066d301dd805c7c31982d9d0575e7cd05879e5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 19 Aug 2026 19:55:02 +0000 Subject: [PATCH 2/2] Address review: robust PKG_VERSION parse, tag checkout before tests, casing/spelling fixes Co-authored-by: BartoszBlizniak <55028730+BartoszBlizniak@users.noreply.github.com> --- .github/workflows/release.yml | 13 +++++++++++-- CONTRIBUTING.MD | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cb6b1a39..bedd7995 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -31,7 +31,7 @@ jobs: id: version run: | set -euo pipefail - version=$(grep -oE '"[0-9]+\.[0-9]+\.[0-9]+"' bin/generate | head -1 | tr -d '"') + version=$(sed -n 's/^PKG_VERSION=\${1:-"\([0-9]\+\.[0-9]\+\.[0-9]\+\)"}.*/\1/p' bin/generate | head -1 || true) if [ -z "$version" ]; then echo "Could not parse PKG_VERSION from bin/generate" >&2 exit 1 @@ -59,6 +59,15 @@ jobs: fi echo "exists=false" >> "$GITHUB_OUTPUT" + - name: Check out existing tag + if: steps.existing.outputs.exists == 'tag-only' + env: + TAG: ${{ steps.version.outputs.tag }} + run: | + set -euo pipefail + git fetch --no-tags origin "refs/tags/${TAG}:refs/tags/${TAG}" || true + git checkout --detach "refs/tags/${TAG}" + - name: Test if: steps.existing.outputs.exists != 'true' run: go test -v ./... @@ -76,7 +85,7 @@ jobs: notes="Go API bindings ${TAG}." notes="${notes}"$'\n\n'"- Binding version: \`${VERSION}\`" if [ -n "${api_version:-}" ]; then - notes="${notes}"$'\n'"- CloudSmith API version: \`${api_version}\`" + notes="${notes}"$'\n'"- Cloudsmith API version: \`${api_version}\`" fi extra=() diff --git a/CONTRIBUTING.MD b/CONTRIBUTING.MD index 965bb0f7..41f276eb 100644 --- a/CONTRIBUTING.MD +++ b/CONTRIBUTING.MD @@ -22,7 +22,7 @@ Convenience tasks: * Update `PKG_VERSION` in `bin/generate` * Run `bin/generate` (or `mise run generate`) to generate bindings -* Create a PR specifing API and binding version +* Create a PR specifying API and binding version * After merge, the **Release** workflow tags `v$PKG_VERSION` and creates the GitHub release when that tag does not already exist ### Automated approach (local)