diff --git a/core/src/test/java/org/alfresco/util/VersionNumberTest.java b/core/src/test/java/org/alfresco/util/VersionNumberTest.java index 3a1bd79b60..5699708bb2 100644 --- a/core/src/test/java/org/alfresco/util/VersionNumberTest.java +++ b/core/src/test/java/org/alfresco/util/VersionNumberTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2010 Alfresco Software Limited. + * Copyright (C) 2005-2020 Alfresco Software Limited. * * This file is part of Alfresco * @@ -74,6 +74,22 @@ public class VersionNumberTest extends TestCase { // OK } + try + { + new VersionNumber("1.2.3-M4"); + fail("Should not have created an invalid version"); + } catch (Exception exception) + { + // OK + } + try + { + new VersionNumber("1.2.3-A4"); + fail("Should not have created an invalid version"); + } catch (Exception exception) + { + // OK + } } public void testEquals() diff --git a/repository/src/main/java/org/alfresco/repo/module/ModuleVersionNumber.java b/repository/src/main/java/org/alfresco/repo/module/ModuleVersionNumber.java index b8c0728611..a73f84fdc0 100644 --- a/repository/src/main/java/org/alfresco/repo/module/ModuleVersionNumber.java +++ b/repository/src/main/java/org/alfresco/repo/module/ModuleVersionNumber.java @@ -1,34 +1,36 @@ -/* - * #%L - * Alfresco Repository - * %% - * Copyright (C) 2005 - 2016 Alfresco Software Limited - * %% - * This file is part of the Alfresco software. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * Alfresco is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Alfresco is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Alfresco. If not, see . - * #L% - */ +/* + * #%L + * Alfresco Repository + * %% + * Copyright (C) 2005 - 2020 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ package org.alfresco.repo.module; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.alfresco.util.VersionNumber; import org.apache.maven.artifact.versioning.ComparableVersion; @@ -49,7 +51,11 @@ public class ModuleVersionNumber implements Externalizable public static final ModuleVersionNumber VERSION_ZERO = new ModuleVersionNumber("0");; public static final ModuleVersionNumber VERSION_BIG = new ModuleVersionNumber("999.999.999.99"); - + + // Matches versions with 3 or 4 parts to their basic number such as 1.2.3 or 1.2.3.4 + // that also optionally have a -A9 -M9 or -RC9 suffix whe 9 is an integer. + private static Pattern A_M_RC_VERSION_PATTERN = Pattern.compile("((\\d+\\.){2,3}\\d+)(-(A|M|RC)\\d+)?"); + protected ComparableVersion delegate; public ModuleVersionNumber() @@ -67,11 +73,56 @@ public class ModuleVersionNumber implements Externalizable this(versionCurrent.toString()); } + /** + * Now that we create internal releases of the form {@code M.m.r-M9} (milestone), {@code M.m.r-A9} (alpha) and + * {@code M.m.r-RC9} (release candidate) during development and testing, we need to ensure we can upgrade from any + * of these to any other, as they may occur in any order and also to the final external release {@code M.m.r}. We + * also will allow a change from the final release back to an internal one for regression testing. + * + * The code within {@link ModuleComponentHelper} which calls this method, checks if it is the same version + * ({@code 0}) and then if it is downgrading ({@code > 0}), so if they share the same {@code M.m.r} part matches + * AND is one of these formats, we return {@code <0}. + * + * @param installingVersion the new version + * @return a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than + * the specified object. + */ public int compareTo(ModuleVersionNumber installingVersion) { + String thisVersion = toString(); + String thatVersion = installingVersion.toString(); + if (thisVersion.equals(thatVersion)) + { + return 0; + } + + String thisVersionWithoutSuffix = getVersionWithoutSuffix(); + if (thisVersionWithoutSuffix != null) + { + String thatVersionWithoutSuffix = installingVersion.getVersionWithoutSuffix(); + if (thisVersionWithoutSuffix.equals(thatVersionWithoutSuffix)) + { + return -1; + } + } + return delegate.compareTo(installingVersion.delegate); } + String getVersionWithoutSuffix() + { + String versionWithoutAMOrRc = null; + String fullVersion = toString(); + Matcher matcher = A_M_RC_VERSION_PATTERN.matcher(fullVersion); + if (matcher.matches()) + { + versionWithoutAMOrRc = matcher.group(1); + // matcher.group(3) would be the suffix, such as "-M4" + // matcher.group(4) would be the type of release: "RC", "A" or "M" + } + return versionWithoutAMOrRc; + } + @Override public int hashCode() { @@ -114,6 +165,4 @@ public class ModuleVersionNumber implements Externalizable String versionString = in.readUTF(); delegate = new ComparableVersion(versionString); } - - } diff --git a/repository/src/test/java/org/alfresco/AllUnitTestsSuite.java b/repository/src/test/java/org/alfresco/AllUnitTestsSuite.java index 6840d989e1..7b66418b17 100644 --- a/repository/src/test/java/org/alfresco/AllUnitTestsSuite.java +++ b/repository/src/test/java/org/alfresco/AllUnitTestsSuite.java @@ -2,7 +2,7 @@ * #%L * Alfresco Repository * %% - * Copyright (C) 2005 - 2017 Alfresco Software Limited + * Copyright (C) 2005 - 2020 Alfresco Software Limited * %% * This file is part of the Alfresco software. * If the software was purchased under a paid Alfresco license, the terms of @@ -79,6 +79,7 @@ import org.junit.runners.Suite; org.alfresco.service.cmr.calendar.CalendarRecurrenceHelperTest.class, org.alfresco.service.cmr.calendar.CalendarTimezoneHelperTest.class, org.alfresco.tools.RenameUserTest.class, + org.alfresco.util.VersionNumberTest.class, org.alfresco.util.FileNameValidatorTest.class, org.alfresco.util.HttpClientHelperTest.class, org.alfresco.util.JSONtoFmModelTest.class, diff --git a/repository/src/test/java/org/alfresco/repo/module/ModuleVersionNumberTest.java b/repository/src/test/java/org/alfresco/repo/module/ModuleVersionNumberTest.java index af609d6699..ac25191215 100644 --- a/repository/src/test/java/org/alfresco/repo/module/ModuleVersionNumberTest.java +++ b/repository/src/test/java/org/alfresco/repo/module/ModuleVersionNumberTest.java @@ -2,7 +2,7 @@ * #%L * Alfresco Repository * %% - * Copyright (C) 2005 - 2016 Alfresco Software Limited + * Copyright (C) 2005 - 2020 Alfresco Software Limited * %% * This file is part of the Alfresco software. * If the software was purchased under a paid Alfresco license, the terms of @@ -230,4 +230,87 @@ public class ModuleVersionNumberTest extends TestCase ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray())); return (ModuleVersionNumber) objectInputStream.readObject(); } + + // Tests that we can strip the suffixes such as "-M2", "-A12" or "-RC2" from versions "7.0.0-M2", "6.2.2-A12", "7.0.1-RC2" + // The main version may contain 3 or 4 digit parts. + public void testGetVersionWithoutSuffix() + { + for (String[] pair: new String[][] + {{null, "1.2"}, + {"1.2.3", "1.2.3"}, + {"1.2.3.4", "1.2.3.4"}, + {null, "1.2.3.4.5"}, + + {"1.2.3", "1.2.3-M4"}, + {"1.2.3.4", "1.2.3.4-A56"}, + {"1.2.3", "1.2.3-RC456"}, + {"11.22.33.44", "11.22.33.44-A5"}, + + {null, "1.2.3-456"}, + {null, "1.2.3-X12"}, + + {null, "1.2.5-A6-A6"}, + {null, "1.2.3.4.5-A6"}, + {null, "1.2-M3"}, + + {null, "1.2.3-RCA-45"}, + {null, "1.2.3-AM4"}, + + {null, "1.2.3-A56A"}, + }) + { + String expected = pair[0]; + String value = pair[1]; + ModuleVersionNumber version = new ModuleVersionNumber(value); + String actual = version.getVersionWithoutSuffix(); + assertEquals(expected, actual); + } + } + + public void testInternalVersionsAreUpgrades() + { + for (String[] pair: new String[][] + // same base version with an optional special suffix (-A9, -M9, -RC9) + {{"upgrade", "7.0.0-A10", "7.0.0"}, + {"upgrade", "7.0.0", "7.0.0-A11"}, + {"upgrade", "7.0.0-A10", "7.0.0-A12"}, + {"upgrade", "7.0.0-A13", "7.0.0-M1"}, + {"upgrade", "7.0.0-A13", "7.0.0-RC1"}, + + // Just the same version + {"same", "7.0.0", "7.0.0"}, + {"same", "7.0.0-A14", "7.0.0-A14"}, + + // Normal versions using standard maven compare + {"downgrade", "7.0.0", "6.2.3"}, + {"upgrade", "6.2.3", "7.0.0"}, + + // standard maven compare - note sure these even make sense as these are not maven format versions! + {"upgrade", "7.0.0-A15", "7.0.0-1234"}, + {"downgrade", "7.0.0-1234", "7.0.0-M2"}, + {"downgrade", "7.0.0-Rubbish1", "7.0.0-M3"}, + {"upgrade", "7.0.0-A16", "7.0.0-Rubbish2"} + }) + { + String expected = pair[0]; + + String value1 = pair[1]; + String value2 = pair[2]; + ModuleVersionNumber thisVersion = new ModuleVersionNumber(value1); + ModuleVersionNumber thatVersion = new ModuleVersionNumber(value2); + int actual = thisVersion.compareTo(thatVersion); + if ("downgrade".equals(expected)) + { + assertTrue("Expected "+thisVersion+" to be a downgrade "+thatVersion+" ("+actual+")", actual > 0); + } + else if ("same".equals(expected)) + { + assertTrue("Expected "+thisVersion+" to be the same base version as "+thatVersion+" ("+actual+")", actual == 0); + } + else if ("upgrade".equals(expected)) + { + assertTrue("Expected "+thisVersion+" to be an upgrade from "+thatVersion+" ("+actual+")", actual < 0); + } + } + } }