Skip to content

Commit fc509ce

Browse files
committed
add a release script
1 parent 6b01c95 commit fc509ce

File tree

5 files changed

+232
-25
lines changed

5 files changed

+232
-25
lines changed

scripts/apply-hotfixes.sh

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,6 @@ then
2424
exit 1
2525
fi
2626

27-
# Check if the current branch is a release branch (release-*)
28-
# If it is not a release branch, don't let the patch be applied
29-
GIT_BRANCH=$(git branch | sed -n -e 's/^\* \(.*\)/\1/p')
30-
if ! [[ $GIT_BRANCH =~ .*release-.* ]]; then
31-
echo Current branch: $GIT_BRANCH
32-
echo You are not in a release branch, e.g., release-11.0, release-10.0
33-
echo Please switch to a release branch to run this script.
34-
exit 1
35-
fi
36-
3727
# Patching commit for custom client behavior
3828
# UPDATE: The commit being cherry-picked is updated since the the client generated in 1adaaecd0879d7315f48259ad8d6cbd66b835385
3929
# differs from the initial hotfix

scripts/release.sh

Lines changed: 124 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,126 @@
1-
# This file is intended to document release steps.
2-
# Verify each step's result before calling the next command.
3-
# It is documented here with the intention of being automated
4-
# as a shell script later.
1+
#!/bin/bash
52

6-
echo 'git clean -xdf'
7-
echo 'python setup.py sdist'
8-
echo 'python setup.py bdist_wheel --universal'
9-
echo 'twine upload dist/* -r https://upload.pypi.org/legacy/ -u kubernetes'
3+
# Copyright 2021 The Kubernetes Authors.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
1016

17+
# Workflow
18+
# 1. [master branch] update existing snapshot (include API change for a new alpha/beta/GA
19+
# release)
20+
# - add a new snapshot or reuse the existing snapshot, the latter means either
21+
# API change happened in a k8s patch release, or we want to include some new
22+
# python / python-base change in the release note
23+
# - API change w/ release notes
24+
# - master change w/ release notes
25+
# - submodule change w/ release notes
26+
# 2. [master branch] create new snapshot (include API change for a new alpha release)
27+
# - add a new snapshot or reuse the existing snapshot, the latter means either
28+
# API change happened in a k8s patch release, or we want to include some new
29+
# python / python-base change in the release note
30+
# - API change w/ release notes
31+
# - master change w/ release notes
32+
# - submodule change w/ release notes
33+
# 3. [release branch] create a new release
34+
# - pull master
35+
# - it's possible that master has new changes after the latest snaphost,
36+
# update CHANGELOG accordingly
37+
# - for generated file, resolve conflict by committing the master version
38+
# - abort if a snapshot doesn't exists
39+
# - generate client change, abort if API change is detected
40+
# - CHANGELOG: latest snapshot becomes the release, create a new snapshot
41+
# section that reflect the master branch state
42+
# - README: add the release to README
43+
# - an extra PR to update CHANGELOG and README in master in sync with this new
44+
# release
45+
#
46+
# Difference between 1&2: API change release notes
47+
#
48+
# TODO(roycaihw):
49+
# - add user input validation
50+
# - add function input validaiton (release/version strings start with 'v' or not)
51+
# - automatically send a PR; provide useful links for review
52+
# - master branch diff: https://github.com/kubernetes-client/python/compare/commit1..commit2
53+
# - python base diff: https://github.com/kubernetes-client/python-base/compare/commit1..commit2
54+
# - Kubernetes changelog, e.g. https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.18.md
55+
# - add debug log
56+
# - add a sentence about "changes since {last release}". In most cases our
57+
# releases should be sequential. This script (the workflow above) is based on
58+
# this assumption, and we should make the release note clear about that.
59+
#
60+
# Usage:
61+
62+
set -o errexit
63+
set -o nounset
64+
set -o pipefail
65+
66+
repo_root="$(git rev-parse --show-toplevel)"
67+
declare -r repo_root
68+
cd "${repo_root}"
69+
70+
source scripts/util/changelog.sh
71+
source scripts/util/kube_changelog.sh
72+
73+
old_client_version=$(python3 "scripts/constants.py" CLIENT_VERSION)
74+
old_k8s_api_version=$(util::changelog::get_k8s_api_version "v$old_client_version")
75+
KUBERNETES_BRANCH=${KUBERNETES_BRANCH:-$(python3 "scripts/constants.py" KUBERNETES_BRANCH)}
76+
CLIENT_VERSION=${CLIENT_VERSION:-$(python3 "scripts/constants.py" CLIENT_VERSION)}
77+
DEVELOPMENT_STATUS=${DEVELOPMENT_STATUS:-$(python3 "scripts/constants.py" DEVELOPMENT_STATUS)}
78+
79+
# get Kubernetes API Version
80+
new_k8s_api_version=$(util::kube_changelog::find_latest_patch_version $KUBERNETES_BRANCH)
81+
echo "Old Kubernetes API Version: $old_k8s_api_version"
82+
echo "New Kubernetes API Version: $new_k8s_api_version"
83+
84+
sed -i "s/^KUBERNETES_BRANCH =.*$/KUBERNETES_BRANCH = \"$KUBERNETES_BRANCH\"/g" scripts/constants.py
85+
sed -i "s/^CLIENT_VERSION =.*$/CLIENT_VERSION = \"$CLIENT_VERSION\"/g" scripts/constants.py
86+
sed -i "s/^DEVELOPMENT_STATUS =.*$/DEVELOPMENT_STATUS = \"$DEVELOPMENT_STATUS\"/g" scripts/constants.py
87+
git commit -am "update version constants for $CLIENT_VERSION release"
88+
89+
util::changelog::update_release_api_version $CLIENT_VERSION $old_client_version $new_k8s_api_version
90+
91+
# get API change release notes since $old_k8s_api_version.
92+
# NOTE: $old_k8s_api_version may be one-minor-version behind $KUBERNETES_BRANCH, e.g.
93+
# KUBERNETES_BRANCH=release-1.19
94+
# old_k8s_api_version=1.18.17
95+
# when we bump the minor version for the snapshot in the master branch. We
96+
# don't need to collect release notes in release-1.18, because any API
97+
# change in 1.18.x (x > 17) must be a cherrypick that is already included in
98+
# release-1.19.
99+
# TODO(roycaihw): not all Kubernetes API changes modify the OpenAPI spec.
100+
# Download the patch and skip if the spec is not modified. Also we want want to
101+
# look at other k/k sections like "deprecation"
102+
release_notes=$(util::kube_changelog::get_api_changelog "$KUBERNETES_BRANCH" "$old_k8s_api_version")
103+
if [[ -n "$release_notes" ]]; then
104+
util::changelog::write_changelog v$CLIENT_VERSION "### API Change" "$release_notes"
105+
fi
106+
107+
git commit -m "update changelog"
108+
109+
# run client generator
110+
scripts/update-client.sh
111+
112+
rm -r kubernetes/test/
113+
git add .
114+
git commit -m "temporary generated commit"
115+
scripts/apply-hotfixes.sh
116+
git reset HEAD~2
117+
# custom object API is hosted in gen repo. Commit API change separately for
118+
# easier review
119+
if [[ -z "$(git diff kubernetes/client/api/custom_objects_api.py)" ]]; then
120+
git add kubernetes/client/api/custom_objects_api.py
121+
git commit -m "generated client change for custom_objects"
122+
fi
123+
git add kubernetes/docs kubernetes/client/api/ kubernetes/client/models/ kubernetes/swagger.json.unprocessed scripts/swagger.json
124+
git commit -m "generated API change"
125+
git add .
126+
git commit -m "generated client change"

scripts/update-client.sh

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ export OPENAPI_GENERATOR_COMMIT="v4.3.0"
2626

2727
SCRIPT_ROOT=$(dirname "${BASH_SOURCE}")
2828
CLIENT_ROOT="${SCRIPT_ROOT}/../kubernetes"
29-
CLIENT_VERSION=$(python "${SCRIPT_ROOT}/constants.py" CLIENT_VERSION)
30-
PACKAGE_NAME=$(python "${SCRIPT_ROOT}/constants.py" PACKAGE_NAME)
31-
DEVELOPMENT_STATUS=$(python "${SCRIPT_ROOT}/constants.py" DEVELOPMENT_STATUS)
29+
CLIENT_VERSION=$(python3 "${SCRIPT_ROOT}/constants.py" CLIENT_VERSION)
30+
PACKAGE_NAME=$(python3 "${SCRIPT_ROOT}/constants.py" PACKAGE_NAME)
31+
DEVELOPMENT_STATUS=$(python3 "${SCRIPT_ROOT}/constants.py" DEVELOPMENT_STATUS)
3232

3333
pushd "${SCRIPT_ROOT}" > /dev/null
3434
SCRIPT_ROOT=`pwd`
@@ -45,8 +45,8 @@ TEMP_FOLDER=$(mktemp -d)
4545
trap "rm -rf ${TEMP_FOLDER}" EXIT SIGINT
4646

4747
SETTING_FILE="${TEMP_FOLDER}/settings"
48-
echo "export KUBERNETES_BRANCH=\"$(python ${SCRIPT_ROOT}/constants.py KUBERNETES_BRANCH)\"" > $SETTING_FILE
49-
echo "export CLIENT_VERSION=\"$(python ${SCRIPT_ROOT}/constants.py CLIENT_VERSION)\"" >> $SETTING_FILE
48+
echo "export KUBERNETES_BRANCH=\"$(python3 ${SCRIPT_ROOT}/constants.py KUBERNETES_BRANCH)\"" > $SETTING_FILE
49+
echo "export CLIENT_VERSION=\"$(python3 ${SCRIPT_ROOT}/constants.py CLIENT_VERSION)\"" >> $SETTING_FILE
5050
echo "export PACKAGE_NAME=\"client\"" >> $SETTING_FILE
5151

5252
if [[ -z ${GEN_ROOT:-} ]]; then

scripts/util/changelog.sh

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
# See the License for the specific language governing permissions and
1515
# limitations under the License.
1616

17+
18+
# Utilities for parsing/writing the Python client's changelog.
19+
1720
changelog="$(git rev-parse --show-toplevel)/CHANGELOG.md"
1821

1922
function util::changelog::has_release {
@@ -44,7 +47,7 @@ function util::changelog::find_release_end {
4447
echo $((${releases[${next_release_index}]}-1))
4548
}
4649

47-
# has_section returns if the given section exists between start and end
50+
# has_section_in_range returns if the given section exists between start and end
4851
function util::changelog::has_section_in_range {
4952
local section="$1"
5053
local start=$2
@@ -59,7 +62,7 @@ function util::changelog::has_section_in_range {
5962
return 1
6063
}
6164

62-
# find_section returns the number of the first line of the given section
65+
# find_section_in_range returns the number of the first line of the given section
6366
function util::changelog::find_section_in_range {
6467
local section="$1"
6568
local start=$2
@@ -107,3 +110,44 @@ function util::changelog::write_changelog {
107110
# update changelog
108111
sed -i "${line_to_edit}i${release_notes}" $changelog
109112
}
113+
114+
# get_api_version returns the Kubernetes API Version for the given client
115+
# version in the changelog.
116+
function util::changelog::get_k8s_api_version {
117+
local client_version="$1"
118+
119+
local api_version_section="Kubernetes API Version: "
120+
if ! util::changelog::has_release "$client_version"; then
121+
echo "error: release $client_version not found"
122+
exit 1
123+
fi
124+
125+
local start=$(util::changelog::find_release_start "$client_version")
126+
local end=$(util::changelog::find_release_end "$client_version")
127+
if ! util::changelog::has_section_in_range "$api_version_section" "$start" "$end"; then
128+
echo "error: api version for release $client_version not found"
129+
exit 1
130+
fi
131+
132+
local api_version_line=$(util::changelog::find_section_in_range "$api_version_section" "$start" "$end")
133+
echo $(sed -n ${api_version_line}p $changelog | sed "s/$api_version_section//g")
134+
}
135+
136+
function util::changelog::update_release_api_version {
137+
local release="$1"
138+
local old_release="$2"
139+
local k8s_api_version="$3"
140+
141+
echo "New release: $release"
142+
echo "Old release: $old_release"
143+
144+
if ! util::changelog::has_release v$old_release; then
145+
sed -i "1i# v$release\n\nKubernetes API Version: $k8s_api_version\n\n" $changelog
146+
exit 0
147+
fi
148+
start=$(util::changelog::find_release_start v$old_release)
149+
sed -i "${start}s/# v$old_release/# v$release/" $changelog
150+
echo "$start"
151+
echo "$((${start}+2))"
152+
sed -i "$((${start}+2))s/^Kubernetes API Version: .*$/Kubernetes API Version: $k8s_api_version/" $changelog
153+
}

scripts/util/kube_changelog.sh

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#!/bin/bash
2+
3+
# Copyright 2021 The Kubernetes Authors.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
18+
# Utilities for parsing Kubernetes changelog.
19+
20+
# find_latest_patch_version finds the latest released patch version for the
21+
# given branch.
22+
# We use the version to track what API surface the generated Python client
23+
# cooresponds to, and collect all API change release notes up to that version.
24+
# There is one tricky point: the code generator we use pulls the latest OpenAPI
25+
# spec from the given branch. The spec may contain API changes that aren't
26+
# documented in the Kubernetes release notes. Until the code generator pulls
27+
# the spec from a tag instead of the branch, we can only collect the release
28+
# notes the next time we generate the client.
29+
function util::kube_changelog::find_latest_patch_version {
30+
local kubernetes_branch=$1
31+
32+
# trim "release-" prefix
33+
local version=${kubernetes_branch:8}
34+
local changelog="/tmp/k8s-changelog-$version.md"
35+
curl -s -o $changelog "https://raw.githubusercontent.com/kubernetes/kubernetes/master/CHANGELOG/CHANGELOG-$version.md"
36+
echo $(grep "v$version" $changelog | head -1 | sed 's/- \[//g' | sed 's/\].*//g')
37+
rm -f $changelog
38+
}
39+
40+
# get_api_changelog gets the API Change release notes in the given Kubernetes
41+
# branch for all versions newer than the given trim version.
42+
function util::kube_changelog::get_api_changelog {
43+
local kubernetes_branch="$1"
44+
local trim_version="$2"
45+
46+
# trim "release-" prefix
47+
local version=${kubernetes_branch:8}
48+
local changelog="/tmp/k8s-changelog-$version.md"
49+
curl -s -o $changelog "https://raw.githubusercontent.com/kubernetes/kubernetes/master/CHANGELOG/CHANGELOG-$version.md"
50+
51+
# remove changelog for versions less than or equal to $trim_version
52+
sed -i "/^# $trim_version$/q" $changelog
53+
# ignore section titles and empty lines; add "kubernetes/kubernetes" to links; replace newline with liternal "\n"
54+
release_notes=$(sed -n "/^### API Change/,/^#/{/^#/!p}" $changelog | sed -n "{/^$/!p}" | sed 's/(\[\#/(\[kubernetes\/kubernetes\#/g' | sed ':a;N;$!ba;s/\n/\\n/g')
55+
rm -f $changelog
56+
echo "$release_notes"
57+
}

0 commit comments

Comments
 (0)