diff --git a/.bcr/source.template.json b/.bcr/source.template.json index 4f148199..902c2386 100644 --- a/.bcr/source.template.json +++ b/.bcr/source.template.json @@ -1,5 +1,5 @@ { "integrity": "", "strip_prefix": "{REPO}-{VERSION}", - "url": "https://github.com/{OWNER}/{REPO}/archive/refs/tags/{TAG}.tar.gz" + "url": "https://github.com/{OWNER}/{REPO}/releases/download/{TAG}/{REPO}-{VERSION}.tar.gz" } diff --git a/.github/workflows/create-release-draft.yaml b/.github/workflows/create-release-draft.yaml new file mode 100644 index 00000000..b5c48331 --- /dev/null +++ b/.github/workflows/create-release-draft.yaml @@ -0,0 +1,39 @@ +name: Create release draft + +on: + workflow_call: + inputs: + tag_name: + description: Tag to create a release for. + required: true + type: string + workflow_dispatch: + inputs: + tag_name: + description: Tag to create a release for. + required: true + type: string + push: + tags: + - v* + +jobs: + create-release-draft: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ github.event.inputs.tag_name || github.ref_name }} + - name: Create release tarball + run: .github/workflows/release_prep.sh ${{ github.event.inputs.tag_name || github.ref_name }} + - name: Release + uses: softprops/action-gh-release@v2 + with: + draft: true + tag_name: ${{ github.event.inputs.tag_name || github.ref_name }} + body_path: release_notes.md + generate_release_notes: true + files: | + protovalidate-*.tar.gz + diff --git a/.github/workflows/create-release-tag.yaml b/.github/workflows/create-release-tag.yaml new file mode 100644 index 00000000..18f58fb3 --- /dev/null +++ b/.github/workflows/create-release-tag.yaml @@ -0,0 +1,60 @@ +name: Create release tag + +on: + workflow_dispatch: + inputs: + tag_name: + description: 'Tag name for release (e.g. "v1.0.0")' + required: true + +permissions: + contents: write + +jobs: + create-release-tag: + name: Create release tag + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Create tag + uses: actions/github-script@v7 + with: + script: | + const tag = '${{ github.event.inputs.tag_name }}'; + const toolsTag = `tools/${tag}`; + const commitTag = await github.rest.git.createTag({ + owner: context.repo.owner, + repo: context.repo.repo, + tag, + message: tag, + object: context.sha, + type: 'commit', + }); + const toolsCommitTag = await github.rest.git.createTag({ + owner: context.repo.owner, + repo: context.repo.repo, + tag: toolsTag, + message: toolsTag, + object: context.sha, + type: 'commit', + }); + await github.rest.git.createRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: `refs/tags/${tag}`, + sha: commitTag.data.sha, + }); + await github.rest.git.createRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: `refs/tags/${toolsTag}`, + sha: toolsCommitTag.data.sha, + }); + + create-release-draft: + name: Start release automation + uses: ./.github/workflows/create-release-draft.yaml + with: + tag_name: ${{ github.event.inputs.tag_name }} diff --git a/.github/workflows/release_prep.sh b/.github/workflows/release_prep.sh new file mode 100755 index 00000000..de5f98bd --- /dev/null +++ b/.github/workflows/release_prep.sh @@ -0,0 +1,72 @@ +#!/bin/bash +set -x -e -u -o pipefail + +if [[ $# -ne 1 ]]; then + >&2 echo "Usage: ${0} " + exit 1 +fi + +NAME="protovalidate" +TAG="${1}" +PREFIX="${NAME}-${TAG:1}" +ARCHIVE="${PREFIX}.tar.gz" + +# Update MODULE.bazel version +>&2 echo "# Update MODULE.bazel version to ${TAG:1}" +if ! awk -v tag="${TAG:1}" ' + sub(/version = "0\.0\.0",/, "version = \"" tag "\",") { + count++; + } + { print; } + END { + if (count != 1) { + exit 1; + } + } +' MODULE.bazel > MODULE.bazel.tmp; then + >&2 echo "Failed to update MODULE.bazel version!" + rm MODULE.bazel.tmp + exit 1 +fi + +mv MODULE.bazel.tmp MODULE.bazel +>&2 echo "MODULE.bazel contents:" +cat MODULE.bazel + +# Create release archive +>&2 echo "# Create release archive ${ARCHIVE}" +git archive \ + --prefix="${PREFIX}/" \ + --output="${ARCHIVE}" \ + "$(git stash create)" + +>&2 echo "Release archive ${ARCHIVE} contents:" +tar tvf "${ARCHIVE}" + +# Calculate SHA256 sum for WORKSPACE code +SHA256=$(shasum -a 256 "${ARCHIVE}" | awk '{print $1}') + +# Generate release notes snippets +>&2 echo "# Generate release notes snippets" +> release_notes.md cat << EOF +## \`MODULE.bazel\` Usage +\`\`\`bzl +bazel_dep(name = "protovalidate", version = "${TAG:1}") +\`\`\` + +## \`WORKSPACE\` Usage +\`\`\`bzl +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +http_archive( + name = "com_github_bufbuild_protovalidate", + sha256 = "${SHA256}", + strip_prefix = "${PREFIX}", + urls = [ + "https://github.com/bufbuild/protovalidate/releases/download/${TAG}/protovalidate-${TAG}.tar.gz", + ], +) +\`\`\` +EOF + +>&2 echo "Success." diff --git a/.gitignore b/.gitignore index 16665399..0149aacc 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ *.svg cover.out /bazel-* +/protovalidate-*.tar.gz +/release_notes.md diff --git a/MODULE.bazel b/MODULE.bazel index 5d11c679..82945724 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -14,7 +14,7 @@ module( name = "protovalidate", - version = "0.10.0", + version = "0.0.0", repo_name = "com_github_bufbuild_protovalidate", ) diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 351ca90f..d87b6b74 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -441,7 +441,7 @@ "@@rules_buf+//buf:extensions.bzl%buf": { "general": { "bzlTransitiveDigest": "Cn52bY/1OxGKNv4TI5yExj2vL9hBgfRj4HOOcjWQTdQ=", - "usagesDigest": "kgkTda36TM0OQAZD9IGhUdFyy7Q94+znktf/Uhw8RKM=", + "usagesDigest": "DNyLeXiz76KXJ1VlWq1b3zhuLWpJNMllrMF6Fo6iD90=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, diff --git a/RELEASING.md b/RELEASING.md new file mode 100644 index 00000000..b5ab649c --- /dev/null +++ b/RELEASING.md @@ -0,0 +1,83 @@ +# Releasing protovalidate + +The protovalidate repository contains two Go modules, and a Bazel module with +Bzlmod and WORKSPACE support, which is pushed to the Bazel Central Repository. +Proper release process is necessary to ensure that a protovalidate release is +usable in all of these forms. + +Most of the protovalidate release process is automated, but in the event that +automation can not be utilized, the manual steps are also included in the +collapsed sections below. + +1. **Run the [create release tag] workflow.** + + Go to the [create release tag] workflow page and select Run workflow, + with the desired version tag (e.g. `v1.2.3`). + +
+ + What this workflow does + + This will create two release tags for the latest `main` revision: + + - `v1.2.3`: For Bazel, BCR, Go main module, etc. + - `tools/v1.2.3`: For the Go tools module + + These tags can also be created manually. Pushing the `v1.2.3` tag should + trigger the remaining release automation. Do not forget to create both tags + in the event of manually cutting a release. + + Note that this workflow creates tags directly on GitHub instead of pushing + tags up, so it will not indirectly trigger the draft release automation in + that way. Instead, a workflow call is used. So, the creat release draft + workflow will appear nested under the create release tag workflow as a step. + +
+ +1. **Find the draft release.** + + Upon either pushing a release tag or running the previous workflow, a + release draft should be created. Check for it in the [releases page]. + + If for some reason this doesn't happen, it is possible to directly trigger + the workflow by going to the [create release draft] action and selecting + Run workflow. + +
+ + Manually creating a release draft + + To manually create a release draft, run `.github/workflows/release_prep.sh` + with the version tag (e.g. `vX.Y.Z`) as an argument, while checked out to + the release tag/commit: + + ``` + .github/workflows/release_prep.sh v1.2.3 + ``` + + This will create two files: + + - `release_notes.md`: This should be prepended to the GitHub-generated + release notes. It contains instructions on how to include the repo with + Bazel. + - `protovalidate-1.2.3.tar.gz`: This should be attached to the release. It + includes a stable tarball of the release commit for Bazel. + +
+ +1. **Publish the release.** + + Once the release draft is created, edit it as needed, prepending any + important notes (e.g. breaking changes), and finally, publish it. + +1. **Check [Bazel Central Registry repository] for a pull request.** + + Shortly after publishing the release, the [Publish to BCR] app should've + created a new pull request. There may be failures in CI that need to be + addressed. + +[create release tag]: https://github.com/bufbuild/protovalidate/actions/workflows/create-release-tag.yaml +[create release draft]: https://github.com/bufbuild/protovalidate/actions/workflows/create-release-draft.yaml +[releases page]: https://github.com/bufbuild/protovalidate/releases +[Bazel Central Registry repository]: https://github.com/bazelbuild/bazel-central-registry/pulls +[Publish to BCR]: https://github.com/apps/publish-to-bcr \ No newline at end of file