2525package io .jenkins .tools .incrementals .enforcer ;
2626
2727import java .util .List ;
28+ import java .util .Objects ;
2829import java .util .regex .Matcher ;
2930import java .util .regex .Pattern ;
31+ import javax .inject .Inject ;
32+ import javax .inject .Named ;
3033import org .apache .maven .AbstractMavenLifecycleParticipant ;
34+ import org .apache .maven .artifact .versioning .ArtifactVersion ;
3135import org .apache .maven .artifact .versioning .DefaultArtifactVersion ;
36+ import org .apache .maven .artifact .versioning .InvalidVersionSpecificationException ;
37+ import org .apache .maven .artifact .versioning .VersionRange ;
38+ import org .apache .maven .enforcer .rule .api .AbstractEnforcerRule ;
3239import org .apache .maven .enforcer .rule .api .EnforcerRuleException ;
33- import org .apache .maven .enforcer .rule .api .EnforcerRuleHelper ;
34- import org .apache .maven .plugin .logging .Log ;
35- import org .apache .maven .plugins .enforcer .AbstractVersionEnforcer ;
40+ import org .codehaus .plexus .PlexusContainer ;
3641import org .codehaus .plexus .classworlds .realm .ClassRealm ;
3742import org .codehaus .plexus .component .repository .exception .ComponentLookupException ;
43+ import org .codehaus .plexus .util .StringUtils ;
3844
3945/**
4046 * Verifies that {@code git-changelist-maven-extension}, if present, is sufficiently new.
4147 */
42- public class RequireExtensionVersion extends AbstractVersionEnforcer {
48+ @ Named ("requireExtensionVersion" )
49+ public class RequireExtensionVersion extends AbstractEnforcerRule {
4350
4451 private static final Pattern ID_PATTERN = Pattern .compile ("\\ QcoreExtension>io.jenkins.tools.incrementals:git-changelist-maven-extension:\\ E(.+)" );
4552
53+ /**
54+ * Specify the required version. Some examples are:
55+ * <ul>
56+ * <li><code>2.0.4</code> Version 2.0.4 and higher (different from Maven meaning)</li>
57+ * <li><code>[2.0,2.1)</code> Versions 2.0 (included) to 2.1 (not included)</li>
58+ * <li><code>[2.0,2.1]</code> Versions 2.0 to 2.1 (both included)</li>
59+ * <li><code>[2.0.5,)</code> Versions 2.0.5 and higher</li>
60+ * <li><code>(,2.0.5],[2.1.1,)</code> Versions up to 2.0.5 (included) and 2.1.1 or higher</li>
61+ * </ul>
62+ *
63+ * @see {@link #setVersion(String)}
64+ * @see {@link #getVersion()}
65+ */
66+ private String version ;
67+
68+ private final PlexusContainer container ;
69+
70+ @ Inject
71+ public RequireExtensionVersion (PlexusContainer container ) {
72+ this .container = Objects .requireNonNull (container );
73+ }
74+
4675 @ Override
47- public void execute (EnforcerRuleHelper erh ) throws EnforcerRuleException {
48- Log log = erh .getLog ();
76+ public void execute () throws EnforcerRuleException {
4977 List <AbstractMavenLifecycleParticipant > participants ;
5078 try {
51- participants = erh . getContainer () .lookupList (AbstractMavenLifecycleParticipant .class );
79+ participants = container .lookupList (AbstractMavenLifecycleParticipant .class );
5280 } catch (ComponentLookupException x ) {
53- log .warn (x );
81+ getLog () .warn (x . getMessage () );
5482 return ;
5583 }
5684 for (AbstractMavenLifecycleParticipant participant : participants ) {
@@ -59,10 +87,113 @@ public void execute(EnforcerRuleHelper erh) throws EnforcerRuleException {
5987 if (loader instanceof ClassRealm ) {
6088 Matcher m = ID_PATTERN .matcher (((ClassRealm ) loader ).getId ());
6189 if (m .matches ()) {
62- enforceVersion (log , "git-changelist-maven-extension" , getVersion (), new DefaultArtifactVersion (m .group (1 )));
90+ enforceVersion ("git-changelist-maven-extension" , getVersion (), new DefaultArtifactVersion (m .group (1 )));
6391 }
6492 }
6593 }
6694 }
6795
96+ /**
97+ * Compares the specified version to see if it is allowed by the defined version range.
98+ *
99+ * @param variableName name of variable to use in messages (Example: "Maven" or "Java" etc).
100+ * @param requiredVersionRange range of allowed versions.
101+ * @param actualVersion the version to be checked.
102+ * @throws EnforcerRuleException the enforcer rule exception
103+ */
104+ // CHECKSTYLE_OFF: LineLength
105+ private void enforceVersion (String variableName , String requiredVersionRange , ArtifactVersion actualVersion )
106+ throws EnforcerRuleException
107+ // CHECKSTYLE_ON: LineLength
108+ {
109+ if (StringUtils .isEmpty (requiredVersionRange )) {
110+ throw new EnforcerRuleException (variableName + " version can't be empty." );
111+ } else {
112+
113+ VersionRange vr ;
114+ String msg = "Detected " + variableName + " Version: " + actualVersion ;
115+
116+ // short circuit check if the strings are exactly equal
117+ if (actualVersion .toString ().equals (requiredVersionRange )) {
118+ getLog ().debug (msg + " is allowed in the range " + requiredVersionRange + "." );
119+ } else {
120+ try {
121+ vr = VersionRange .createFromVersionSpec (requiredVersionRange );
122+
123+ if (containsVersion (vr , actualVersion )) {
124+ getLog ().debug (msg + " is allowed in the range " + toString (vr ) + "." );
125+ } else {
126+ throw new EnforcerRuleException (msg + " is not in the allowed range " + toString (vr ) + "." );
127+ }
128+ } catch (InvalidVersionSpecificationException e ) {
129+ throw new EnforcerRuleException (
130+ "The requested " + variableName + " version " + requiredVersionRange + " is invalid." , e );
131+ }
132+ }
133+ }
134+ }
135+
136+ /**
137+ * Copied from Artifact.VersionRange. This is tweaked to handle singular ranges properly. Currently the default
138+ * containsVersion method assumes a singular version means allow everything. This method assumes that "2.0.4" ==
139+ * "[2.0.4,)"
140+ *
141+ * @param allowedRange range of allowed versions.
142+ * @param theVersion the version to be checked.
143+ * @return true if the version is contained by the range.
144+ */
145+ private static boolean containsVersion (VersionRange allowedRange , ArtifactVersion theVersion ) {
146+ ArtifactVersion recommendedVersion = allowedRange .getRecommendedVersion ();
147+ if (recommendedVersion == null ) {
148+ return allowedRange .containsVersion (theVersion );
149+ } else {
150+ // only singular versions ever have a recommendedVersion
151+ int compareTo = recommendedVersion .compareTo (theVersion );
152+ return (compareTo <= 0 );
153+ }
154+ }
155+
156+ private static String toString (VersionRange vr ) {
157+ // as recommended version is used as lower bound in this context modify the string representation
158+ if (vr .getRecommendedVersion () != null ) {
159+ return "[" + vr .getRecommendedVersion ().toString () + ",)" ;
160+ } else {
161+ return vr .toString ();
162+ }
163+ }
164+
165+ @ Override
166+ public String getCacheId () {
167+ if (StringUtils .isNotEmpty (version )) {
168+ // return the hashcodes of the parameter that matters
169+ return "" + version .hashCode ();
170+ } else {
171+ return "0" ;
172+ }
173+ }
174+
175+ /**
176+ * Gets the required version.
177+ *
178+ * @return the required version
179+ */
180+ public final String getVersion () {
181+ return this .version ;
182+ }
183+
184+ /**
185+ * Specify the required version. Some examples are:
186+ * <ul>
187+ * <li><code>2.0.4</code> Version 2.0.4 and higher (different from Maven meaning)</li>
188+ * <li><code>[2.0,2.1)</code> Versions 2.0 (included) to 2.1 (not included)</li>
189+ * <li><code>[2.0,2.1]</code> Versions 2.0 to 2.1 (both included)</li>
190+ * <li><code>[2.0.5,)</code> Versions 2.0.5 and higher</li>
191+ * <li><code>(,2.0.5],[2.1.1,)</code> Versions up to 2.0.5 (included) and 2.1.1 or higher</li>
192+ * </ul>
193+ *
194+ * @param theVersion the required version to set
195+ */
196+ public void setVersion (String theVersion ) {
197+ this .version = theVersion ;
198+ }
68199}
0 commit comments