You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by cz...@apache.org on 2019/09/09 07:19:37 UTC

[sling-slingfeature-maven-plugin] branch master updated: SLING-8689 : Improve version handling

This is an automated email from the ASF dual-hosted git repository.

cziegeler pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-slingfeature-maven-plugin.git


The following commit(s) were added to refs/heads/master by this push:
     new 1bdba86  SLING-8689 : Improve version handling
1bdba86 is described below

commit 1bdba861db12a3f1ce09017887fd1cdf9a7089d3
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Mon Sep 9 09:18:41 2019 +0200

    SLING-8689 : Improve version handling
---
 README.md                                          |  33 ++++
 .../feature/maven/mojos/UpdateVersionsMojo.java    | 192 +++++++++++++++------
 2 files changed, 177 insertions(+), 48 deletions(-)

diff --git a/README.md b/README.md
index cc5964e..279d327 100644
--- a/README.md
+++ b/README.md
@@ -242,6 +242,39 @@ https://github.com/apache/sling-org-apache-sling-feature-analyser/blob/master/sr
 Attach feature files found in the project to the projects produced artifacts. This includes features
 found in `src/main/features` as well as features produce with the `aggregate-features` goal if no configuration is specified.
 
+### update-feature-versions
+
+The update feature versions goal can be used to check for updates of artifacts contained in the features
+that are part of the project.
+
+Without specifying any other arguments, all artifacts will be updated to the latest version found. You can specify
+a dry run to just check if there are updates:
+```
+    mvn slingfeature:update-feature-versions -DdryRun=true
+```
+
+You can specify includes and excludes based on maven coordinates to further redefine which artifacts to update.
+The most common use case is to specify the group id only. For example if you want to update only artifacts
+with the Sling group id, use this command:
+```
+    mvn slingfeature:update-feature-versions -DdryRun=true -Dincludes=org.apache.sling
+```
+You can specify several includes and excludes by separating them by comma.
+
+It's also possible to define the version scope, which means the policy how to update. By default *ANY* is used,
+meaning the latest found version (excluding snapshots) is used. You can also specify *MAJOR*, *MINOR*, *INCREMENTAL*
+and *SUBINCREMENTAL* by using the `versionScope` parameter.
+
+Alternative you can combine this with the includes and specify a different scope per include:
+```
+    mvn slingfeature:update-feature-versions -DdryRun=true -Dincludes=org.apache.sling/MAJOR,org.apache.felix/INCREMENTAL
+```
+
+With an include you can also specify an exact version:
+```
+    mvn slingfeature:update-feature-versions -DdryRun=true -Dincludes=org.apache.jackrabbit.oak/4.0.2
+```
+
 ### repository
 
 With the repository goal, a directory with all artifacts from the selected features will be created.
diff --git a/src/main/java/org/apache/sling/feature/maven/mojos/UpdateVersionsMojo.java b/src/main/java/org/apache/sling/feature/maven/mojos/UpdateVersionsMojo.java
index f8d243c..f2d940b 100644
--- a/src/main/java/org/apache/sling/feature/maven/mojos/UpdateVersionsMojo.java
+++ b/src/main/java/org/apache/sling/feature/maven/mojos/UpdateVersionsMojo.java
@@ -90,6 +90,13 @@ public class UpdateVersionsMojo extends AbstractIncludingFeatureMojo {
     private String updatesExcludesList;
 
     /**
+     * The scope to use to find the highest version, use ANY, MAJOR, MINOR,
+     * INCREMENTAL, or SUBINCREMENTAL
+     */
+    @Parameter(property = "versionScope")
+    private String versionScope;
+
+    /**
      * If set to true, no changes are performed
      */
     @Parameter(defaultValue = "false", property = "dryRun")
@@ -128,23 +135,44 @@ public class UpdateVersionsMojo extends AbstractIncludingFeatureMojo {
         return matches;
     }
 
+    /**
+     * Get the raw features (not the assembled ones)
+     *
+     * @return Map with the features
+     * @throws MojoExecutionException
+     */
     private Map<String, Feature> getFeatures() throws MojoExecutionException {
-        return this.selectAllFeatureFiles();
+        final Map<String, Feature> features = new HashMap<>();
+        for (final Map.Entry<String, Feature> entry : this.selectAllFeatureFiles().entrySet()) {
+            features.put(entry.getKey(), ProjectHelper.getFeatures(project).get(entry.getKey()));
+        }
+        if (features.isEmpty()) {
+            throw new MojoExecutionException("No features found in project!");
+        }
+        return features;
     }
 
-    private void addDependencies(final Set<Dependency> dependencies, final List<Artifact> artifacts) {
+    private void addDependencies(final Set<Dependency> dependencies, final List<Artifact> artifacts,
+            final UpdateConfig cfg) {
         for (final Artifact a : artifacts) {
-            dependencies.add(ProjectHelper.toDependency(a.getId(), org.apache.maven.artifact.Artifact.SCOPE_PROVIDED));
+            final String versionInfo = shouldHandle(a.getId(), cfg);
+            if (versionInfo != null) {
+                final Dependency dep = ProjectHelper.toDependency(a.getId(),
+                        org.apache.maven.artifact.Artifact.SCOPE_PROVIDED);
+                // we store the version info as system path as this seems to be very useful...
+                dep.setSystemPath(versionInfo);
+                dependencies.add(dep);
+            }
         }
     }
 
-    private Set<Dependency> getDependencies(final Map<String, Feature> features) {
+    private Set<Dependency> getDependencies(final Map<String, Feature> features, final UpdateConfig cfg) {
         final Set<Dependency> dependencies = new TreeSet<>(new DependencyComparator());
         for (final Map.Entry<String, Feature> entry : features.entrySet()) {
-            addDependencies(dependencies, entry.getValue().getBundles());
+            addDependencies(dependencies, entry.getValue().getBundles(), cfg);
             for (final Extension ext : entry.getValue().getExtensions()) {
                 if (ext.getType() == ExtensionType.ARTIFACTS) {
-                    addDependencies(dependencies, ext.getArtifacts());
+                    addDependencies(dependencies, ext.getArtifacts(), cfg);
                 }
             }
         }
@@ -161,36 +189,50 @@ public class UpdateVersionsMojo extends AbstractIncludingFeatureMojo {
         }
     }
 
+    private UpdateConfig createConfiguration() throws MojoExecutionException {
+        final UpdateConfig cfg = new UpdateConfig();
+
+        // get includes and excludes
+        cfg.includes = parseMatches(updatesIncludesList, "includes");
+        // check for version info
+        if (cfg.includes != null) {
+            cfg.includeVersionInfo = new ArrayList<>();
+            for (final String[] include : cfg.includes) {
+                final int lastIndex = include.length - 1;
+                final int pos = include[lastIndex].indexOf('/');
+                if (pos != -1) {
+                    cfg.includeVersionInfo.add(include[lastIndex].substring(pos + 1));
+                    include[lastIndex] = include[lastIndex].substring(0, pos);
+                } else {
+                    cfg.includeVersionInfo.add("");
+                }
+            }
+        }
+        cfg.excludes = parseMatches(updatesExcludesList, "excludes");
+
+        return cfg;
+    }
+
     @Override
     public void execute() throws MojoExecutionException, MojoFailureException {
         checkPreconditions();
-        // get the features
-        final Map<String, Feature> assembledFeatures = this.getFeatures();
-        if (assembledFeatures.isEmpty()) {
-            throw new MojoExecutionException("No features found in project!");
-        }
 
-        final Map<String, Feature> features = new HashMap<>();
-        for (final Map.Entry<String, Feature> entry : assembledFeatures.entrySet()) {
-            features.put(entry.getKey(), ProjectHelper.getFeatures(project).get(entry.getKey()));
-        }
+        // Get the raw features
+        final Map<String, Feature> features = this.getFeatures();
 
-        // create config
-        final UpdateConfig cfg = new UpdateConfig();
+        // Create config
+        final UpdateConfig cfg = this.createConfiguration();
 
         // Calculate dependencies for features
-        final Set<Dependency> dependencies = getDependencies(features);
-        // get updates
+        final Set<Dependency> dependencies = getDependencies(features, cfg);
+
+        // Get updates
         try {
             cfg.updateInfos = calculateUpdateInfos(getHelper().lookupDependenciesUpdates(dependencies, false));
         } catch (ArtifactMetadataRetrievalException | InvalidVersionSpecificationException e) {
             throw new MojoExecutionException("Unable to calculate updates", e);
         }
 
-        // get includes and excludes
-        cfg.includes = parseMatches(updatesIncludesList, "include");
-        cfg.excludes = parseMatches(updatesExcludesList, "exclude");
-
         final Map<String, UpdateResult> results = new LinkedHashMap<>();
 
         final Map<String, Set<String>> globalPropertyUpdates = new HashMap<String, Set<String>>();
@@ -289,20 +331,23 @@ public class UpdateVersionsMojo extends AbstractIncludingFeatureMojo {
         }
     }
 
-    private boolean shouldHandle(final ArtifactId id, final UpdateConfig cfg) {
-        boolean include = true;
+    private String shouldHandle(final ArtifactId id, final UpdateConfig cfg) {
+        String include = "";
         if (cfg.includes != null) {
-            include = match(id, cfg.includes);
+            include = match(id, cfg.includes, cfg.includeVersionInfo);
         }
-        if (include && cfg.excludes != null) {
-            include = !match(id, cfg.excludes);
+        if (include != null && cfg.excludes != null) {
+            if (match(id, cfg.excludes, null) != null) {
+                include = null;
+            }
         }
         return include;
     }
 
-    private boolean match(final ArtifactId id, final List<String[]> matches) {
+    private String match(final ArtifactId id, final List<String[]> matches, final List<String> versionInfo) {
         boolean match = false;
 
+        int index = 0;
         for(final String[] m : matches) {
             match = id.getGroupId().equals(m[0]);
             if (match && m.length > 1) {
@@ -327,8 +372,15 @@ public class UpdateVersionsMojo extends AbstractIncludingFeatureMojo {
             if (match) {
                 break;
             }
+            index++;
         }
-        return match;
+        if (match) {
+            if (versionInfo != null) {
+                return versionInfo.get(index);
+            }
+            return "";
+        }
+        return null;
     }
 
     private String update(final Artifact artifact, final List<Map.Entry<Dependency, String>> updates)
@@ -368,6 +420,8 @@ public class UpdateVersionsMojo extends AbstractIncludingFeatureMojo {
         public List<String[]> includes;
         public List<String[]> excludes;
 
+        public List<String> includeVersionInfo;
+
         List<Map.Entry<Dependency, String>> updateInfos;
 	}
 
@@ -450,26 +504,68 @@ public class UpdateVersionsMojo extends AbstractIncludingFeatureMojo {
 	    }
 	}
 
-    private List<Map.Entry<Dependency, String>> calculateUpdateInfos(Map<Dependency, ArtifactVersions> updateInfos) {
+    private String getVersion(final Map.Entry<Dependency, ArtifactVersions> entry, final UpdateScope scope) {
+        ArtifactVersion latest;
+        if (entry.getValue().isCurrentVersionDefined()) {
+            latest = entry.getValue().getNewestUpdate(scope, false);
+        } else {
+            ArtifactVersion newestVersion = entry.getValue()
+                    .getNewestVersion(entry.getValue().getArtifact().getVersionRange(), false);
+            latest = newestVersion == null ? null
+                    : entry.getValue().getNewestUpdate(newestVersion, scope, false);
+            if (latest != null
+                    && ArtifactVersions.isVersionInRange(latest, entry.getValue().getArtifact().getVersionRange())) {
+                latest = null;
+            }
+        }
+        return latest != null ? latest.toString() : null;
+    }
+
+    private UpdateScope getScope(final String versionInfo) {
+        final UpdateScope scope;
+        if (versionInfo == null || "ANY".equalsIgnoreCase(versionInfo)) {
+            scope = UpdateScope.ANY;
+        } else if ("MAJOR".equalsIgnoreCase(versionInfo)) {
+            scope = UpdateScope.MAJOR;
+        } else if ("MINOR".equalsIgnoreCase(versionInfo)) {
+            scope = UpdateScope.MINOR;
+        } else if ("INCREMENTAL".equalsIgnoreCase(versionInfo)) {
+            scope = UpdateScope.INCREMENTAL;
+        } else if ("SUBINCREMENTAL".equalsIgnoreCase(versionInfo)) {
+            scope = UpdateScope.SUBINCREMENTAL;
+        } else {
+            scope = null;
+        }
+        return scope;
+    }
+
+    private List<Map.Entry<Dependency, String>> calculateUpdateInfos(
+            final Map<Dependency, ArtifactVersions> updateInfos) throws MojoExecutionException {
+        final UpdateScope defaultScope = getScope(this.versionScope);
+        if (defaultScope == null) {
+            throw new MojoExecutionException("Invalid update scope specified: " + this.versionScope);
+        }
         final List<Map.Entry<Dependency, String>> updates = new ArrayList<>();
         for (final Map.Entry<Dependency, ArtifactVersions> entry : updateInfos.entrySet()) {
-            ArtifactVersion latest;
-            if (entry.getValue().isCurrentVersionDefined()) {
-                latest = entry.getValue().getNewestUpdate(UpdateScope.ANY, false);
-            } else {
-                ArtifactVersion newestVersion = entry.getValue().getNewestVersion(
-                        entry.getValue().getArtifact().getVersionRange(),
-                        false);
-                latest = newestVersion == null ? null
-                        : entry.getValue().getNewestUpdate(newestVersion, UpdateScope.ANY, false);
-                if (latest != null
-                        && ArtifactVersions.isVersionInRange(latest,
-                                entry.getValue().getArtifact().getVersionRange())) {
-                    latest = null;
+            UpdateScope scope = defaultScope;
+            final String versionInfo = entry.getKey().getSystemPath();
+            String newVersion = null;
+            if (versionInfo != null && !versionInfo.trim().isEmpty()) {
+                scope = getScope(versionInfo);
+                if (scope == null) {
+                    getLog().debug(
+                            "Using provided version " + versionInfo + " for " + ProjectHelper.toString(entry.getKey()));
+                    newVersion = versionInfo;
                 }
             }
-            if (latest != null) {
-                final String newVersion = latest.toString();
+            if (newVersion == null) {
+                newVersion = getVersion(entry, scope);
+                getLog().debug("Detected new version " + newVersion + " using scope " + scope.toString() + " for "
+                        + ProjectHelper.toString(entry.getKey()));
+
+            }
+            if (newVersion != null) {
+                final String version = newVersion;
                 updates.add(new Map.Entry<Dependency, String>() {
 
                     @Override
@@ -479,7 +575,7 @@ public class UpdateVersionsMojo extends AbstractIncludingFeatureMojo {
 
                     @Override
                     public String getValue() {
-                        return newVersion;
+                        return version;
                     }
 
                     @Override
@@ -563,7 +659,7 @@ public class UpdateVersionsMojo extends AbstractIncludingFeatureMojo {
             final UpdateConfig cfg)
             throws MojoExecutionException {
         for (final Artifact a : artifacts) {
-            if (shouldHandle(a.getId(), cfg)) {
+            if (shouldHandle(a.getId(), cfg) != null) {
                 final String newVersion = update(a, cfg.updateInfos);
                 if (newVersion != null) {
                     final ArtifactUpdate update = new ArtifactUpdate();