mirror of
https://github.com/vmware-tanzu/velero.git
synced 2025-12-23 14:25:22 +00:00
Add scripts for tagging Velero releases (#2592)
* Add release tools Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Document the tag-release release tool Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Make sure the upstream used is correct Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Add copyright statement Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Address review feedback * Pause to allow for cherry-picking on the release branch before pushing it * Move master branch logic into an else statement * Correct typo Signed-off-by: Nolan Brubaker <brubakern@vmware.com> * Uncomment check for dirty git working tree Signed-off-by: Nolan Brubaker <brubakern@vmware.com>
This commit is contained in:
75
hack/release-tools/chk_version.go
Normal file
75
hack/release-tools/chk_version.go
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 the Velero contributors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This regex should match both our GA format (example: v1.4.3) and pre-release format (v1.2.4-beta.2)
|
||||||
|
// The following sub-capture groups are defined:
|
||||||
|
// major
|
||||||
|
// minor
|
||||||
|
// patch
|
||||||
|
// prerelease (this will be alpha/beta followed by a ".", followed by 1 or more digits (alpha.5)
|
||||||
|
var release_regex *regexp.Regexp = regexp.MustCompile("^v(?P<major>[[:digit:]]+)\\.(?P<minor>[[:digit:]]+)\\.(?P<patch>[[:digit:]]+)(-{1}(?P<prerelease>(alpha|beta)\\.[[:digit:]]+))*")
|
||||||
|
|
||||||
|
// This small program exists because checking the VELERO_VERSION rules in bash is difficult, and difficult to test for correctness.
|
||||||
|
// Calling it with --verify will verify whether or not the VELERO_VERSION environment variable is a valid version string, without parsing for its components.
|
||||||
|
// Calling it without --verify will try to parse the version into its component pieces.
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
velero_version := os.Getenv("VELERO_VERSION")
|
||||||
|
|
||||||
|
submatches := reSubMatchMap(release_regex, velero_version)
|
||||||
|
|
||||||
|
// Didn't match the regex, exit.
|
||||||
|
if len(submatches) == 0 {
|
||||||
|
fmt.Printf("VELERO_VERSION of %s was not valid. Please correct the value and retry.", velero_version)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(os.Args) > 1 && os.Args[1] == "--verify" {
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send these in a bash variable format to stdout, so that they can be consumed by bash scripts that call the go program.
|
||||||
|
fmt.Printf("VELERO_MAJOR=%s\n", submatches["major"])
|
||||||
|
fmt.Printf("VELERO_MINOR=%s\n", submatches["minor"])
|
||||||
|
fmt.Printf("VELERO_PATCH=%s\n", submatches["patch"])
|
||||||
|
fmt.Printf("VELERO_PRERELEASE=%s\n", submatches["prerelease"])
|
||||||
|
}
|
||||||
|
|
||||||
|
// reSubMatchMap returns a map with the named submatches within a regular expression populated as keys, and their matched values within a given string as values.
|
||||||
|
// If no matches are found, a nil map is returned
|
||||||
|
func reSubMatchMap(r *regexp.Regexp, s string) map[string]string {
|
||||||
|
match := r.FindStringSubmatch(s)
|
||||||
|
submatches := make(map[string]string)
|
||||||
|
if len(match) == 0 {
|
||||||
|
return submatches
|
||||||
|
}
|
||||||
|
for i, name := range r.SubexpNames() {
|
||||||
|
// 0 will always be empty from the return values of SubexpNames's documentation, so skip it.
|
||||||
|
if i != 0 {
|
||||||
|
submatches[name] = match[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return submatches
|
||||||
|
}
|
||||||
71
hack/release-tools/chk_version_test.go
Normal file
71
hack/release-tools/chk_version_test.go
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 the Velero contributors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRegexMatching(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
version string
|
||||||
|
expectMatch bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
version: "v1.4.0",
|
||||||
|
expectMatch: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
version: "v2.0.0",
|
||||||
|
expectMatch: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
version: "v1.5.0-alpha.1",
|
||||||
|
expectMatch: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
version: "v1.16.1320-beta.14",
|
||||||
|
expectMatch: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
version: "1.0.0",
|
||||||
|
expectMatch: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// this is true because while the "--" is invalid, v1.0.0 is a valid part of the regex
|
||||||
|
version: "v1.0.0--beta.1",
|
||||||
|
expectMatch: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
name := fmt.Sprintf("Testing version string %s", test.version)
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
results := reSubMatchMap(release_regex, test.version)
|
||||||
|
|
||||||
|
if len(results) == 0 && test.expectMatch {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(results) > 0 && !test.expectMatch {
|
||||||
|
fmt.Printf("%v", results)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
118
hack/release-tools/tag-release.sh
Executable file
118
hack/release-tools/tag-release.sh
Executable file
@@ -0,0 +1,118 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Copyright 2020 the Velero contributors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
|
||||||
|
# This script will do the necessary checks and actions to create a release of Velero.
|
||||||
|
# It will first validate that all prerequisites are met, then verify the version string is what the user expects.
|
||||||
|
# A git tag will be created and pushed to GitHub, and GoReleaser will be invoked.
|
||||||
|
|
||||||
|
# This script is meant to be a combination of documentation and executable.
|
||||||
|
# If you have questions at any point, please stop and ask!
|
||||||
|
|
||||||
|
# Directory in which the script itself resides, so we can use it for calling programs that are in the same directory.
|
||||||
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||||
|
|
||||||
|
function tag_and_push() {
|
||||||
|
echo "Tagging and pushing $VELERO_VERSION"
|
||||||
|
git tag $VELERO_VERSION
|
||||||
|
git push $VELERO_VERSION
|
||||||
|
}
|
||||||
|
|
||||||
|
# For now, have the person doing the release pass in the VELERO_VERSION variable as an environment variable.
|
||||||
|
# In the future, we might be able to inspect git via `git describe --abbrev=0` to get a hint for it.
|
||||||
|
if [[ -z "$VELERO_VERSION" ]]; then
|
||||||
|
printf "The \$VELERO_VERSION environment variable is not set. Please set it with\n\texport VELERO_VERSION=v<version.to.release>\nthen try again."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Make sure the user's provided their github token, so we can give it to goreleaser.
|
||||||
|
if [[ -z "$GITHUB_TOKEN" ]]; then
|
||||||
|
printf "The GITHUB_TOKEN environment variable is not set. Please set it with\n\t export GITHUB_TOKEN=<your github token>\n then try again."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
Ensure that we have a clean working tree before we let any changes happen, especially important for cutting release branches.
|
||||||
|
if [[ -n $(git status --short) ]]; then
|
||||||
|
echo "Your git working directory is dirty! Please clean up untracked files and stash any changes before proceeding."
|
||||||
|
exit 3
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Make sure that there's no issue with the environment variable's format before trying to eval the parsed version.
|
||||||
|
if ! go run $DIR/chk_version.go --verify; then
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
# Since we're past the validation of the VELERO_VERSION, parse the version's individual components.
|
||||||
|
eval $(go run $DIR/chk_version.go)
|
||||||
|
|
||||||
|
|
||||||
|
printf "To clarify, you've provided a version string of $VELERO_VERSION.\n"
|
||||||
|
printf "Based on this, the following assumptions have been made: \n"
|
||||||
|
|
||||||
|
[[ "$VELERO_PATCH" != 0 ]] && printf "*\t This is a patch release.\n"
|
||||||
|
|
||||||
|
# -n is "string is non-empty"
|
||||||
|
[[ -n $VELERO_PRERELEASE ]] && printf "*\t This is a pre-release.\n"
|
||||||
|
|
||||||
|
# -z is "string is empty"
|
||||||
|
[[ -z $VELERO_PRERELEASE ]] && printf "*\t This is a GA release.\n"
|
||||||
|
|
||||||
|
echo "If this is all correct, press enter/return to proceed to TAG THE RELEASE and UPLOAD THE TAG TO GITHUB."
|
||||||
|
echo "Otherwise, press ctrl-c to CANCEL the process without making any changes."
|
||||||
|
|
||||||
|
read -p "Ready to continue? "
|
||||||
|
|
||||||
|
echo "Alright, let's go."
|
||||||
|
|
||||||
|
echo "Pulling down all git tags and branches before doing any work."
|
||||||
|
git fetch upstream --all --tags
|
||||||
|
|
||||||
|
# If we've got a patch release, we'll need to create a release branch for it.
|
||||||
|
if [[ "$VELERO_PATCH" > 0 ]]; then
|
||||||
|
release_branch_name=release-$VELERO_MAJOR.$VELERO_MINOR
|
||||||
|
|
||||||
|
# Check if the branch exists, creating it if not.
|
||||||
|
# The fetch command above should have gotten all the upstream branches, so we can safely assume this check is local & upstream branches.
|
||||||
|
if [[ -z $(git branch | grep $release_branch_name) ]]; then
|
||||||
|
git checkout -b $release_branch_name
|
||||||
|
echo "Release branch made."
|
||||||
|
else
|
||||||
|
echo "Release branch $release_branch_name exists already."
|
||||||
|
git checkout $release_branch_name
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Now you'll need to cherry-pick any relevant git commits into this release branch."
|
||||||
|
echo "Either pause this script with ctrl-z, or open a new terminal window and do the cherry-picking."
|
||||||
|
read -p "Press enter when you're done cherry-picking. THIS WILL MAKE A TAG PUSH THE BRANCH TO UPSTREAM"
|
||||||
|
|
||||||
|
# TODO can/should we add a way to review the cherry-picked commits before the push?
|
||||||
|
|
||||||
|
echo "Pushing $release_branch_name to upstream remote"
|
||||||
|
git push --set-upstream upstream/$release_branch_name $release_branch_name
|
||||||
|
|
||||||
|
tag_and_push
|
||||||
|
else
|
||||||
|
echo "Checking out upstream/master."
|
||||||
|
git checkout upstream/master
|
||||||
|
|
||||||
|
tag_and_push
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
echo "Invoking Goreleaser to create the GitHub release."
|
||||||
|
RELEASE_NOTES_FILE=changelogs/CHANGELOG-$VELERO_MAJOR.$VELERO_MINOR.md \
|
||||||
|
PUBLISH=TRUE \
|
||||||
|
make release
|
||||||
@@ -54,18 +54,8 @@ You may regenerate the token for every release if you prefer.
|
|||||||
This process is the same for both pre-release and GA, except for the fact that there will not be a blog post PR to merge for pre-release versions.
|
This process is the same for both pre-release and GA, except for the fact that there will not be a blog post PR to merge for pre-release versions.
|
||||||
|
|
||||||
1. Merge the changelog + docs PR, so that it's included in the release tag.
|
1. Merge the changelog + docs PR, so that it's included in the release tag.
|
||||||
1. Make sure your working directory is clean: `git status` should show `nothing to commit, working tree clean`.
|
1. Set your GitHub token as an environment variable. `export GITHUB_TOKEN=<your token value>`
|
||||||
1. Run `git fetch upstream master && git checkout upstream/master`.
|
1. Run `/hack/release-tools/tag-release.sh` and follow the instructions.
|
||||||
1. Run `git tag $VELERO_VERSION (e.g. `git tag v1.2.0` or `git tag v1.2.0-beta.1`).
|
|
||||||
1. Run `git push upstream $VELERO_VERSION` (e.g. `git push upstream v1.2.0` or `git push upstream v1.2.0-beta.1`). This will trigger the github action that builds/publishes the Docker images.
|
|
||||||
1. Generate the GitHub release (it will be created in "Draft" status, which means it's not visible to the outside world until you click "Publish"):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
GITHUB_TOKEN=your-github-token \
|
|
||||||
RELEASE_NOTES_FILE=changelogs/CHANGELOG-<major>.<minor>.md \
|
|
||||||
PUBLISH=true \
|
|
||||||
make release
|
|
||||||
```
|
|
||||||
|
|
||||||
1. Navigate to the draft GitHub release, at https://github.com/vmware-tanzu/velero/releases.
|
1. Navigate to the draft GitHub release, at https://github.com/vmware-tanzu/velero/releases.
|
||||||
1. If this is a patch release (e.g. `v1.2.1`), note that the full `CHANGELOG-1.2.md` contents will be included in the body of the GitHub release. You need to delete the previous releases' content (e.g. `v1.2.0`'s changelog) so that only the latest patch release's changelog shows.
|
1. If this is a patch release (e.g. `v1.2.1`), note that the full `CHANGELOG-1.2.md` contents will be included in the body of the GitHub release. You need to delete the previous releases' content (e.g. `v1.2.0`'s changelog) so that only the latest patch release's changelog shows.
|
||||||
|
|||||||
Reference in New Issue
Block a user