Skip to content

Commit

Permalink
Merge pull request #254 from zero88/feature/add-jooqx-version-utils
Browse files Browse the repository at this point in the history
Feature/add jooqx version utils
  • Loading branch information
zero88 authored Jun 27, 2024
2 parents 272fd81 + 8314f70 commit 0547a6c
Show file tree
Hide file tree
Showing 8 changed files with 218 additions and 10 deletions.
2 changes: 1 addition & 1 deletion .github_changelog_generator
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
base=CHANGELOG.md
breaking-labels=breaking-changes
bug-labels=T: Bug
exclude-tags-regex=(jpa|rsql|docs\/.+)\/v.+
exclude-tags-regex=(jpa|rsql|(docs\/.+))\/v.+
exclude-labels=R: Duplicate,R: Invalid,R: Wontfix,T: Question,!release-note,Project: jpa,Project: rsql
enhancement-labels=T: Improvement,T: Feature
exclude-tags=v2.0.0-rc2,v2.0.0-rc2+2
4 changes: 1 addition & 3 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ subprojects {
}
}
}

val buildVersion = when (jvmRuntime) {
"8" -> if (jvmRelease == "8") "" else "+jvm8"
"11" -> if (jvmRelease == "11") "" else "+jvm11"
Expand All @@ -82,8 +81,7 @@ subprojects {
val semanticVersion = prop(project, "semanticVersion", "")
version = when (semanticVersion) {
"-SNAPSHOT" -> project.version.toString().replace(semanticVersion, buildVersion + semanticVersion)
"" -> project.version.toString() + buildVersion
else -> project.version.toString().replace(semanticVersion, semanticVersion + buildVersion)
else -> "${project.version}$buildVersion"
}

dependencies {
Expand Down
17 changes: 17 additions & 0 deletions core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,17 @@ val bridges = setOf(
setOf("**/datatype/BridgeConverter.java")
)
)
val createVersionFile = tasks.register("createVersionFile") {
group = "build"
// Register the project version as a task input, so Gradle can cache the task
inputs.property("projectVersion", project.version)
// tell Gradle about the output directory
outputs.dir(temporaryDir)

doLast {
File(temporaryDir, "jooqx-version.txt").writeText(project.version.toString(), Charsets.UTF_8)
}
}

sourceSets {
bridges.forEach {
Expand All @@ -73,6 +84,9 @@ sourceSets {
java {
bridges.filter { it.versionConstraint }.forEach { exclude(it.excludes) }
}
resources {
srcDir(createVersionFile.map { it.outputs })
}
}
}

Expand Down Expand Up @@ -103,4 +117,7 @@ tasks {
title = "jOOQx Testing ${project.version} API"
}

test {
systemProperty("jooqx-build-version", project.version)
}
}
126 changes: 126 additions & 0 deletions core/src/main/java/io/github/zero88/jooqx/JooqxVersion.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package io.github.zero88.jooqx;

import static io.github.zero88.jooqx.Utils.brackets;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.Scanner;

import org.jetbrains.annotations.ApiStatus.Internal;
import org.jooq.Constants;

import io.vertx.core.impl.launcher.commands.VersionCommand;
import io.vertx.core.impl.logging.Logger;
import io.vertx.core.impl.logging.LoggerFactory;
import io.vertx.core.json.JsonObject;

/**
* JOOQ.X version
*
* @since 2.0.0
*/
public final class JooqxVersion {

private static final Logger LOGGER = LoggerFactory.getLogger(JooqxVersion.class);
private static String version;
private static String jooqVersion;

private JooqxVersion() { }

/**
* @return {@code jooq.x} version
*/
@Internal
public static String getVersion() {
if (version == null) {
version = loadFromFile();
}
return version;
}

/**
* Query version from the direct dependent libraries: {@code jOOQ}, {@code vert.x}, and combine with {@code jooq.x}
* version
*
* @return versions in JSON format
* @see #getVersion()
*/
public static JsonObject versionComponents() {
return JsonObject.of("jOOQ", getJooqVersion(), "Vert.x", VersionCommand.getVersion(), "jooq.x", getVersion());
}

/**
* Validate the version compatibility between {@code jooq.x} and the direct dependent libraries
*/
public static void validate() {
try {
validateJooq(getVersion(), getJooqVersion());
} catch (IncompatibleVersion ex) {
LOGGER.warn(ex.getMessage());
} catch (Exception ex) {
LOGGER.trace("Validate compatibility version failed", ex);
}
}

static void validateJooq(String jooqxVer, String jooqVersion) {
boolean isJvm8 = jooqxVer.contains("+jvm8");
String[] versions = jooqVersion.split("\\.", 3);
boolean isMajor3 = Objects.equals(versions[0], "3");
int jooqMinor = Integer.parseInt(versions[1]);
if (isMajor3 && isJvm8 == (jooqMinor >= 18)) {
throw new IncompatibleVersion(
"jOOQ.x version" + brackets(jooqxVer) + " is not compatible with jOOQ version" + brackets(jooqVersion) +
". Please refer the documentation: " + docUrl(jooqxVer) + " for more details.");
}
}

private static String docUrl(String jooqxVer) {
String releaseVer = jooqxVer.replace("+jvm8", "");
releaseVer = releaseVer.contains("-SNAPSHOT") ? "main" : releaseVer;
return "https://zero88.github.io/webdocs/jooqx/" + releaseVer + "/core-usage.html#_compatibility_matrix";
}

private static String getJooqVersion() {
if (jooqVersion == null) {
try {
final Class<?> aClass = JooqxVersion.class.getClassLoader().loadClass("org.jooq.Constants");
final Field versionField = aClass.getDeclaredField("VERSION");
jooqVersion = (String) versionField.get(null);
} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException ex) {
LOGGER.debug("Unable to load runtime jOOQ version, fallback to build version", ex);
jooqVersion = Constants.VERSION;
}
}
return jooqVersion;
}

private static String loadFromFile() {
// in build process, version will be auto-inject to manifest by
// `JooqxVersion.class.getPackage().getImplementationVersion()`
// however, fat-jar will override the package version by itself application version
// so load from file is safe choice
LOGGER.debug("Loading `jooq.x` version from file `jooqx-version.txt`...");
try (InputStream is = JooqxVersion.class.getClassLoader().getResourceAsStream("jooqx-version.txt")) {
if (is == null) {
LOGGER.warn("Cannot find jooqx-version.txt on classpath");
return null;
}
try (Scanner scanner = new Scanner(is, StandardCharsets.UTF_8.name()).useDelimiter("\\A")) {
return scanner.hasNext() ? scanner.next().trim() : "";
}
} catch (IOException ex) {
LOGGER.warn("Cannot read jooqx-version.txt on classpath", ex);
return null;
}
}

static class IncompatibleVersion extends RuntimeException {

public IncompatibleVersion(String msg) { super(msg); }

}

}
1 change: 1 addition & 0 deletions core/src/main/java/io/github/zero88/jooqx/SQLImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ abstract static class SQLEI<S, B, PQ extends SQLPreparedQuery<B>, RC extends SQL

protected SQLEI(Vertx vertx, DSLContext dsl, S sqlClient, PQ preparedQuery, RC resultCollector,
SQLErrorConverter errorConverter, DataTypeMapperRegistry typeMapperRegistry) {
JooqxVersion.validate();
this.vertx = vertx;
this.dsl = dsl;
this.sqlClient = sqlClient;
Expand Down
55 changes: 55 additions & 0 deletions core/src/test/java/io/github/zero88/jooqx/JooqxVersionTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package io.github.zero88.jooqx;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

import io.github.zero88.jooqx.JooqxVersion.IncompatibleVersion;
import io.vertx.core.json.JsonObject;

class JooqxVersionTest {

@Test
void test_version_should_be_available() {
final String buildVersion = System.getProperty("jooqx-build-version");
Assertions.assertNotNull(buildVersion);
Assertions.assertEquals(buildVersion, JooqxVersion.getVersion());
}

@Test
void test_version_json_should_be_available() {
final String buildVersion = System.getProperty("jooqx-build-version");
Assertions.assertNotNull(buildVersion);
final JsonObject jsonObject = JooqxVersion.versionComponents();
Assertions.assertEquals(buildVersion, jsonObject.getString("jooq.x"));
Assertions.assertTrue(jsonObject.containsKey("jOOQ"));
Assertions.assertTrue(jsonObject.containsKey("Vert.x"));
}

@ParameterizedTest
//@formatter:off
@CsvSource({
// jooq.x `+jvm8`
"2.0.0+jvm8-SNAPSHOT,3.14.9,true", "2.0.0+jvm8-SNAPSHOT,3.17.26,true", "2.0.0+jvm8-SNAPSHOT,3.18.5,false",
"2.0.0+jvm8,3.14.9,true", "2.0.0+jvm8,3.17.26,true", "2.0.0+jvm8,3.18.5,false",
"2.0.0-rc3+jvm8,3.14.9,true", "2.0.0-rc3+jvm8,3.17.26,true", "2.0.0-rc3+jvm8,3.18.5,false",
"2.0.0+hf1+jvm8,3.14.9,true", "2.0.0+hf1+jvm8,3.17.26,true", "2.0.0+hf1+jvm8,3.18.5,false",
// jooq.x
"2.0.0-SNAPSHOT,3.18.5,true", "2.0.0-SNAPSHOT,3.19.6,true", "2.0.0-SNAPSHOT,3.17.26,false",
"2.0.0,3.18.5,true", "2.0.0,3.19.6,true", "2.0.0,3.17.26,false",
"2.0.0-rc3,3.18.5,true", "2.0.0-rc3,3.19.6,true", "2.0.0-rc3,3.17.26,false",
"2.0.0+hf1,3.18.5,true", "2.0.0+hf1,3.19.6,true", "2.0.0+hf1,3.17.26,false",
})
//@formatter:on
void test_validate_jooq_compatibility_version(String jooqxVersion, String jooqVersion, boolean expected) {
if (expected) {
JooqxVersion.validateJooq(jooqxVersion, jooqVersion);
} else {
Assertions.assertThrows(IncompatibleVersion.class,
() -> JooqxVersion.validateJooq(jooqxVersion, jooqVersion),
"Expected IncompatibleVersion exception");
}
}

}
14 changes: 8 additions & 6 deletions docs/asciidoc/src/antora/pages/core-usage.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -50,25 +50,27 @@ dependencies {
}
----

== Matrix support
== Compatibility Matrix

The table below describe `jooq.x` compatibility with several integrations.

|===
|Java |jOOQ |Vert.x |jooq.x

|`8`
|`<= 3.14.16`
|`\<= 3.14.16`
|`^4.2`
|{jooqx-version}-jvm8
|{jooqx-jvm8-artifact}

|`11`
|`<= 3.16.23`
|`\<= 3.16.23`
|`^4.2`
|{jooqx-version}-jvm8
|{jooqx-jvm8-artifact}

|`17`
|`~3.17.0`
|`^4.2`
|{jooqx-version}-jvm8
|{jooqx-jvm8-artifact}

|`17`
|`^3.18`
Expand Down
9 changes: 9 additions & 0 deletions docs/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import cloud.playio.gradle.shared.prop

@Suppress("DSL_SCOPE_VIOLATION")
plugins {
alias(libs.plugins.antora)
Expand All @@ -10,11 +12,18 @@ subprojects {
}
}

val semanticVersion = prop(project, "semanticVersion", "")
val jvm8Version = when (semanticVersion) {
"-SNAPSHOT" -> project.version.toString().replace(semanticVersion, "+jvm8$semanticVersion")
else -> "${project.version}+jvm8"
}

documentation {
antora {
asciiAttributes.set(
mapOf(
"jooqx-version" to project.version,
"jooqx-jvm8-artifact" to jvm8Version,
"jooq-version" to libs.jooq.get().version,
"vertx-version" to libs.vertxCore.get().version,
"mutiny-version" to libs.mutinyCore.get().version,
Expand Down

0 comments on commit 0547a6c

Please sign in to comment.