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>pull/2320/head
parent
695715ff6a
commit
c8f4b60b5b
|
@ -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
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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.
|
||||
|
||||
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. Run `git fetch upstream master && git checkout upstream/master`.
|
||||
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. Set your GitHub token as an environment variable. `export GITHUB_TOKEN=<your token value>`
|
||||
1. Run `/hack/release-tools/tag-release.sh` and follow the instructions.
|
||||
|
||||
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.
|
||||
|
|
Loading…
Reference in New Issue