Skip to content

Commit 052f6df

Browse files
authored
[jvm-packages] Update helper script for publishing Maven Central (dmlc#11393)
* Update helper script for publishing Maven Central * Show progress for GPU variant * Only upload xgboost4j-spark-gpu when gpu variant is selected * Insert required metadata for xgboost4j-spark-gpu * Restore xgboost4j-spark-gpu/pom.xml for every invocation * Insert metadata first * Work around issue with gtest from dmlc-core * Put metadata in xgboost4j-spark-gpu/pom.xml * Revert "Work around issue with gtest from dmlc-core" This reverts commit bdf0a06. * Support CMake 4.0
1 parent c12b049 commit 052f6df

File tree

5 files changed

+172
-118
lines changed

5 files changed

+172
-118
lines changed

dev/prepare_jvm_release.py

Lines changed: 132 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,33 @@
1+
"""
2+
Helper script to prepare for releasing XGBoost JVM packages to
3+
Maven Central.
4+
5+
## Prerequisite
6+
7+
1. You must have the right to upload artifacts to the Maven Central repo.
8+
If you do not, contact Hyunsu Cho ([email protected]) so that
9+
he can contact Sonatype on your behalf in order to add you as a
10+
"producer" user for the ml.dmlc namespace. See
11+
https://central.sonatype.org/pages/support/#status to learn about
12+
the process for adding or removing users who can publish to the project.
13+
14+
2. Follow instructions in
15+
https://central.sonatype.org/publish/publish-portal-maven/#credentials
16+
to set up the authentication token in your machine.
17+
18+
3. Set up GPG for signing artifacts:
19+
https://central.sonatype.org/publish/requirements/gpg/
20+
21+
## Making the release
22+
Run this script 4 times:
23+
24+
python3 dev/prepare_jvm_release.py --scala-version 2.12 --variant cpu
25+
python3 dev/prepare_jvm_release.py --scala-version 2.12 --variant gpu
26+
python3 dev/prepare_jvm_release.py --scala-version 2.13 --variant cpu
27+
python3 dev/prepare_jvm_release.py --scala-version 2.13 --variant gpu
28+
29+
"""
30+
131
import argparse
232
import errno
333
import glob
@@ -52,7 +82,7 @@ def cd(path):
5282

5383
def run(command, **kwargs):
5484
print(command)
55-
subprocess.check_call(command, shell=True, **kwargs)
85+
subprocess.run(command, shell=True, check=True, **kwargs)
5686

5787

5888
def get_current_commit_hash():
@@ -74,141 +104,135 @@ def retrieve(url, filename=None):
74104

75105

76106
def main():
77-
parser = argparse.ArgumentParser()
107+
parser = argparse.ArgumentParser(
108+
description=__doc__, formatter_class=argparse.RawTextHelpFormatter
109+
)
78110
parser.add_argument(
79111
"--release-version",
80112
type=str,
81113
required=True,
82114
help="Version of the release being prepared",
83115
)
116+
parser.add_argument(
117+
"--scala-version",
118+
type=str,
119+
required=True,
120+
help="Version of Scala to use in the JVM packages",
121+
choices=["2.12", "2.13"],
122+
)
123+
parser.add_argument(
124+
"--variant",
125+
type=str,
126+
required=True,
127+
choices=["cpu", "gpu"],
128+
help="JVM package variant to package and publish",
129+
)
130+
84131
args = parser.parse_args()
85132
version = args.release_version
133+
scala_version = args.scala_version
134+
use_cuda = args.variant == "gpu"
86135

87136
commit_hash = get_current_commit_hash()
88137
git_branch = get_current_git_branch()
89-
print(
90-
f"Using commit {commit_hash} of branch {git_branch}"
138+
print(f"Using commit {commit_hash} of branch {git_branch}")
139+
print(f"====Update pom.xml to use Scala {scala_version}====")
140+
run(
141+
f"{sys.executable} ops/script/change_scala_version.py "
142+
f"--scala-version {scala_version} --purge-artifacts"
91143
)
92144

93145
with cd("jvm-packages/"):
94-
print("====copying pure-Python tracker====")
95-
for use_cuda in [True, False]:
96-
xgboost4j = "xgboost4j-gpu" if use_cuda else "xgboost4j"
97-
cp(
98-
"../python-package/xgboost/tracker.py",
99-
f"{xgboost4j}/src/main/resources",
100-
)
101-
102-
print("====copying resources for testing====")
146+
print("====Copying resources for testing====")
103147
with cd("../demo/CLI/regression"):
104148
run(f"{sys.executable} mapfeat.py")
105149
run(f"{sys.executable} mknfold.py machine.txt 1")
106-
for use_cuda in [True, False]:
107-
xgboost4j = "xgboost4j-gpu" if use_cuda else "xgboost4j"
108-
xgboost4j_spark = "xgboost4j-spark-gpu" if use_cuda else "xgboost4j-spark"
109-
maybe_makedirs(f"{xgboost4j}/src/test/resources")
110-
maybe_makedirs(f"{xgboost4j_spark}/src/test/resources")
111-
for file in glob.glob("../demo/data/agaricus.*"):
112-
cp(file, f"{xgboost4j}/src/test/resources")
113-
cp(file, f"{xgboost4j_spark}/src/test/resources")
114-
for file in glob.glob("../demo/CLI/regression/machine.txt.t*"):
115-
cp(file, f"{xgboost4j_spark}/src/test/resources")
150+
xgboost4j_spark = "xgboost4j-spark-gpu" if use_cuda else "xgboost4j-spark"
151+
maybe_makedirs(f"xgboost4j/src/test/resources")
152+
maybe_makedirs(f"{xgboost4j_spark}/src/test/resources")
153+
for file in glob.glob("../demo/data/agaricus.*"):
154+
cp(file, f"xgboost4j/src/test/resources")
155+
cp(file, f"{xgboost4j_spark}/src/test/resources")
156+
for file in glob.glob("../demo/CLI/regression/machine.txt.t*"):
157+
cp(file, f"{xgboost4j_spark}/src/test/resources")
116158

117159
print("====Creating directories to hold native binaries====")
118-
for os_ident, arch in [
119-
("linux", "x86_64"),
120-
("linux", "aarch64"),
121-
("windows", "x86_64"),
122-
("macos", "x86_64"),
123-
("macos", "aarch64"),
124-
]:
160+
if use_cuda:
161+
# TODO(hcho3): Add GPU build for linux aarch64
162+
matrix = [("linux", "x86_64")]
163+
else:
164+
matrix = [
165+
("linux", "x86_64"),
166+
("linux", "aarch64"),
167+
("windows", "x86_64"),
168+
("macos", "x86_64"),
169+
("macos", "aarch64"),
170+
]
171+
for os_ident, arch in matrix:
125172
output_dir = f"xgboost4j/src/main/resources/lib/{os_ident}/{arch}"
126173
maybe_makedirs(output_dir)
127-
for os_ident, arch in [("linux", "x86_64")]:
128-
output_dir = f"xgboost4j-gpu/src/main/resources/lib/{os_ident}/{arch}"
129-
maybe_makedirs(output_dir)
130174

131175
print("====Downloading native binaries from CI====")
132-
nightly_bucket_prefix = (
133-
"https://s3-us-west-2.amazonaws.com/xgboost-nightly-builds"
134-
)
135-
maven_repo_prefix = (
136-
"https://s3-us-west-2.amazonaws.com/xgboost-maven-repo/release/ml/dmlc"
137-
)
138-
139-
retrieve(
140-
url=f"{nightly_bucket_prefix}/{git_branch}/libxgboost4j/xgboost4j_{commit_hash}.dll",
141-
filename="xgboost4j/src/main/resources/lib/windows/x86_64/xgboost4j.dll",
142-
)
143-
retrieve(
144-
url=f"{nightly_bucket_prefix}/{git_branch}/libxgboost4j/libxgboost4j_linux_x86_64_{commit_hash}.so",
145-
filename="xgboost4j/src/main/resources/lib/linux/x86_64/libxgboost4j.so",
146-
)
147-
retrieve(
148-
url=f"{nightly_bucket_prefix}/{git_branch}/libxgboost4j/libxgboost4j_linux_arm64_{commit_hash}.so",
149-
filename="xgboost4j/src/main/resources/lib/linux/aarch64/libxgboost4j.so",
150-
)
151-
retrieve(
152-
url=f"{nightly_bucket_prefix}/{git_branch}/libxgboost4j/libxgboost4j_{commit_hash}.dylib",
153-
filename="xgboost4j/src/main/resources/lib/macos/x86_64/libxgboost4j.dylib",
154-
)
155-
retrieve(
156-
url=f"{nightly_bucket_prefix}/{git_branch}/libxgboost4j/libxgboost4j_m1_{commit_hash}.dylib",
157-
filename="xgboost4j/src/main/resources/lib/macos/aarch64/libxgboost4j.dylib",
158-
)
159-
160-
with tempfile.TemporaryDirectory() as tempdir:
161-
# libxgboost4j.so for Linux x86_64, GPU support
162-
zip_path = os.path.join(tempdir, "xgboost4j-gpu_2.12.jar")
163-
extract_dir = os.path.join(tempdir, "xgboost4j-gpu")
164-
retrieve(
165-
url=f"{maven_repo_prefix}/xgboost4j-gpu_2.12/{version}/"
166-
f"xgboost4j-gpu_2.12-{version}.jar",
167-
filename=zip_path,
176+
if use_cuda:
177+
url_prefix = (
178+
"https://s3-us-west-2.amazonaws.com/xgboost-maven-repo/release/ml/dmlc"
179+
)
180+
with tempfile.TemporaryDirectory() as tempdir:
181+
# libxgboost4j.so for Linux x86_64, GPU support
182+
zip_path = os.path.join(tempdir, "xgboost4j-spark-gpu_2.12.jar")
183+
extract_dir = os.path.join(tempdir, "xgboost4j-spark-gpu")
184+
retrieve(
185+
url=f"{url_prefix}/xgboost4j-spark-gpu_2.12/{version}/"
186+
f"xgboost4j-spark-gpu_2.12-{version}.jar",
187+
filename=zip_path,
188+
)
189+
os.mkdir(extract_dir)
190+
with zipfile.ZipFile(zip_path, "r") as t:
191+
t.extractall(extract_dir)
192+
cp(
193+
os.path.join(
194+
extract_dir, "lib", "linux", "x86_64", "libxgboost4j.so"
195+
),
196+
"xgboost4j/src/main/resources/lib/linux/x86_64/libxgboost4j.so",
197+
)
198+
run(
199+
"mvn --no-transfer-progress install -Pgpu "
200+
"-DskipTests -Dmaven.test.skip=true -Dskip.native.build=true"
168201
)
169-
os.mkdir(extract_dir)
170-
with zipfile.ZipFile(zip_path, "r") as t:
171-
t.extractall(extract_dir)
172-
cp(
173-
os.path.join(extract_dir, "lib", "linux", "x86_64", "libxgboost4j.so"),
174-
"xgboost4j-gpu/src/main/resources/lib/linux/x86_64/libxgboost4j.so",
202+
run(
203+
"mvn deploy -Pgpu,release -pl xgboost4j-spark-gpu "
204+
"-DskipTests -Dmaven.test.skip=true -Dskip.native.build=true"
205+
)
206+
else:
207+
url_prefix = "https://s3-us-west-2.amazonaws.com/xgboost-nightly-builds"
208+
for os_ident, arch, src_libname, dest_libname in [
209+
("linux", "x86_64", "libxgboost4j_linux_x86_64.so", "libxgboost4j.so"),
210+
(
211+
"linux",
212+
"aarch64",
213+
"libxgboost4j_linux_aarch64.so",
214+
"libxgboost4j.so",
215+
),
216+
("windows", "x86_64", "xgboost4j.dll", "xgboost4j.dll"),
217+
("macos", "x86_64", "libxgboost4j_intel.dylib", "libxgboost4j.dylib"),
218+
("macos", "aarch64", "libxgboost4j_m1.dylib", "libxgboost4j.dylib"),
219+
]:
220+
retrieve(
221+
url=f"{url_prefix}/{git_branch}/{commit_hash}/{src_libname}",
222+
filename=(
223+
"xgboost4j/src/main/resources/lib/"
224+
f"{os_ident}/{arch}/{dest_libname}"
225+
),
226+
)
227+
run(
228+
"mvn --no-transfer-progress deploy -Pdefault,release "
229+
"-DskipTests -Dmaven.test.skip=true -Dskip.native.build=true"
175230
)
176231

177232
print("====Next Steps====")
178-
print("1. Gain upload right to Maven Central repo.")
179-
print("1-1. Sign up for a JIRA account at Sonatype: ")
180-
print(
181-
"1-2. File a JIRA ticket: "
182-
"https://issues.sonatype.org/secure/CreateIssue.jspa?issuetype=21&pid=10134. Example: "
183-
"https://issues.sonatype.org/browse/OSSRH-67724"
184-
)
185-
print(
186-
"2. Store the Sonatype credentials in .m2/settings.xml. See insturctions in "
187-
"https://central.sonatype.org/publish/publish-maven/"
188-
)
189-
print(
190-
"3. Now on a Linux machine, run the following to build Scala 2.12 artifacts. "
191-
"Make sure to use an Internet connection with fast upload speed:"
192-
)
193-
print(
194-
" # Skip native build, since we have all needed native binaries from CI\n"
195-
" GPG_TTY=$(tty) mvn deploy -Prelease -DskipTests -Dskip.native.build=true"
196-
)
197-
print(
198-
"4. Log into https://oss.sonatype.org/. On the left menu panel, click Staging "
199-
"Repositories. Visit the URL https://oss.sonatype.org/content/repositories/mldmlc-xxxx "
200-
"to inspect the staged JAR files. Finally, press Release button to publish the "
201-
"artifacts to the Maven Central repository. The top-level metapackage should be "
202-
"named xgboost-jvm_2.12."
203-
)
204-
print(
205-
"5. Remove the Scala 2.12 artifacts and build Scala 2.13 artifacts:\n"
206-
" python ops/script/change_scala_version.py --scala-version 2.13 --purge-artifacts\n"
207-
" GPG_TTY=$(tty) mvn deploy -Prelease -DskipTests -Dskip.native.build=true"
208-
)
209233
print(
210-
"6. Go to https://oss.sonatype.org/ to release the Scala 2.13 artifacts. "
211-
"The top-level metapackage should be named xgboost-jvm_2.13."
234+
"Visit https://central.sonatype.com/publishing/deployments to verify the deployment. "
235+
"You can either drop the deployment or publish it. Note: publishing is final."
212236
)
213237

214238

jvm-packages/pom.xml

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -197,14 +197,12 @@
197197
</executions>
198198
</plugin>
199199
<plugin>
200-
<groupId>org.sonatype.plugins</groupId>
201-
<artifactId>nexus-staging-maven-plugin</artifactId>
202-
<version>1.7.0</version>
200+
<groupId>org.sonatype.central</groupId>
201+
<artifactId>central-publishing-maven-plugin</artifactId>
202+
<version>0.7.0</version>
203203
<extensions>true</extensions>
204204
<configuration>
205-
<serverId>ossrh</serverId>
206-
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
207-
<autoReleaseAfterClose>false</autoReleaseAfterClose>
205+
<publishingServerId>central</publishingServerId>
208206
</configuration>
209207
</plugin>
210208
<plugin>

jvm-packages/xgboost4j-spark-gpu/pom.xml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,37 @@
1010
</parent>
1111
<name>xgboost4j-spark-gpu</name>
1212
<artifactId>xgboost4j-spark-gpu_2.12</artifactId>
13+
<description>JVM Package for XGBoost</description>
14+
<url>https://github.com/dmlc/xgboost/tree/master/jvm-packages</url>
15+
<licenses>
16+
<license>
17+
<name>The Apache License, Version 2.0</name>
18+
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
19+
</license>
20+
</licenses>
21+
<developers>
22+
<developer>
23+
<name>Bobby Wang</name>
24+
<email>[email protected]</email>
25+
</developer>
26+
<developer>
27+
<name>Jiaming Yuan</name>
28+
<email>[email protected]</email>
29+
</developer>
30+
<developer>
31+
<name>Hyunsu Cho</name>
32+
<email>[email protected]</email>
33+
</developer>
34+
<developer>
35+
<name>CodingCat</name>
36+
<email>[email protected]</email>
37+
</developer>
38+
</developers>
39+
<scm>
40+
<connection>scm:git:git:/github.com/dmlc/xgboost.git</connection>
41+
<developerConnection>scm:git:ssh://github.com/dmlc/xgboost.git</developerConnection>
42+
<url>https://github.com/dmlc/xgboost</url>
43+
</scm>
1344
<build>
1445
<plugins>
1546
<plugin>

ops/script/change_scala_version.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@ def main(args: argparse.Namespace) -> None:
2020
if target.is_dir():
2121
print(f"Removing {target}...")
2222
shutil.rmtree(target)
23-
for target in pathlib.Path("jvm-packages/").glob("**/*.so"):
24-
print(f"Removing {target}...")
25-
target.unlink()
23+
for ext in ["so", "dll", "dylib"]:
24+
for target in pathlib.Path("jvm-packages/").glob(f"**/*.{ext}"):
25+
print(f"Removing {target}...")
26+
target.unlink()
2627

2728
# Update pom.xml
2829
for pom in pathlib.Path("jvm-packages/").glob("**/pom.xml"):

0 commit comments

Comments
 (0)