From ea4e18d347f6f6fa529403576802ad58e6fc5abf Mon Sep 17 00:00:00 2001 From: Alan Davis Date: Mon, 30 Nov 2020 19:54:21 +0000 Subject: [PATCH] ACS-953 Unable to upgrade from ACS-7.0-M1 or ACS-7.0-M2 to ACS-7.0-A12 (#183) * ACS-953 Unable to upgrade from ACS-7.0-M1 or ACS-7.0-M2 to ACS-7.0-A12 Now that we create internal releases of the form M.m.r-M9 (milestone), M.m.r-A9 (alpha) and 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 M.m.r. We also will allow a change from the final release back to an internal one for regression testing. The code within ModuleComponentHelper which calls this method, checks if it is the same version (0) and then if it is downgrading (> 0), so if they share the same M.m.r part matches AND is one of these formats, we return <0. --- .../org/alfresco/util/VersionNumberTest.java | 18 ++- .../repo/module/ModuleVersionNumber.java | 105 +++++++++++++----- .../java/org/alfresco/AllUnitTestsSuite.java | 3 +- .../repo/module/ModuleVersionNumberTest.java | 85 +++++++++++++- 4 files changed, 180 insertions(+), 31 deletions(-) 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); + } + } + } }