Skip to content

Commit ab42bb8

Browse files
[*] CI, publishing
1 parent c00f871 commit ab42bb8

File tree

3 files changed

+232
-6
lines changed

3 files changed

+232
-6
lines changed

build.gradle

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ def leafProjects = subprojects.findAll { subproject ->
3636
}
3737
ext.leafProjects = leafProjects // Publish as external variable
3838

39+
ext {
40+
sonaUser = findProperty('SONATYPE_NEXUS_USERNAME') ?: System.getenv('SONATYPE_NEXUS_USERNAME') ?: "FakeUser"
41+
sonaPass = findProperty('SONATYPE_NEXUS_PASSWORD') ?: System.getenv('SONATYPE_NEXUS_PASSWORD') ?: "FakePass"
42+
}
43+
3944
// Default test categories
4045
ext.categories = 'Unit'
4146

@@ -288,14 +293,18 @@ configure(leafProjects) {
288293

289294
required { isReleaseVersion }
290295
}
296+
}
291297

292-
// //tasks.test { enabled = false }
293-
// test {
294-
// useJUnit {
295-
// setIncludeCategories categories.split(',').collect { "deltix.util.CommonsJUnitCategories\$${it}".toString() } as Set
296-
// }
297-
// }
298+
task publishAll(dependsOn: leafProjects.collect { it.path + ":publish" }) {
299+
group 'publishing'
300+
description 'Publish All Artifacts'
301+
}
298302

303+
tasks.register('uploadArtifactsToCentralPortal', com.epam.deltix.buildsrc.SonatypeCentralPortalUploadRepositoryTask) {
304+
portalUsername.set(sonaUser)
305+
portalPassword.set(sonaPass)
306+
groupId.set('com.epam.deltix')
307+
snapshotRelease.set(false)
299308
}
300309

301310
allprojects {

buildSrc/build.gradle

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
repositories {
2+
mavenCentral()
3+
}
4+
5+
dependencies {
6+
implementation 'org.json:json:20240303'
7+
}
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
/*
2+
* Copyright 2014-2025 Real Logic Limited.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.epam.deltix.buildsrc;
17+
18+
import org.gradle.api.DefaultTask;
19+
import org.gradle.api.provider.Property;
20+
import org.gradle.api.tasks.Input;
21+
import org.gradle.api.tasks.TaskAction;
22+
import org.json.JSONArray;
23+
import org.json.JSONObject;
24+
25+
import java.io.BufferedReader;
26+
import java.io.IOException;
27+
import java.io.InputStream;
28+
import java.io.InputStreamReader;
29+
import java.net.HttpURLConnection;
30+
import java.net.URI;
31+
import java.net.URL;
32+
import java.nio.charset.StandardCharsets;
33+
import java.util.Base64;
34+
35+
/**
36+
* This task performs manual steps to publish artifacts to Central Portal via OSSRH Staging API.
37+
*/
38+
public class SonatypeCentralPortalUploadRepositoryTask extends DefaultTask {
39+
private static final String CENTRAL_PORTAL_OSSRH_API_URI = "https://ossrh-staging-api.central.sonatype.com";
40+
private static final int CONNECTION_TIMEOUT = 30000;
41+
42+
private final Property<String> portalUsername;
43+
private final Property<String> portalPassword;
44+
private final Property<String> groupId;
45+
private final Property<Boolean> snapshotRelease;
46+
47+
/**
48+
* Create new task instance.
49+
*/
50+
public SonatypeCentralPortalUploadRepositoryTask() {
51+
portalUsername = getProject().getObjects().property(String.class);
52+
portalPassword = getProject().getObjects().property(String.class);
53+
groupId = getProject().getObjects().property(String.class);
54+
snapshotRelease = getProject().getObjects().property(Boolean.class);
55+
}
56+
57+
/**
58+
* Return property to set Central Portal username.
59+
*
60+
* @return Central Portal username.
61+
*/
62+
@Input
63+
public Property<String> getPortalUsername() {
64+
return portalUsername;
65+
}
66+
67+
/**
68+
* Return property to set Central Portal password.
69+
*
70+
* @return Central Portal password.
71+
*/
72+
@Input
73+
public Property<String> getPortalPassword() {
74+
return portalPassword;
75+
}
76+
77+
/**
78+
* Return property to set {@code groupId} of the project.
79+
*
80+
* @return {@code groupId} of the project.
81+
*/
82+
@Input
83+
public Property<String> getGroupId() {
84+
return groupId;
85+
}
86+
87+
/**
88+
* Return property to set snapshot release.
89+
*
90+
* @return {@code true} if snapshot release.
91+
*/
92+
@Input
93+
public Property<Boolean> getSnapshotRelease() {
94+
return snapshotRelease;
95+
}
96+
97+
/**
98+
* Publish staging repository to the Central Portal.
99+
*/
100+
@TaskAction
101+
public void run() throws IOException, InterruptedException {
102+
if (!portalUsername.isPresent()) {
103+
return;
104+
}
105+
106+
if (snapshotRelease.get()) {
107+
return;
108+
}
109+
110+
String userNameAndPassword = portalUsername.get() + ":" + portalPassword.get();
111+
String bearer = Base64.getEncoder().encodeToString(userNameAndPassword.getBytes(StandardCharsets.US_ASCII));
112+
URI apiUri = URI.create(CENTRAL_PORTAL_OSSRH_API_URI);
113+
114+
String repositoryKey = findOpenRepository(apiUri, bearer);
115+
uploadRepositoryToPortal(apiUri, bearer, repositoryKey);
116+
dropRepository(apiUri, bearer, repositoryKey);
117+
}
118+
119+
private String findOpenRepository(URI apiUri, String bearer) throws IOException {
120+
String endpoint = apiUri.resolve("/manual/search/repositories?ip=client").toString();
121+
HttpURLConnection conn = (HttpURLConnection) new URL(endpoint).openConnection();
122+
conn.setConnectTimeout(CONNECTION_TIMEOUT);
123+
conn.setReadTimeout(CONNECTION_TIMEOUT);
124+
conn.setRequestMethod("GET");
125+
conn.setRequestProperty("Authorization", "Bearer " + bearer);
126+
127+
int status = conn.getResponseCode();
128+
String body = readBody(conn);
129+
if (status != 200) {
130+
throw new IllegalStateException("Failed to query repositories: " +
131+
"status=" + status + ", response=" + body);
132+
}
133+
134+
JSONArray repositories = new JSONObject(body).getJSONArray("repositories");
135+
if (repositories.isEmpty()) {
136+
throw new IllegalStateException("No open repositories found!");
137+
}
138+
139+
String repositoryKey = null;
140+
String group = groupId.get();
141+
for (int i = 0; i < repositories.length(); i++) {
142+
JSONObject repo = (JSONObject) repositories.get(i);
143+
if ("open".equals(repo.getString("state"))) {
144+
String key = repo.getString("key");
145+
if (key.contains(group)) {
146+
repositoryKey = key;
147+
break;
148+
}
149+
}
150+
}
151+
152+
if (null == repositoryKey) {
153+
throw new IllegalStateException("No open repositories found!");
154+
}
155+
return repositoryKey;
156+
}
157+
158+
private static void uploadRepositoryToPortal(URI apiUri, String bearer, String repositoryKey) throws IOException {
159+
String endpoint = apiUri.resolve("/manual/upload/repository/" + repositoryKey + "?publishing_type=user_managed").toString();
160+
HttpURLConnection conn = (HttpURLConnection) new URL(endpoint).openConnection();
161+
conn.setConnectTimeout(CONNECTION_TIMEOUT);
162+
conn.setReadTimeout(CONNECTION_TIMEOUT);
163+
conn.setRequestMethod("POST");
164+
conn.setRequestProperty("Authorization", "Bearer " + bearer);
165+
conn.setDoOutput(true);
166+
conn.getOutputStream().close();
167+
168+
int status = conn.getResponseCode();
169+
String body = readBody(conn);
170+
if (status != 200) {
171+
throw new IllegalStateException("Failed to upload repository: repository_key=" + repositoryKey + ", status=" + status + ", response=" + body);
172+
}
173+
}
174+
175+
private static void dropRepository(URI apiUri, String bearer, String repositoryKey) throws IOException {
176+
String endpoint = apiUri.resolve("/manual/drop/repository/" + repositoryKey).toString();
177+
HttpURLConnection conn = (HttpURLConnection) new URL(endpoint).openConnection();
178+
conn.setConnectTimeout(CONNECTION_TIMEOUT);
179+
conn.setReadTimeout(CONNECTION_TIMEOUT);
180+
conn.setRequestMethod("DELETE");
181+
conn.setRequestProperty("Authorization", "Bearer " + bearer);
182+
183+
int status = conn.getResponseCode();
184+
String body = readBody(conn);
185+
if (status != 204) {
186+
throw new IllegalStateException("Failed to drop repository: repository_key=" + repositoryKey + ", status=" + status + ", response=" + body);
187+
}
188+
}
189+
190+
private static String readBody(HttpURLConnection conn) throws IOException {
191+
InputStream stream;
192+
try {
193+
stream = (conn.getResponseCode() < 400) ? conn.getInputStream() : conn.getErrorStream();
194+
if (stream == null) {
195+
return "";
196+
}
197+
} catch (IOException e) {
198+
return "";
199+
}
200+
201+
StringBuilder body = new StringBuilder();
202+
try (BufferedReader in = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) {
203+
String line;
204+
while ((line = in.readLine()) != null) {
205+
body.append(line);
206+
}
207+
}
208+
return body.toString();
209+
}
210+
}

0 commit comments

Comments
 (0)