Skip to content

Commit 2e1cec0

Browse files
committed
Add sonatype/MavenCentral repository support
Signed-off-by: Peter Kirschner <[email protected]>
1 parent a8ad7b4 commit 2e1cec0

File tree

43 files changed

+1316
-48
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1316
-48
lines changed

.github/scripts/ci-build.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
#!/usr/bin/env bash
22
set -ev
3+
4+
# gpg key handling for github action build
5+
if [[ -n "${GPG_PRIVATE_KEY}" && -n "${GPG_PASSPHRASE}" ]]; then
6+
echo "GPG environment variables validated successfully"
7+
echo "${GPG_PRIVATE_KEY}" | \
8+
gpg --batch \
9+
--yes \
10+
--pinentry-mode loopback \
11+
--passphrase "${GPG_PASSPHRASE}" \
12+
--import
13+
14+
echo -e "#\n# list secret keys\n#\n"
15+
gpg --list-secret-keys --keyid-format LONG
16+
fi
17+
18+
# build
319
./gradlew --no-daemon --version
420
./mvnw --version
521
./gradlew --no-daemon -Dmaven.repo.local=dist/m2 --continue :build "$@"

.github/workflows/cibuild.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ env:
2929
-Daether.connector.http.connectionMaxTtl=25
3030
-Daether.connector.connectTimeout=120000
3131
BNDTOOLS_CORE_TEST_NOJUNITOSGI: true # This test is very flaky on CI
32+
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
33+
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
34+
P2_SIGN: true
35+
P2_SIGN_KEY: ${{ secrets.GPG_KEY_ID }}
36+
P2_SIGN_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
37+
P2_PUB_KEY: ${{ secrets.GPG_PUBLIC_KEY }}
38+
SONATYPE_BEARER: ${{ secrets.SONATYPE_BEARER }}
3239

3340
defaults:
3441
run:

biz.aQute.bnd/src/aQute/bnd/main/bnd.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969

7070
import aQute.bnd.build.Container;
7171
import aQute.bnd.build.Project;
72+
import aQute.bnd.build.Project.ReleaseParameter;
7273
import aQute.bnd.build.ProjectBuilder;
7374
import aQute.bnd.build.ProjectLauncher;
7475
import aQute.bnd.build.ProjectLauncher.LiveCoding;
@@ -1501,11 +1502,18 @@ public void _release(releaseOptions options) throws Exception {
15011502
}
15021503

15031504
}
1504-
for (Project p : projects) {
1505+
1506+
for (Iterator<Project> iterator = projects.iterator(); iterator.hasNext();) {
1507+
Project p = iterator.next();
15051508
if (repo != null) {
15061509
p.setProperty(Constants.RELEASEREPO, repo);
15071510
}
1508-
p.release(options.test());
1511+
if (iterator.hasNext()) {
1512+
p.release(options.test());
1513+
} else {
1514+
// releasing last bundle in workspace
1515+
p.release(new ReleaseParameter(null, options.test(), true));
1516+
}
15091517
}
15101518
if (project != null) {
15111519
getInfo(project);

biz.aQute.bndlib/src/aQute/bnd/build/Project.java

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1142,16 +1142,17 @@ public URI releaseURI(String name, String jarName, InputStream jarStream) throws
11421142
RepositoryPlugin releaseRepo = releaseRepos.get(0); // use only
11431143
// first
11441144
// release repo
1145-
return releaseRepo(releaseRepo, builder, jarName, jarStream);
1145+
return releaseRepo(releaseRepo, builder, jarName, jarStream, false);
11461146
}
11471147
}
11481148

1149-
private URI releaseRepo(RepositoryPlugin releaseRepo, Processor context, String jarName, InputStream jarStream)
1150-
throws Exception {
1149+
private URI releaseRepo(RepositoryPlugin releaseRepo, Processor context, String jarName, InputStream jarStream,
1150+
boolean lastBundleInWorkspace) throws Exception {
11511151
logger.debug("release to {}", releaseRepo.getName());
11521152
try {
11531153
PutOptions putOptions = new RepositoryPlugin.PutOptions();
11541154
// TODO find sub bnd that is associated with this thing
1155+
context.set("startSonatypePublish", Boolean.toString(lastBundleInWorkspace));
11551156
putOptions.context = context;
11561157
PutResult r = releaseRepo.put(jarStream, putOptions);
11571158
logger.debug("Released {} to {} in repository {}", jarName, r.artifact, releaseRepo);
@@ -1213,14 +1214,30 @@ public void release(boolean test) throws Exception {
12131214
* @throws Exception
12141215
*/
12151216
public void release(String name, boolean test) throws Exception {
1216-
List<RepositoryPlugin> releaseRepos = getReleaseRepos(name);
1217+
release(new ReleaseParameter(name, test, false));
1218+
}
1219+
1220+
public static class ReleaseParameter {
1221+
public String name;
1222+
public boolean test;
1223+
public boolean lastBundleInWorkspace;
1224+
1225+
public ReleaseParameter(String name, boolean test, boolean lastBundleInWorkspace) {
1226+
this.name = name;
1227+
this.test = test;
1228+
this.lastBundleInWorkspace = lastBundleInWorkspace;
1229+
}
1230+
}
1231+
1232+
public void release(ReleaseParameter relParam) throws Exception, IOException {
1233+
List<RepositoryPlugin> releaseRepos = getReleaseRepos(relParam.name);
12171234
if (releaseRepos.isEmpty()) {
12181235
return;
12191236
}
12201237
logger.debug("release");
12211238
File[] jars = getBuildFiles(false);
12221239
if (jars == null) {
1223-
jars = build(test);
1240+
jars = build(relParam.test);
12241241
// If build fails jars will be null
12251242
if (jars == null) {
12261243
logger.debug("no jars built");
@@ -1232,9 +1249,17 @@ public void release(String name, boolean test) throws Exception {
12321249
try (ProjectBuilder builder = getBuilder(null)) {
12331250
builder.init();
12341251
for (RepositoryPlugin releaseRepo : releaseRepos) {
1235-
for (File jar : jars) {
1252+
for (int i = 0; i < jars.length; i++) {
1253+
File jar = jars[i];
12361254
try (InputStream jarStream = new BufferedInputStream(IO.stream(jar))) {
1237-
releaseRepo(releaseRepo, builder, jar.getName(), jarStream);
1255+
if (relParam.lastBundleInWorkspace && i == jars.length - 1) {
1256+
// this is the last jar builded inside bnd workspace
1257+
// and if appropriate "-sub" - the last of builded
1258+
// sub-bundles
1259+
releaseRepo(releaseRepo, builder, jar.getName(), jarStream, true);
1260+
} else {
1261+
releaseRepo(releaseRepo, builder, jar.getName(), jarStream, false);
1262+
}
12381263
}
12391264
}
12401265
}

biz.aQute.repository/src/aQute/bnd/repository/maven/provider/Configuration.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,9 @@ public interface Configuration {
8181
* @return a comma separated list of tags.
8282
*/
8383
String tags();
84+
85+
/**
86+
* @return SonatypeMode for this repository none, manual or autopublish
87+
*/
88+
SonatypeMode sonatypeMode(String deflt);
8489
}

biz.aQute.repository/src/aQute/bnd/repository/maven/provider/MavenBndRepository.java

Lines changed: 68 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import java.io.UnsupportedEncodingException;
1313
import java.net.URI;
1414
import java.net.URLDecoder;
15+
import java.util.ArrayList;
1516
import java.util.Arrays;
1617
import java.util.Collection;
1718
import java.util.Collections;
@@ -99,13 +100,19 @@
99100
@BndPlugin(name = "MavenBndRepository", parameters = Configuration.class)
100101
public class MavenBndRepository extends BaseRepository implements RepositoryPlugin, RegistryPlugin, Plugin, Closeable,
101102
Refreshable, Actionable, ToDependencyPom, ReleaseBracketingPlugin {
102-
final static Pattern PREPROCESS_P = Pattern.compile("\\{\\s*(?<core>[^}]+)\\s*\\}");
103103

104-
private final static Logger logger = LoggerFactory.getLogger(MavenBndRepository.class);
105-
private static final int DEFAULT_POLL_TIME = 5;
104+
public static final String SONATYPE_RELEASE_DIR = "cnf/cache/sonatype-release";
105+
public static final String SONATYPE_DEPLOYMENTID_FILE = "deploymendID.txt";
106106

107-
private static final String NONE = "NONE";
108-
private static final String MAVEN_REPO_LOCAL = System.getProperty("maven.repo.local",
107+
final static Pattern PREPROCESS_P = Pattern
108+
.compile("\\{\\s*(?<core>[^}]+)\\s*\\}");
109+
110+
private final static Logger logger = LoggerFactory
111+
.getLogger(MavenBndRepository.class);
112+
private static final int DEFAULT_POLL_TIME = 5;
113+
114+
private static final String NONE = "NONE";
115+
private static final String MAVEN_REPO_LOCAL = System.getProperty("maven.repo.local",
109116
"~/.m2/repository");
110117
private Configuration configuration;
111118
private Registry registry;
@@ -115,16 +122,16 @@ public class MavenBndRepository extends BaseRepository implements RepositoryPlug
115122
private boolean inited;
116123
IndexFile index;
117124
private ScheduledFuture<?> indexPoller;
118-
private RepoActions actions = new RepoActions(this);
125+
private RepoActions actions = new RepoActions(this);
119126
private String name;
120127
private HttpClient client;
121-
private ReleasePluginImpl releasePlugin = new ReleasePluginImpl(this, null);
122-
private File base = IO.work;
123-
private String status = null;
128+
private ReleasePluginImpl releasePlugin = new ReleasePluginImpl(this, null);
129+
private File base = IO.work;
130+
private String status = null;
124131
private boolean remote;
125-
private final AtomicReference<Throwable> open = new AtomicReference<>();
132+
private final AtomicReference<Throwable> open = new AtomicReference<>();
126133
Optional<Workspace> workspace;
127-
private AtomicBoolean polling = new AtomicBoolean(false);
134+
private AtomicBoolean polling = new AtomicBoolean(false);
128135

129136
/**
130137
* Put result
@@ -282,8 +289,7 @@ private void doExtra(PutOptions options, ReleaseDTO instructions, IPom pom, Rele
282289
String clazz = extra.clazz;
283290
File file = new File(path);
284291
if (!file.isFile())
285-
reporter.error("-release-maven archive contains a path to a file that does not exist: %s",
286-
file);
292+
reporter.error("-release-maven archive contains a path to a file that does not exist: %s", file);
287293
else {
288294
try (Resource r = new FileResource(file)) {
289295
Resource what;
@@ -487,7 +493,6 @@ private ReleaseDTO getReleaseDTO(Processor context) {
487493
release.passphrase = sign.get("passphrase");
488494
}
489495

490-
491496
int clazz = 0;
492497

493498
for (Iterator<Entry<String, Attrs>> it = p.entrySet()
@@ -515,8 +520,7 @@ private ReleaseDTO getReleaseDTO(Processor context) {
515520
.getAbsolutePath();
516521
} else {
517522
reporter.warning(
518-
"The -maven-release instruction has an 'archive' without the path attribute: %s",
519-
e);
523+
"The -maven-release instruction has an 'archive' without the path attribute: %s", e);
520524
continue;
521525
}
522526
extra.path = path;
@@ -649,18 +653,48 @@ synchronized boolean init() {
649653
inited = true;
650654

651655
try {
652-
List<MavenBackingRepository> release = MavenBackingRepository.create(configuration.releaseUrl(), reporter,
653-
localRepo, client);
654-
List<MavenBackingRepository> snapshot = MavenBackingRepository.create(configuration.snapshotUrl(), reporter,
655-
localRepo, client);
656-
656+
List<MavenBackingRepository> release = new ArrayList<MavenBackingRepository>();
657657
MavenBackingRepository staging = null;
658658

659-
if (configuration.stagingUrl() != null) {
660-
staging = MavenBackingRepository.getBackingRepository(configuration.stagingUrl(),
661-
reporter, localRepo, client);
659+
String releaseUrl = configuration.releaseUrl();
660+
SonatypeMode sonatypeMode = configuration.sonatypeMode(SonatypeMode.NONE.name());
661+
662+
String stagingUrl = configuration.stagingUrl();
663+
664+
String sonatypeUrl = null;
665+
switch (sonatypeMode) {
666+
case MANUAL, AUTOPUBLISH -> {
667+
logger.info("deployment via Sonatype Central Portal configured in {} mode", sonatypeMode);
668+
File releaseDir = registry.getPlugin(Workspace.class)
669+
.getFile(SONATYPE_RELEASE_DIR);
670+
if (stagingUrl == null) {
671+
logger.debug("deployment via relase url to Sonatype Portal configured");
672+
List<MavenBackingRepository> releaseLocal = MavenBackingRepository.create(releaseDir.toURI()
673+
.toString(), reporter, localRepo, client);
674+
release.addAll(releaseLocal);
675+
sonatypeUrl = releaseUrl;
676+
} else {
677+
logger.debug("deployment via staging url to Sonatype Portal configured");
678+
release = MavenBackingRepository.create(releaseUrl, reporter, localRepo, client);
679+
staging = MavenBackingRepository.getBackingRepository(releaseDir.toURI()
680+
.toString(), reporter, localRepo, client);
681+
sonatypeUrl = stagingUrl;
682+
}
683+
}
684+
case NONE -> {
685+
if (stagingUrl == null) {
686+
release = MavenBackingRepository.create(releaseUrl, reporter, localRepo, client);
687+
} else {
688+
release = MavenBackingRepository.create(releaseUrl, reporter, localRepo, client);
689+
staging = MavenBackingRepository.getBackingRepository(configuration.stagingUrl(), reporter,
690+
localRepo, client);
691+
}
692+
}
662693
}
663694

695+
List<MavenBackingRepository> snapshot = MavenBackingRepository.create(configuration.snapshotUrl(), reporter,
696+
localRepo, client);
697+
664698
for (MavenBackingRepository mbr : release) {
665699
if (mbr.isRemote()) {
666700
remote = true;
@@ -675,9 +709,13 @@ synchronized boolean init() {
675709
}
676710
}
677711

678-
storage = new MavenRepository(localRepo, name, release, staging, snapshot,
679-
client.promiseFactory()
712+
storage = new MavenRepository(localRepo, name, release, staging, snapshot, client.promiseFactory()
680713
.executor(), reporter);
714+
MavenRepository storageMvn = (MavenRepository) storage;
715+
storageMvn.setSonatypeMode(sonatypeMode);
716+
if (sonatypeUrl != null) {
717+
storageMvn.setSonatypePublisherUrl(sonatypeUrl);
718+
}
681719

682720
File indexFile = getIndexFile();
683721
Processor domain = (registry != null) ? registry.getPlugin(Processor.class) : null;
@@ -1085,4 +1123,8 @@ public boolean isRemote() {
10851123
return remote;
10861124
}
10871125

1126+
public HttpClient getClient() {
1127+
return client;
1128+
}
1129+
10881130
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package aQute.bnd.repository.maven.provider;
2+
3+
public enum SonatypeMode {
4+
5+
/*
6+
* No special Sonatype Portal handling
7+
*/
8+
NONE("none"),
9+
10+
/*
11+
* Manual mode where artifacts are staged but not published
12+
*/
13+
MANUAL("manual"),
14+
15+
/*
16+
* Automatic publishing after upload and validatíon
17+
*/
18+
AUTOPUBLISH("autopublish");
19+
20+
private final String value;
21+
22+
SonatypeMode(String value) {
23+
this.value = value;
24+
}
25+
26+
@Override
27+
public String toString() {
28+
return value;
29+
}
30+
}

biz.aQute.repository/src/aQute/maven/provider/MavenBackingRepository.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,9 @@ static public MavenBackingRepository getBackingRepository(String url, Reporter r
231231
if (uri.getScheme()
232232
.equalsIgnoreCase("file")) {
233233
File remote = new File(uri);
234-
return new MavenFileRepository(localRepo, remote, reporter);
234+
MavenFileRepository fileRepo = new MavenFileRepository(localRepo, remote, reporter);
235+
fileRepo.setClient(client);
236+
return fileRepo;
235237
} else {
236238
return new MavenRemoteRepository(localRepo, client, url, reporter);
237239
}

0 commit comments

Comments
 (0)