Skip to content

Commit

Permalink
Add a flag to allow minor updates (#708)
Browse files Browse the repository at this point in the history
  • Loading branch information
melix authored Jul 12, 2024
1 parent 4ad53dc commit 7acaa1c
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public void apply(Project project) {
task.getIgnoredModules().convention(Collections.emptySet());
task.getRejectedVersionsPerModule().convention(Collections.emptyMap());
task.getAllowMajorUpdates().convention(false);
task.getAllowMinorUpdates().convention(true);
});
tasks.register("useLatestVersions", Copy.class, task -> {
VersionCatalogUpdate dependent = updater.get();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import io.micronaut.build.catalogs.internal.VersionModel;
import org.gradle.api.DefaultTask;
import org.gradle.api.GradleException;
import org.gradle.api.artifacts.ComponentSelection;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.ConfigurationContainer;
import org.gradle.api.artifacts.Dependency;
Expand Down Expand Up @@ -80,6 +81,9 @@ public abstract class VersionCatalogUpdate extends DefaultTask {
@Input
public abstract Property<Boolean> getAllowMajorUpdates();

@Input
public abstract Property<Boolean> getAllowMinorUpdates();

@Input
public abstract MapProperty<String, String> getRejectedVersionsPerModule();

Expand Down Expand Up @@ -134,6 +138,7 @@ private void updateCatalog(File inputCatalog, File outputCatalog, File logFile)
}
List<String> lines = Files.readAllLines(inputCatalog.toPath(), StandardCharsets.UTF_8);
boolean allowMajorUpdate = getAllowMajorUpdates().get();
boolean allowMinorUpdate = getAllowMinorUpdates().get();
VersionCatalogTomlModel model = parser.getModel();
DependencyHandler dependencies = getProject().getDependencies();
ConfigurationContainer configurations = getProject().getConfigurations();
Expand Down Expand Up @@ -181,14 +186,7 @@ private void updateCatalog(File inputCatalog, File outputCatalog, File logFile)
log.println("Rejecting version " + candidateVersion + " because of configuration. It matches regular expression: " + rejected);
}
}
if (!allowMajorUpdate) {
String major = majorVersionOf(required);
String candidateMajor = majorVersionOf(candidateVersion);
if (!major.equals(candidateMajor)) {
rules.reject("Rejecting major version " + candidateMajor);
log.println("Rejecting " + candidateModule.getModuleIdentifier() + " version " + candidateVersion + " because it's not the same major version");
}
}
maybeRejectVersionByMinorMajor(rules, allowMajorUpdate, allowMinorUpdate, required, candidateVersion, log, candidateModule);
}
}
}
Expand Down Expand Up @@ -286,6 +284,31 @@ private void updateCatalog(File inputCatalog, File outputCatalog, File logFile)
}
}

// Visible for testing
static void maybeRejectVersionByMinorMajor(ComponentSelection rules,
boolean allowMajorUpdate,
boolean allowMinorUpdate,
String currentVersion,
String candidateVersion,
PrintWriter log,
ModuleComponentIdentifier candidateModule) {
if (!allowMajorUpdate || !allowMinorUpdate) {
int major = majorVersionOf(currentVersion);
int candidateMajor = majorVersionOf(candidateVersion);
if (major != candidateMajor && !allowMajorUpdate) {
rules.reject("Rejecting major version " + candidateMajor);
log.println("Rejecting " + candidateModule.getModuleIdentifier() + " version " + candidateVersion + " because it's not the same major version");
} else if (major == candidateMajor && !allowMinorUpdate) {
int minor = minorVersionOf(currentVersion);
int candidateMinor = minorVersionOf(candidateVersion);
if (minor!=candidateMinor) {
rules.reject("Rejecting minor version " + candidateMinor);
log.println("Rejecting " + candidateModule.getModuleIdentifier() + " version " + candidateVersion + " because it's not the same minor version");
}
}
}
}

private static String requiredVersionOf(Library library) {
RichVersion version = library.getVersion().getVersion();
if (version != null) {
Expand All @@ -307,11 +330,38 @@ private static PrintWriter newPrintWriter(File file) throws FileNotFoundExceptio
return new PrintWriter(new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8));
}

private static String majorVersionOf(String version) {
static int majorVersionOf(String version) {
int idx = version.indexOf(".");
if (idx < 0) {
return safeParseInt(version);
}
return safeParseInt(version.substring(0, idx));
}

static int minorVersionOf(String version) {
int idx = version.indexOf(".");
if (idx < 0) {
return version;
return 0;
}
var bugfixIdx = version.indexOf(".", idx + 1);
if (bugfixIdx < 0) {
return safeParseInt(version.substring(idx + 1));
}
return safeParseInt(version.substring(idx + 1, bugfixIdx));
}

private static int safeParseInt(String pollutedVersion) {
int idx = 0;
while (idx < pollutedVersion.length() && Character.isDigit(pollutedVersion.charAt(idx))) {
idx++;
}
if (idx == 0) {
return 0;
}
try {
return Integer.parseInt(pollutedVersion.substring(0, idx));
} catch (NumberFormatException ex) {
return 0;
}
return version.substring(0, idx);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package io.micronaut.build.catalogs.tasks

import org.gradle.api.artifacts.ComponentSelection
import org.gradle.api.artifacts.component.ModuleComponentIdentifier
import spock.lang.Specification

import static io.micronaut.build.catalogs.tasks.VersionCatalogUpdate.maybeRejectVersionByMinorMajor

class VersionCatalogUpdateTest extends Specification {
def "test major and minor version extraction"() {
expect:
VersionCatalogUpdate.majorVersionOf(version) == expectedMajor
VersionCatalogUpdate.minorVersionOf(version) == expectedMinor

where:
version | expectedMajor | expectedMinor
"1.2.3" | 1 | 2
"1.2" | 1 | 2
"1" | 1 | 0
"1.2.3.4" | 1 | 2
"3.5-beta" | 3 | 5
"3.5-beta1" | 3 | 5
"2.1.0-rc1" | 2 | 1
"128.256.12" | 128 | 256
// not semantic versioning, edge cases to make sure
// the implementation is robust enough
"abc.def" | 0 | 0
"oh.123noes" | 0 | 123
"" | 0 | 0
"wut" | 0 | 0
}

def "tests rejection rules"() {
def componentSelection = Mock(ComponentSelection)
def log = Stub(PrintWriter)
def id = Stub(ModuleComponentIdentifier) {
getGroup() >> "io.micronaut"
getModule() >> "micronaut-core"
getVersion() >> candidateVersion
}

when:
maybeRejectVersionByMinorMajor(
componentSelection,
allowMajorUpdate,
allowMinorUpdate,
currentVersion,
candidateVersion,
log,
id
)

then:
reject * componentSelection.reject(_)

where:
allowMajorUpdate | allowMinorUpdate | currentVersion | candidateVersion | reject
false | false | '1.0.0' | '2.0.0' | 1
false | false | '1.0.0' | '1.1.0' | 1
false | false | '1.0.0' | '1.0.1' | 0
false | true | '1.0.0' | '1.1.0' | 0
false | true | '1.0.0' | '2.0.0' | 1
true | false | '1.0.0' | '2.0.0' | 0
true | false | '1.0.0' | '1.1.0' | 1
true | false | '1.0.0' | '1.0.1' | 0
true | true | '1.0.0' | '2.0.0' | 0
true | true | '1.0.0' | '1.1.0' | 0
true | true | '1.0.0' | '1.0.1' | 0
}
}

0 comments on commit 7acaa1c

Please sign in to comment.