Add script for change version. (#8443)
- Replace jvm regex replacement script with mvn command. - Replace cmake script for python version with python script. - Automate rest of the manual steps. The script can handle dev branch, rc release, and formal release version.
This commit is contained in:
parent
5f1a6fca0d
commit
284dcf8d22
@ -1 +0,0 @@
|
|||||||
@xgboost_VERSION_MAJOR@.@xgboost_VERSION_MINOR@.@xgboost_VERSION_PATCH@-dev
|
|
||||||
@ -3,7 +3,4 @@ function (write_version)
|
|||||||
configure_file(
|
configure_file(
|
||||||
${xgboost_SOURCE_DIR}/cmake/version_config.h.in
|
${xgboost_SOURCE_DIR}/cmake/version_config.h.in
|
||||||
${xgboost_SOURCE_DIR}/include/xgboost/version_config.h @ONLY)
|
${xgboost_SOURCE_DIR}/include/xgboost/version_config.h @ONLY)
|
||||||
configure_file(
|
|
||||||
${xgboost_SOURCE_DIR}/cmake/Python_version.in
|
|
||||||
${xgboost_SOURCE_DIR}/python-package/xgboost/VERSION @ONLY)
|
|
||||||
endfunction (write_version)
|
endfunction (write_version)
|
||||||
|
|||||||
@ -17,18 +17,7 @@ Making a Release
|
|||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
1. Create an issue for the release, noting the estimated date and expected features or major fixes, pin that issue.
|
1. Create an issue for the release, noting the estimated date and expected features or major fixes, pin that issue.
|
||||||
2. Create a release branch if this is a major release. Bump release version.
|
2. Create a release branch if this is a major release. Bump release version. There's a helper script ``tests/ci_build/change_version.py``.
|
||||||
|
|
||||||
1. Modify ``CMakeLists.txt`` in source tree and ``cmake/Python_version.in`` if needed, run CMake.
|
|
||||||
|
|
||||||
If this is a RC release, the Python version has the form <major>.<minor>.<patch>rc1
|
|
||||||
|
|
||||||
2. Modify ``DESCRIPTION`` and ``configure.ac`` in R-package. Run ``autoreconf``.
|
|
||||||
|
|
||||||
3. Run ``change_version.sh`` in ``jvm-packages/dev``
|
|
||||||
|
|
||||||
If this is a RC release, the version for JVM packages has the form <major>.<minor>.<patch>-RC1
|
|
||||||
|
|
||||||
3. Commit the change, create a PR on GitHub on release branch. Port the bumped version to default branch, optionally with the postfix ``SNAPSHOT``.
|
3. Commit the change, create a PR on GitHub on release branch. Port the bumped version to default branch, optionally with the postfix ``SNAPSHOT``.
|
||||||
4. Create a tag on release branch, either on GitHub or locally.
|
4. Create a tag on release branch, either on GitHub or locally.
|
||||||
5. Make a release on GitHub tag page, which might be done with previous step if the tag is created on GitHub.
|
5. Make a release on GitHub tag page, which might be done with previous step if the tag is created on GitHub.
|
||||||
|
|||||||
@ -1,43 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
#
|
|
||||||
# Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
# or more contributor license agreements. See the NOTICE file
|
|
||||||
# distributed with this work for additional information
|
|
||||||
# regarding copyright ownership. The ASF licenses this file
|
|
||||||
# to you 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.
|
|
||||||
#
|
|
||||||
# (Yizhi) This is mainly inspired by the script in apache/spark.
|
|
||||||
# I did some modifications to get it with our project.
|
|
||||||
# (Nan) Modified from MxNet
|
|
||||||
#
|
|
||||||
set -e
|
|
||||||
|
|
||||||
if [[ ($# -ne 2) || ( $1 == "--help") || $1 == "-h" ]]; then
|
|
||||||
echo "Usage: $(basename $0) [-h|--help] <from_version> <to_version>" 1>&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
FROM_VERSION=$1
|
|
||||||
TO_VERSION=$2
|
|
||||||
|
|
||||||
sed_i() {
|
|
||||||
perl -p -000 -e "$1" "$2" > "$2.tmp" && mv "$2.tmp" "$2"
|
|
||||||
}
|
|
||||||
|
|
||||||
export -f sed_i
|
|
||||||
|
|
||||||
BASEDIR=$(dirname $0)/..
|
|
||||||
find "$BASEDIR" -name 'pom.xml' -not -path '*target*' -print \
|
|
||||||
-exec bash -c \
|
|
||||||
"sed_i 's/(<artifactId>(xgboost-jvm.*|xgboost4j.*)<\/artifactId>\s+<version)>'$FROM_VERSION'(<\/version>)/\1>'$TO_VERSION'\3/g' {}" \;
|
|
||||||
141
tests/ci_build/change_version.py
Normal file
141
tests/ci_build/change_version.py
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
"""
|
||||||
|
1. Modify ``CMakeLists.txt`` in source tree and ``python-package/xgboost/VERSION`` if
|
||||||
|
needed, run CMake .
|
||||||
|
If this is a RC release, the Python version has the form <major>.<minor>.<patch>rc1
|
||||||
|
2. Modify ``DESCRIPTION`` and ``configure.ac`` in R-package. Run ``autoreconf``.
|
||||||
|
3. Run ``mvn`` in ``jvm-packages``
|
||||||
|
If this is a RC release, the version for JVM packages has the form
|
||||||
|
<major>.<minor>.<patch>-RC1
|
||||||
|
"""
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
from test_utils import JVM_PACKAGES, PY_PACKAGE, R_PACKAGE, ROOT, cd
|
||||||
|
|
||||||
|
|
||||||
|
@cd(ROOT)
|
||||||
|
def cmake(major: int, minor: int, patch: int) -> None:
|
||||||
|
version = f"{major}.{minor}.{patch}"
|
||||||
|
with open("CMakeLists.txt", "r") as fd:
|
||||||
|
cmakelist = fd.read()
|
||||||
|
pattern = r"project\(xgboost LANGUAGES .* VERSION ([0-9]+\.[0-9]+\.[0-9]+)\)"
|
||||||
|
matched = re.search(pattern, cmakelist)
|
||||||
|
assert matched, "Couldn't find the version string in CMakeLists.txt."
|
||||||
|
print(matched.start(1), matched.end(1))
|
||||||
|
cmakelist = cmakelist[: matched.start(1)] + version + cmakelist[matched.end(1) :]
|
||||||
|
with open("CMakeLists.txt", "w") as fd:
|
||||||
|
fd.write(cmakelist)
|
||||||
|
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
subprocess.call(["cmake", "-S", ".", "-B", tmpdir])
|
||||||
|
|
||||||
|
|
||||||
|
@cd(PY_PACKAGE)
|
||||||
|
def pypkg(
|
||||||
|
major: int, minor: int, patch: int, rc: int, is_rc: bool, is_dev: bool
|
||||||
|
) -> None:
|
||||||
|
version = f"{major}.{minor}.{patch}"
|
||||||
|
pyver_path = os.path.join("xgboost", "VERSION")
|
||||||
|
pyver = version
|
||||||
|
if is_rc:
|
||||||
|
pyver = pyver + f"rc{rc}"
|
||||||
|
if is_dev:
|
||||||
|
pyver = pyver + "-dev"
|
||||||
|
with open(pyver_path, "w") as fd:
|
||||||
|
fd.write(pyver)
|
||||||
|
|
||||||
|
|
||||||
|
@cd(R_PACKAGE)
|
||||||
|
def rpkg(major: int, minor: int, patch: int) -> None:
|
||||||
|
version = f"{major}.{minor}.{patch}.1"
|
||||||
|
# Version: 2.0.0.1
|
||||||
|
desc_path = "DESCRIPTION"
|
||||||
|
with open(desc_path, "r") as fd:
|
||||||
|
description = fd.read()
|
||||||
|
pattern = r"Version:\ ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)"
|
||||||
|
matched = re.search(pattern, description)
|
||||||
|
assert matched, "Couldn't find version string in DESCRIPTION."
|
||||||
|
description = (
|
||||||
|
description[: matched.start(1)] + version + description[matched.end(1) :]
|
||||||
|
)
|
||||||
|
with open(desc_path, "w") as fd:
|
||||||
|
fd.write(description)
|
||||||
|
|
||||||
|
config_path = "configure.ac"
|
||||||
|
# AC_INIT([xgboost],[2.0.0],[],[xgboost],[])
|
||||||
|
version = f"{major}.{minor}.{patch}"
|
||||||
|
with open(config_path, "r") as fd:
|
||||||
|
config = fd.read()
|
||||||
|
pattern = (
|
||||||
|
r"AC_INIT\(\[xgboost\],\[([0-9]+\.[0-9]+\.[0-9]+)\],\[\],\[xgboost\],\[\]\)"
|
||||||
|
)
|
||||||
|
matched = re.search(pattern, config)
|
||||||
|
assert matched, "Couldn't find version string in configure.ac"
|
||||||
|
config = config[: matched.start(1)] + version + config[matched.end(1) :]
|
||||||
|
|
||||||
|
with open(config_path, "w") as fd:
|
||||||
|
fd.write(config)
|
||||||
|
|
||||||
|
subprocess.check_call(["autoreconf"])
|
||||||
|
|
||||||
|
|
||||||
|
@cd(JVM_PACKAGES)
|
||||||
|
def jvmpkgs(
|
||||||
|
major: int, minor: int, patch: int, rc: int, is_rc: bool, is_dev: bool
|
||||||
|
) -> None:
|
||||||
|
version = f"{major}.{minor}.{patch}"
|
||||||
|
if is_dev:
|
||||||
|
version += "-SNAPSHOT"
|
||||||
|
if is_rc:
|
||||||
|
version += f"-RC{rc}"
|
||||||
|
subprocess.check_call(["mvn", "versions:set", f"-DnewVersion={version}"])
|
||||||
|
|
||||||
|
|
||||||
|
@cd(ROOT)
|
||||||
|
def main(args: argparse.Namespace) -> None:
|
||||||
|
major = args.major
|
||||||
|
minor = args.minor
|
||||||
|
patch = args.patch
|
||||||
|
rc = args.rc
|
||||||
|
is_rc = args.is_rc == 1
|
||||||
|
is_dev = args.is_dev == 1
|
||||||
|
if is_rc and is_dev:
|
||||||
|
raise ValueError("It cannot be both a rc and a dev branch.")
|
||||||
|
if is_rc:
|
||||||
|
assert rc >= 1, "RC version starts from 1."
|
||||||
|
else:
|
||||||
|
assert rc == 0, "RC is not used."
|
||||||
|
|
||||||
|
cmake(major, minor, patch)
|
||||||
|
pypkg(major, minor, patch, rc, is_rc, is_dev)
|
||||||
|
rpkg(major, minor, patch)
|
||||||
|
jvmpkgs(major, minor, patch, rc, is_rc, is_dev)
|
||||||
|
|
||||||
|
print(
|
||||||
|
"""
|
||||||
|
|
||||||
|
Please examine the changes and commit. Be aware that mvn might leave backup files in the
|
||||||
|
source tree.
|
||||||
|
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--major", type=int)
|
||||||
|
parser.add_argument("--minor", type=int)
|
||||||
|
parser.add_argument("--patch", type=int)
|
||||||
|
parser.add_argument("--rc", type=int, default=0)
|
||||||
|
parser.add_argument("--is-rc", type=int, choices=[0, 1])
|
||||||
|
parser.add_argument("--is-dev", type=int, choices=[0, 1])
|
||||||
|
args = parser.parse_args()
|
||||||
|
try:
|
||||||
|
main(args)
|
||||||
|
except Exception as e:
|
||||||
|
print("Error:", e, file=sys.stderr)
|
||||||
|
exit(-1)
|
||||||
@ -6,10 +6,9 @@ from multiprocessing import Pool, cpu_count
|
|||||||
from typing import Dict, Tuple
|
from typing import Dict, Tuple
|
||||||
|
|
||||||
from pylint import epylint
|
from pylint import epylint
|
||||||
from test_utils import DirectoryExcursion, print_time, record_time
|
from test_utils import PY_PACKAGE, ROOT, cd, print_time, record_time
|
||||||
|
|
||||||
CURDIR = os.path.normpath(os.path.abspath(os.path.dirname(__file__)))
|
CURDIR = os.path.normpath(os.path.abspath(os.path.dirname(__file__)))
|
||||||
PROJECT_ROOT = os.path.normpath(os.path.join(CURDIR, os.path.pardir, os.path.pardir))
|
|
||||||
|
|
||||||
|
|
||||||
@record_time
|
@record_time
|
||||||
@ -45,9 +44,9 @@ Please run the following command on your machine to address the formatting error
|
|||||||
|
|
||||||
|
|
||||||
@record_time
|
@record_time
|
||||||
|
@cd(PY_PACKAGE)
|
||||||
def run_mypy(rel_path: str) -> bool:
|
def run_mypy(rel_path: str) -> bool:
|
||||||
with DirectoryExcursion(os.path.join(PROJECT_ROOT, "python-package")):
|
path = os.path.join(ROOT, rel_path)
|
||||||
path = os.path.join(PROJECT_ROOT, rel_path)
|
|
||||||
ret = subprocess.run(["mypy", path])
|
ret = subprocess.run(["mypy", path])
|
||||||
if ret.returncode != 0:
|
if ret.returncode != 0:
|
||||||
return False
|
return False
|
||||||
@ -58,7 +57,7 @@ class PyLint:
|
|||||||
"""A helper for running pylint, mostly copied from dmlc-core/scripts."""
|
"""A helper for running pylint, mostly copied from dmlc-core/scripts."""
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.pypackage_root = os.path.join(PROJECT_ROOT, "python-package/")
|
self.pypackage_root = os.path.join(ROOT, "python-package/")
|
||||||
self.pylint_cats = set(["error", "warning", "convention", "refactor"])
|
self.pylint_cats = set(["error", "warning", "convention", "refactor"])
|
||||||
self.pylint_opts = [
|
self.pylint_opts = [
|
||||||
"--extension-pkg-whitelist=numpy",
|
"--extension-pkg-whitelist=numpy",
|
||||||
@ -147,9 +146,6 @@ def main(args: argparse.Namespace) -> None:
|
|||||||
"tests/python/test_data_iterator.py",
|
"tests/python/test_data_iterator.py",
|
||||||
"tests/python/test_quantile_dmatrix.py",
|
"tests/python/test_quantile_dmatrix.py",
|
||||||
"tests/python-gpu/test_gpu_data_iterator.py",
|
"tests/python-gpu/test_gpu_data_iterator.py",
|
||||||
"tests/ci_build/lint_python.py",
|
|
||||||
"tests/ci_build/test_r_package.py",
|
|
||||||
"tests/ci_build/test_utils.py",
|
|
||||||
"tests/test_distributed/test_with_spark/",
|
"tests/test_distributed/test_with_spark/",
|
||||||
"tests/test_distributed/test_gpu_with_spark/",
|
"tests/test_distributed/test_gpu_with_spark/",
|
||||||
# demo
|
# demo
|
||||||
@ -157,6 +153,11 @@ def main(args: argparse.Namespace) -> None:
|
|||||||
"demo/guide-python/cat_in_the_dat.py",
|
"demo/guide-python/cat_in_the_dat.py",
|
||||||
"demo/guide-python/categorical.py",
|
"demo/guide-python/categorical.py",
|
||||||
"demo/guide-python/spark_estimator_examples.py",
|
"demo/guide-python/spark_estimator_examples.py",
|
||||||
|
# CI
|
||||||
|
"tests/ci_build/lint_python.py",
|
||||||
|
"tests/ci_build/test_r_package.py",
|
||||||
|
"tests/ci_build/test_utils.py",
|
||||||
|
"tests/ci_build/change_version.py",
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
if not all(black_results):
|
if not all(black_results):
|
||||||
@ -195,14 +196,17 @@ def main(args: argparse.Namespace) -> None:
|
|||||||
# tests
|
# tests
|
||||||
"tests/python/test_data_iterator.py",
|
"tests/python/test_data_iterator.py",
|
||||||
"tests/python-gpu/test_gpu_data_iterator.py",
|
"tests/python-gpu/test_gpu_data_iterator.py",
|
||||||
"tests/ci_build/lint_python.py",
|
|
||||||
"tests/ci_build/test_r_package.py",
|
|
||||||
"tests/ci_build/test_utils.py",
|
|
||||||
"tests/test_distributed/test_with_spark/test_data.py",
|
"tests/test_distributed/test_with_spark/test_data.py",
|
||||||
"tests/test_distributed/test_gpu_with_spark/test_data.py",
|
"tests/test_distributed/test_gpu_with_spark/test_data.py",
|
||||||
"tests/test_distributed/test_gpu_with_dask/test_gpu_with_dask.py",
|
"tests/test_distributed/test_gpu_with_dask/test_gpu_with_dask.py",
|
||||||
|
# CI
|
||||||
|
"tests/ci_build/lint_python.py",
|
||||||
|
"tests/ci_build/test_r_package.py",
|
||||||
|
"tests/ci_build/test_utils.py",
|
||||||
|
"tests/ci_build/change_version.py",
|
||||||
]
|
]
|
||||||
):
|
):
|
||||||
|
subprocess.check_call(["mypy", "--version"])
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
|
|
||||||
if args.pylint == 1:
|
if args.pylint == 1:
|
||||||
|
|||||||
@ -6,14 +6,7 @@ import subprocess
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from platform import system
|
from platform import system
|
||||||
|
|
||||||
from test_utils import DirectoryExcursion, cd, print_time, record_time
|
from test_utils import R_PACKAGE, ROOT, DirectoryExcursion, cd, print_time, record_time
|
||||||
|
|
||||||
ROOT = os.path.normpath(
|
|
||||||
os.path.join(
|
|
||||||
os.path.dirname(os.path.abspath(__file__)), os.path.pardir, os.path.pardir
|
|
||||||
)
|
|
||||||
)
|
|
||||||
r_package = os.path.join(ROOT, "R-package")
|
|
||||||
|
|
||||||
|
|
||||||
def get_mingw_bin() -> str:
|
def get_mingw_bin() -> str:
|
||||||
@ -153,7 +146,7 @@ def check_rpackage(path: str) -> None:
|
|||||||
raise ValueError("Suspicious NOTE.")
|
raise ValueError("Suspicious NOTE.")
|
||||||
|
|
||||||
|
|
||||||
@cd(r_package)
|
@cd(R_PACKAGE)
|
||||||
@record_time
|
@record_time
|
||||||
def check_rmarkdown() -> None:
|
def check_rmarkdown() -> None:
|
||||||
assert system() != "Windows", "Document test doesn't support Windows."
|
assert system() != "Windows", "Document test doesn't support Windows."
|
||||||
@ -171,7 +164,7 @@ def check_rmarkdown() -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@cd(r_package)
|
@cd(R_PACKAGE)
|
||||||
@record_time
|
@record_time
|
||||||
def test_with_autotools() -> None:
|
def test_with_autotools() -> None:
|
||||||
"""Windows only test. No `--as-cran` check, only unittests. We don't want to manage
|
"""Windows only test. No `--as-cran` check, only unittests. We don't want to manage
|
||||||
@ -240,7 +233,7 @@ def test_with_cmake(args: argparse.Namespace) -> None:
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise ValueError("Wrong compiler")
|
raise ValueError("Wrong compiler")
|
||||||
with DirectoryExcursion(r_package):
|
with DirectoryExcursion(R_PACKAGE):
|
||||||
subprocess.check_call(
|
subprocess.check_call(
|
||||||
[
|
[
|
||||||
R,
|
R,
|
||||||
|
|||||||
@ -70,3 +70,13 @@ def print_time() -> None:
|
|||||||
"Elapsed:",
|
"Elapsed:",
|
||||||
f"{v['total'].seconds} secs",
|
f"{v['total'].seconds} secs",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
ROOT = os.path.normpath(
|
||||||
|
os.path.join(
|
||||||
|
os.path.dirname(os.path.abspath(__file__)), os.path.pardir, os.path.pardir
|
||||||
|
)
|
||||||
|
)
|
||||||
|
R_PACKAGE = os.path.join(ROOT, "R-package")
|
||||||
|
JVM_PACKAGES = os.path.join(ROOT, "jvm-packages")
|
||||||
|
PY_PACKAGE = os.path.join(ROOT, "python-package")
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user