Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ stage('Build') {
// Use withEnv instead of setting env directly, as that is global!
// See https://github.com/jenkinsci/pipeline-plugin/blob/master/TUTORIAL.md
withEnv(["JAVA_HOME=${javaHome}", "PATH+JAVA=${javaHome}/bin"]) {
state[buildEnv.tag]['additionalOptions'] = '-PmavenMirror=nexus-load-balancer-c4cf05fd92f43ef8.elb.us-east-1.amazonaws.com'
state[buildEnv.tag]['additionalOptions'] = ''
if ( buildEnv.mainJdkVersion ) {
state[buildEnv.tag]['additionalOptions'] = state[buildEnv.tag]['additionalOptions'] +
" -Pmain.jdk.version=${buildEnv.mainJdkVersion}"
Expand Down Expand Up @@ -387,4 +387,4 @@ static def tryFinally(Closure main, Closure ... finallies) {
if ( mainFailure ) { // We may reach here if only the "finally" failed
throw mainFailure
}
}
}
9 changes: 8 additions & 1 deletion MAINTAINERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ Continuous integration is split across two platforms:
* GitHub Actions at https://github.com/hibernate/hibernate-orm/actions
* a self-hosted Jenkins instance at https://ci.hibernate.org.

### Tips

The Hibernate ORM build can use a mirror instead of Maven central.
To do so, set the `MAVEN_MIRROR` environment variable to the URL of your mirror,
e.g. `http://something-on-aws.com/path/to/repo`.
The mirror can use unsecure HTTP, but obviously that exposes you to MITM attacks unless the build runs in a completely isolated network.

### GitHub Actions workflows

TODO: describe the workflows available.
Expand All @@ -32,7 +39,7 @@ It is generally triggered on push,
but can also be triggered manually,
which is particularly useful to test more environments on a pull request.

See [Jenkinsfile](Jenkinsfile) for the job definition.
See [Jenkinsfile](Jenkinsfile) for the job definition.

### Release pipeline

Expand Down
4 changes: 2 additions & 2 deletions ci/jpa-3.2-tck.Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@ pipeline {
withEnv([
"DISABLE_REMOTE_GRADLE_CACHE=true"
]) {
sh './gradlew clean publishToMavenLocal -x test --no-scan --no-daemon --no-build-cache --stacktrace -PmavenMirror=nexus-load-balancer-c4cf05fd92f43ef8.elb.us-east-1.amazonaws.com'
sh './gradlew clean publishToMavenLocal -x test --no-scan --no-daemon --no-build-cache --stacktrace'
// For some reason, Gradle does not publish hibernate-platform and hibernate-testing
// to the local maven repository with the previous command,
// but requires an extra run instead
sh './gradlew :hibernate-testing:publishToMavenLocal :hibernate-platform:publishToMavenLocal -x test --no-scan --no-daemon --no-build-cache --stacktrace -PmavenMirror=nexus-load-balancer-c4cf05fd92f43ef8.elb.us-east-1.amazonaws.com'
sh './gradlew :hibernate-testing:publishToMavenLocal :hibernate-platform:publishToMavenLocal -x test --no-scan --no-daemon --no-build-cache --stacktrace'
}
script {
env.HIBERNATE_VERSION = sh (
Expand Down
2 changes: 1 addition & 1 deletion ci/quarkus.Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ pipeline {
script {
dir('hibernate') {
checkout scm
sh "./gradlew clean publishToMavenLocal -x test --no-scan --no-daemon --no-build-cache --stacktrace -PmavenMirror=nexus-load-balancer-c4cf05fd92f43ef8.elb.us-east-1.amazonaws.com -Dmaven.repo.local=${env.WORKSPACE_TMP}/.m2repository"
sh "./gradlew clean publishToMavenLocal -x test --no-scan --no-daemon --no-build-cache --stacktrace -Dmaven.repo.local=${env.WORKSPACE_TMP}/.m2repository"
script {
env.HIBERNATE_VERSION = sh (
script: "grep hibernateVersion gradle/version.properties|cut -d'=' -f2",
Expand Down
15 changes: 11 additions & 4 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,18 @@ plugins {

dependencyResolutionManagement {
repositories {
if ( rootProject.hasProperty( "mavenMirror" ) ) {
url( rootProject.property( "mavenMirror" ) )
// See MAINTAINERS.md for documentation.
// TODO Move to infra overrides instead;
// see https://blog.gradle.org/maven-central-mirror#overriding-the-urls-for-maven-central-and-the-plugin-portal-repositories
if ( System.env['MAVEN_MIRROR'] ) {
maven {
url System.env['MAVEN_MIRROR']
allowInsecureProtocol = true
}
}
else {
mavenCentral()
}

mavenCentral()

if (System.getProperty('JPA_PREVIEW') != null) {
maven {
Expand Down
7 changes: 5 additions & 2 deletions tooling/hibernate-maven-plugin/hibernate-maven-plugin.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ tasks.register('integrationTest', Test) {
shouldRunAfter test

useJUnitPlatform()

}

tasks.forbiddenApisIntTest {
Expand Down Expand Up @@ -85,8 +84,12 @@ publishingExtension.publications.named("publishedArtifacts") {

integrationTest {
environment "hibernateVersion", project.version
testLogging {
exceptionFormat = 'full'
}
}

integrationTest.dependsOn rootProject.childProjects.'hibernate-core'.tasks.publishToMavenLocal
integrationTest.dependsOn project(':hibernate-core').tasks.publishToMavenLocal
integrationTest.dependsOn ":hibernate-platform:publishToMavenLocal"
integrationTest.dependsOn publishToMavenLocal
check.dependsOn integrationTest
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.orm.tooling.maven;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.apache.maven.cli.MavenCli;
import org.codehaus.plexus.classworlds.ClassWorld;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;

public abstract class AbstractMavenTestIT {

protected static final String MVN_HOME = "maven.multiModuleProjectDirectory";

private static ClassWorld classWorld;
private static MavenCli mavenCli;
private static Path mavenSettingsFile;

@BeforeAll
public static void initMavenCli() throws Exception {
classWorld = new ClassWorld( "plexus.core", Thread.currentThread().getContextClassLoader() );
mavenCli = new MavenCli( classWorld );
String mavenMirror = System.getenv( "MAVEN_MIRROR" );
if ( mavenMirror != null && !mavenMirror.isEmpty() ) {
mavenSettingsFile = Files.createTempFile( "maven-settings", ".xml" );
Files.writeString( mavenSettingsFile,
"<settings>\n" +
" <mirrors>\n" +
" <mirror>\n" +
" <id>ci-mirror</id>\n" +
" <mirrorOf>central</mirrorOf>\n" +
" <url>${env.MAVEN_MIRROR}</url>\n" +
" </mirror>\n" +
" </mirrors>\n" +
"</settings>\n" );
}
}

@AfterAll
public static void closeMavenCli() throws Exception {
classWorld.close();
if ( mavenSettingsFile != null ) {
Files.deleteIfExists( mavenSettingsFile );
mavenSettingsFile = null;
}
}

protected void runMaven(String workingDirectory, String... goals) {
System.setProperty( MVN_HOME, workingDirectory );
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayOutputStream err = new ByteArrayOutputStream();
String[] args;
if ( mavenSettingsFile != null ) {
args = new String[goals.length + 2];
args[0] = "-s";
args[1] = mavenSettingsFile.toAbsolutePath().toString();
System.arraycopy( goals, 0, args, 2, goals.length );
}
else {
args = goals;
}
int result = mavenCli.doMain(
args,
workingDirectory,
new PrintStream( out ),
new PrintStream( err ) );
assertEquals( 0, result,
"Maven invocation failed for goals: " + Arrays.asList( goals )
+ "\n--- stdout ---\n" + out
+ "\n--- stderr ---\n" + err );
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.assertFalse;

import org.apache.maven.cli.MavenCli;
import org.hibernate.bytecode.enhance.spi.EnhancementInfo;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
Expand All @@ -21,20 +21,21 @@
import java.nio.file.Files;
import java.util.List;

public class EnhancerMojoTestIT {

public static final String MVN_HOME = "maven.multiModuleProjectDirectory";
public class EnhancerMojoTestIT extends AbstractMavenTestIT {

@TempDir
File projectDir;

private MavenCli mavenCli;
private URLClassLoader testClassLoader;

@BeforeEach
public void beforeEach() throws Exception {
copyJavFiles();
System.setProperty(MVN_HOME, projectDir.getAbsolutePath());
mavenCli = new MavenCli();
}

@AfterEach
public void afterEach() throws Exception {
destroyTestClassLoader();
}

@Test
Expand Down Expand Up @@ -214,11 +215,7 @@ private void executeCompileGoal() {
assertFalse(fileExists("target/classes/Baz.class"));
assertFalse(fileExists("target/classes/Foo.class"));
// Execute the 'compile' target
new MavenCli().doMain(
new String[]{"compile"},
projectDir.getAbsolutePath(),
null,
null);
runMaven( projectDir.getAbsolutePath(), "compile" );
// The class files should exist now
assertTrue( fileExists( "target/classes/Bar.class" ) );
assertTrue( fileExists( "target/classes/Baz.class" ) );
Expand All @@ -231,16 +228,8 @@ private void executeEnhanceGoal() throws Exception {
assertFalse( isEnhanced( "Baz" ));
assertFalse( isEnhanced( "Foo" ));
// Execute the 'enhance' target
mavenCli.doMain(
new String[]{"process-classes"},
projectDir.getAbsolutePath(),
null,
null);
mavenCli.doMain(
new String[]{"dependency:copy-dependencies"},
projectDir.getAbsolutePath(),
null,
null);
runMaven( projectDir.getAbsolutePath(), "process-classes" );
runMaven( projectDir.getAbsolutePath(), "dependency:copy-dependencies" );
// The results are verified in the respective tests
}

Expand Down Expand Up @@ -278,14 +267,29 @@ private void copyJavFile(String javFileName, File toFolder) throws Exception {
}

private ClassLoader getTestClassLoader() throws Exception {
return new URLClassLoader( new URL[]{
new File(projectDir, "target/classes").toURI().toURL(),
new File(projectDir, "target/dependency/geolatte-geom-1.10.jar").toURI().toURL(),
});
if ( testClassLoader == null ) {
testClassLoader = new URLClassLoader( new URL[] {
new File( projectDir, "target/classes" ).toURI().toURL(),
new File( projectDir, "target/dependency/geolatte-geom-1.10.jar" ).toURI().toURL(),
} );
}
return testClassLoader;
}

private void destroyTestClassLoader() throws Exception {
if ( testClassLoader != null ) {
testClassLoader.close();
testClassLoader = null;
}
}

private boolean isEnhanced(String className) throws Exception {
return getTestClassLoader().loadClass( className ).isAnnotationPresent( EnhancementInfo.class );
try {
return getTestClassLoader().loadClass( className ).isAnnotationPresent( EnhancementInfo.class );
}
finally {
destroyTestClassLoader();
}
}

private boolean methodIsPresentInClass(String methodName, String className) throws Exception {
Expand All @@ -296,30 +300,38 @@ private boolean methodIsPresentInClass(String methodName, String className) thro
} catch (NoSuchMethodException e) {
return false;
}
finally {
destroyTestClassLoader();
}
}

private boolean isAssociationManagementPresent() throws Exception {
// Some dynamic programming
ClassLoader loader = getTestClassLoader();
// Obtain the class objects for 'Baz' and 'Bar'
Class<?> bazClass = loader.loadClass( "Baz" );
Class<?> barClass = loader.loadClass( "Bar" );
// Create an instance of both 'Baz' and 'Bar'
Object bazObject = bazClass.getDeclaredConstructor().newInstance();
Object barObject = barClass.getDeclaredConstructor().newInstance();
// Lookup the 'bars' field of class 'Baz' (an ArrayList of 'Bar' objects)
Field bazBarsField = bazClass.getDeclaredField( "bars" );
bazBarsField.setAccessible( true );
// Obtain the 'bars' list of the 'Baz' object; it should be empty
List<?> bazBarsList = (List<?>) bazBarsField.get( bazObject ); // baz.bars
assertTrue(bazBarsList.isEmpty());
// Lookup the 'setBaz' method of class 'Bar' and invoke it on the 'Bar' object
Method barSetBazMethod = barClass.getDeclaredMethod( "setBaz", new Class[] { bazClass } );
barSetBazMethod.invoke( barObject, bazObject ); // bar.setBaz(baz)
// Reobtain the 'bars' list of the 'Baz' object
bazBarsList = (List<?>) bazBarsField.get( bazObject );
// If there is association management, the 'bars' list should contain the 'Bar' object
return bazBarsList.contains( barObject ); // baz.bars.contains(bar)
try {
// Obtain the class objects for 'Baz' and 'Bar'
Class<?> bazClass = loader.loadClass( "Baz" );
Class<?> barClass = loader.loadClass( "Bar" );
// Create an instance of both 'Baz' and 'Bar'
Object bazObject = bazClass.getDeclaredConstructor().newInstance();
Object barObject = barClass.getDeclaredConstructor().newInstance();
// Lookup the 'bars' field of class 'Baz' (an ArrayList of 'Bar' objects)
Field bazBarsField = bazClass.getDeclaredField( "bars" );
bazBarsField.setAccessible( true );
// Obtain the 'bars' list of the 'Baz' object; it should be empty
List<?> bazBarsList = (List<?>) bazBarsField.get( bazObject ); // baz.bars
assertTrue( bazBarsList.isEmpty() );
// Lookup the 'setBaz' method of class 'Bar' and invoke it on the 'Bar' object
Method barSetBazMethod = barClass.getDeclaredMethod( "setBaz", new Class[] {bazClass} );
barSetBazMethod.invoke( barObject, bazObject ); // bar.setBaz(baz)
// Reobtain the 'bars' list of the 'Baz' object
bazBarsList = (List<?>) bazBarsField.get( bazObject );
// If there is association management, the 'bars' list should contain the 'Bar' object
return bazBarsList.contains( barObject ); // baz.bars.contains(bar)
}
finally {
destroyTestClassLoader();
}
}

private boolean fileExists(String relativePath) {
Expand Down