You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by si...@apache.org on 2019/06/03 16:20:45 UTC
[sling-slingfeature-maven-plugin] 01/01: SLING-8468 -
[slingfeature-m-p] donate a new MOJO which is able to scan and detect
differences between different versions of the same Feature model
This is an automated email from the ASF dual-hosted git repository.
simonetripodi pushed a commit to branch feature_diff
in repository https://gitbox.apache.org/repos/asf/sling-slingfeature-maven-plugin.git
commit ca5494721cbe3718f14d06217800de2be772c2d9
Author: Simo Tripodi <st...@adobe.com>
AuthorDate: Mon Jun 3 18:20:31 2019 +0200
SLING-8468 - [slingfeature-m-p] donate a new MOJO which is able to scan
and detect differences between different versions of the same Feature
model
initial checkin
---
pom.xml | 23 ++-
.../feature/maven/mojos/FeaturesDiffMojo.java | 199 +++++++++++++++++++++
2 files changed, 217 insertions(+), 5 deletions(-)
diff --git a/pom.xml b/pom.xml
index 7d9f48a..0e30d91 100644
--- a/pom.xml
+++ b/pom.xml
@@ -172,6 +172,24 @@
<version>1.0.2</version>
</dependency>
<dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.feature.apiregions.model</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.feature.diff</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ </dependency>
+ <!--
+ | JSON patch
+ -->
+ <dependency>
+ <groupId>com.flipkart.zjsonpatch</groupId>
+ <artifactId>zjsonpatch</artifactId>
+ <version>0.4.8</version>
+ </dependency>
+ <dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-core</artifactId>
<version>${maven.version}</version>
@@ -248,11 +266,6 @@
<artifactId>json-schema-validator</artifactId>
<version>2.2.10</version>
</dependency>
- <dependency>
- <groupId>com.fasterxml.jackson.core</groupId>
- <artifactId>jackson-core</artifactId>
- <version>2.2.3</version>
- </dependency>
<!-- APIs JARs -->
<dependency>
<groupId>org.apache.felix</groupId>
diff --git a/src/main/java/org/apache/sling/feature/maven/mojos/FeaturesDiffMojo.java b/src/main/java/org/apache/sling/feature/maven/mojos/FeaturesDiffMojo.java
new file mode 100644
index 0000000..cc76ccb
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/maven/mojos/FeaturesDiffMojo.java
@@ -0,0 +1,199 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.sling.feature.maven.mojos;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.factory.ArtifactFactory;
+import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException;
+import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
+import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
+import org.apache.maven.artifact.resolver.ArtifactResolutionException;
+import org.apache.maven.artifact.resolver.ArtifactResolver;
+import org.apache.maven.artifact.versioning.ArtifactVersion;
+import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
+import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
+import org.apache.maven.artifact.versioning.VersionRange;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.Component;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.diff.FeatureDiff;
+import org.apache.sling.feature.diff.io.json.FeatureDiffJSONSerializer;
+import org.apache.sling.feature.io.json.FeatureJSONReader;
+
+/**
+ * Compares different versions of the same Feature Model.
+ */
+@Mojo(name = "features-diff",
+ defaultPhase = LifecyclePhase.PACKAGE,
+ requiresDependencyResolution = ResolutionScope.TEST,
+ threadSafe = true
+)
+@SuppressWarnings("deprecation")
+public final class FeaturesDiffMojo extends AbstractIncludingFeatureMojo {
+
+ @Parameter
+ private FeatureSelectionConfig selection;
+
+ @Parameter(defaultValue = "${project.build.directory}/features-diff", readonly = true)
+ private File mainOutputDir;
+
+ @Parameter(defaultValue = "(,${project.version})")
+ protected String comparisonVersion;
+
+ @Component
+ protected ArtifactResolver resolver;
+
+ @Component
+ protected ArtifactFactory factory;
+
+ @Component
+ private ArtifactMetadataSource metadataSource;
+
+ @Override
+ public void execute() throws MojoExecutionException, MojoFailureException {
+ getLog().debug("Retrieving Feature files...");
+ final Collection<Feature> features = getSelectedFeatures(selection).values();
+
+ if (features.isEmpty()) {
+ getLog().debug("There are no assciated Feature files to current project, plugin execution will be interrupted");
+ return;
+ }
+
+ if (!mainOutputDir.exists()) {
+ mainOutputDir.mkdirs();
+ }
+
+ getLog().debug("Starting Feature(s) analysis...");
+
+ for (final Feature feature : features) {
+ onFeature(feature);
+ }
+ }
+
+ private void onFeature(Feature current) throws MojoExecutionException, MojoFailureException {
+ Feature previous = getPreviousFeature(current);
+
+ if (previous == null) {
+ getLog().info("There is no previous verion available of " + current + " model");
+ return;
+ }
+
+ getLog().info("Comparing current " + current + " to previous " + previous);
+
+ FeatureDiff featureDiff = FeatureDiff.compareFeatures(previous, current);
+
+ if (featureDiff.isEmpty()) {
+ getLog().info("There are no differences between current " + current + " and previous " + previous + " models");
+ return;
+ }
+
+ File outputDiffFile = new File(mainOutputDir, current.getId().getClassifier() + ".diff.json");
+
+ getLog().info("Rendering differences to file " + outputDiffFile);
+
+ try (FileOutputStream output = new FileOutputStream(outputDiffFile)) {
+ FeatureDiffJSONSerializer.serializeFeatureDiff(featureDiff, output);
+ } catch (IOException e) {
+ throw new MojoExecutionException("An error occurred while serializing Feature diff to " + outputDiffFile, e);
+ }
+ }
+
+ private Feature getPreviousFeature(Feature current) throws MojoExecutionException, MojoFailureException {
+ VersionRange range;
+ try {
+ range = VersionRange.createFromVersionSpec(comparisonVersion);
+ } catch (InvalidVersionSpecificationException e) {
+ throw new MojoFailureException("Invalid comparison version: " + e.getMessage());
+ }
+
+ Artifact previousArtifact;
+
+ try {
+ previousArtifact = factory.createDependencyArtifact(current.getId().getGroupId(),
+ current.getId().getArtifactId(),
+ range,
+ current.getId().getType(),
+ current.getId().getClassifier(),
+ Artifact.SCOPE_COMPILE);
+
+ if (!previousArtifact.getVersionRange().isSelectedVersionKnown(previousArtifact)) {
+ getLog().debug("Searching for versions in range: " + previousArtifact.getVersionRange());
+ List<ArtifactVersion> availableVersions = metadataSource.retrieveAvailableVersions(previousArtifact,
+ mavenSession.getLocalRepository(),
+ project.getRemoteArtifactRepositories());
+ filterSnapshots(availableVersions);
+ ArtifactVersion version = range.matchVersion(availableVersions);
+ if (version != null) {
+ previousArtifact.selectVersion(version.toString());
+ }
+ }
+ } catch (OverConstrainedVersionException ocve) {
+ throw new MojoFailureException("Invalid comparison version: " + ocve.getMessage());
+ } catch (ArtifactMetadataRetrievalException amre) {
+ throw new MojoExecutionException("Error determining previous version: " + amre.getMessage(), amre);
+ }
+
+ if (previousArtifact.getVersion() == null) {
+ getLog().info("Unable to find a previous version of the " + current + " Feature in the repository");
+ return null;
+ }
+
+ try {
+ resolver.resolve(previousArtifact, project.getRemoteArtifactRepositories(), mavenSession.getLocalRepository());
+ } catch (ArtifactResolutionException are) {
+ getLog().warn("Artifact " + previousArtifact + " cannot be resolved : " + are.getMessage(), are);
+ } catch (ArtifactNotFoundException anfe) {
+ getLog().warn("Artifact " + previousArtifact + " does not exist on local/remote repositories", anfe);
+ }
+
+ File featureFile = previousArtifact.getFile();
+
+ if (featureFile == null || !featureFile.exists()) {
+ return null;
+ }
+
+ try (FileReader reader = new FileReader(featureFile)) {
+ return FeatureJSONReader.read(reader, featureFile.getAbsolutePath());
+ } catch (IOException e) {
+ throw new MojoExecutionException("An error occurred while reading the " + featureFile + " Feature file:", e);
+ }
+ }
+
+ private void filterSnapshots(List<ArtifactVersion> versions) {
+ Iterator<ArtifactVersion> versionIterator = versions.iterator();
+ while (versionIterator.hasNext()) {
+ ArtifactVersion version = versionIterator.next();
+ if (version.getQualifier() != null && version.getQualifier().endsWith("SNAPSHOT")) {
+ versionIterator.remove();
+ }
+ }
+ }
+
+}