You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by kw...@apache.org on 2021/04/09 12:53:32 UTC

[sling-org-apache-sling-feature-analyser] 01/01: SLING-10285 add analyser to validate that feature id matches one of a given set

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

kwin pushed a commit to branch feature/feature-id-analyser
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-feature-analyser.git

commit fd099328e74a0b0ab7838e36952c23dadb128785
Author: Konrad Windszus <kw...@apache.org>
AuthorDate: Fri Apr 9 14:53:16 2021 +0200

    SLING-10285 add analyser to validate that feature id matches one of a
    given set
---
 readme.md                                          |  12 +++
 .../feature/analyser/task/impl/CheckFeatureId.java |  93 ++++++++++++++++++
 ...apache.sling.feature.analyser.task.AnalyserTask |   1 +
 .../task/impl/AnalyserTaskContextImpl.java         | 109 +++++++++++++++++++++
 .../analyser/task/impl/CheckFeatureIdTest.java     |  52 ++++++++++
 .../analyser/task/impl/CheckRepoinitTest.java      |  75 --------------
 6 files changed, 267 insertions(+), 75 deletions(-)

diff --git a/readme.md b/readme.md
index 4a4d137..9f17ff9 100644
--- a/readme.md
+++ b/readme.md
@@ -32,6 +32,8 @@ The following analysers are defined:
 
 * `repoinit`: Checks the syntax of all repoinit sections.
 
+* `feature-id`: Checks if the used feature id matches one of the given Maven coordinates.
+
 Additional analysers in relation to Feature Model API Regions can be found here: https://github.com/apache/sling-org-apache-sling-feature-extension-apiregions
 
 For further documentation see: https://github.com/apache/sling-org-apache-sling-feature/blob/master/readme.md
@@ -49,3 +51,13 @@ This analyser requires additional configuration:
 `compare-extension` | extension name | If this configuration is absent, the feature's bundles are compared. Otherwise the extensions with the specified name are compared. These extensions must be of type `ARTIFACTS`.
 `compare-mode` | `SAME` or `DIFFERENT` | Whether the sections must be the same or must be different. Defaults to `SAME`.
 `compare-metadata` | `true` or `false` | Whether to include the artifact metadata in the comparison. Defaults to `false`.
+
+## `feature-id`
+
+This analyser checks that the feature id matches one of the given accepted feature ids. If it doesn't it will emit an error.
+
+This analyser requires additional configuration:
+
+ Configuration key | Allowed values | Description 
+ ----- | ----- | -----
+`accepted-feature-ids` | comma-separated list of Maven IDs | The Maven ID/coordinates have the format `groupId:artifactId[:packaging[:classifier]]:version`. Each item is either a string which must be equal to the according item of the feature id, or a `*` which acts as wildcard (i.e. everything matches).
diff --git a/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckFeatureId.java b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckFeatureId.java
new file mode 100644
index 0000000..050db36
--- /dev/null
+++ b/src/main/java/org/apache/sling/feature/analyser/task/impl/CheckFeatureId.java
@@ -0,0 +1,93 @@
+/*
+ * 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.analyser.task.impl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.sling.feature.ArtifactId;
+import org.apache.sling.feature.analyser.task.AnalyserTask;
+import org.apache.sling.feature.analyser.task.AnalyserTaskContext;
+
+public class CheckFeatureId implements AnalyserTask {
+
+    static final String CONFIG_KEY_ACCEPTED_FEATURE_IDS = "accepted-feature-ids";
+
+    @Override
+    public String getId() {
+        return "feature-id";
+    }
+
+    @Override
+    public String getName() {
+        return "Restrict feature id format";
+    }
+
+    @Override
+    public void execute(AnalyserTaskContext ctx) throws Exception {
+        Map<String, String> cfg = ctx.getConfiguration();
+        String acceptedFeatureIds = cfg.get(CONFIG_KEY_ACCEPTED_FEATURE_IDS);
+        if (acceptedFeatureIds == null) {
+            // this is a comma-separated list of accepted 
+            throw new IllegalArgumentException("Missing 'accepted-feature-ids' configuration for feature-id analyser.");
+        }
+        Collection<ArtifactId> acceptedArtifactIds = new ArrayList<>();
+        for (String acceptedFeatureId : acceptedFeatureIds.split(",")) {
+            try {
+                acceptedArtifactIds.add(ArtifactId.fromMvnId(acceptedFeatureId));
+            } catch (IllegalArgumentException e) {
+                throw new IllegalArgumentException("Invalid 'accepted-feature-ids' configuration for feature-id analyser, element '" + acceptedFeatureId + "' is not a valid maven coordinate string in format 'groupId:artifactId[:packaging[:classifier]]:version'", e);
+            }
+        }
+        if (!matchesAnyOf(ctx.getFeature().getId(), acceptedArtifactIds)) {
+            ctx.reportError("Feature " + ctx.getFeature().getId() + " does not match any of the accepted feature ids ");
+        }
+    }
+
+    static boolean matchesAnyOf(ArtifactId artifactId, Collection<ArtifactId> expectedArtifactIds) {
+        for (ArtifactId expectedArtifactId : expectedArtifactIds) {
+            if (matches(artifactId, expectedArtifactId)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    static boolean matches(ArtifactId artifactId, ArtifactId expectedArtifactId) {
+        if (!expectedArtifactId.getGroupId().equals(artifactId.getGroupId()) && !expectedArtifactId.getGroupId().equals("*")) {
+            return false;
+        }
+        if (!expectedArtifactId.getArtifactId().equals(artifactId.getArtifactId()) && !expectedArtifactId.getArtifactId().equals("*")) {
+            return false;
+        }
+        if (!expectedArtifactId.getVersion().equals(artifactId.getVersion()) && !expectedArtifactId.getVersion().equals("*")) {
+            return false;
+        }
+        if (!expectedArtifactId.getType().equals(artifactId.getType()) && !expectedArtifactId.getVersion().equals("*")) {
+            return false;
+        }
+        // classifier is optional
+        if (expectedArtifactId.getClassifier() != null && !expectedArtifactId.getClassifier().equals(artifactId.getClassifier()) && !expectedArtifactId.getClassifier().equals("*")) {
+            return false;
+        }
+        return true;
+    }
+
+}
diff --git a/src/main/resources/META-INF/services/org.apache.sling.feature.analyser.task.AnalyserTask b/src/main/resources/META-INF/services/org.apache.sling.feature.analyser.task.AnalyserTask
index 9a0111e..503dc36 100644
--- a/src/main/resources/META-INF/services/org.apache.sling.feature.analyser.task.AnalyserTask
+++ b/src/main/resources/META-INF/services/org.apache.sling.feature.analyser.task.AnalyserTask
@@ -11,3 +11,4 @@ org.apache.sling.feature.analyser.task.impl.CheckDuplicateSymbolicName
 org.apache.sling.feature.analyser.task.impl.CheckRepoinit
 org.apache.sling.feature.analyser.task.impl.CheckRequirementsCapabilities
 org.apache.sling.feature.analyser.task.impl.CheckUnusedBundles
+org.apache.sling.feature.analyser.task.impl.CheckFeatureId
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/feature/analyser/task/impl/AnalyserTaskContextImpl.java b/src/test/java/org/apache/sling/feature/analyser/task/impl/AnalyserTaskContextImpl.java
new file mode 100644
index 0000000..1ee90d2
--- /dev/null
+++ b/src/test/java/org/apache/sling/feature/analyser/task/impl/AnalyserTaskContextImpl.java
@@ -0,0 +1,109 @@
+/*
+ * 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.analyser.task.impl;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.sling.feature.ArtifactId;
+import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.analyser.task.AnalyserTaskContext;
+import org.apache.sling.feature.builder.FeatureProvider;
+import org.apache.sling.feature.scanner.BundleDescriptor;
+import org.apache.sling.feature.scanner.FeatureDescriptor;
+
+public class AnalyserTaskContextImpl implements AnalyserTaskContext {
+
+    private final Feature f;
+    private final Map<String, String> configuration = new HashMap<>();
+
+    private final List<String> errors = new ArrayList<>();
+
+    public AnalyserTaskContextImpl() {
+        this("g:a:1");
+    }
+    
+    public AnalyserTaskContextImpl(String artifactId) {
+        f = new Feature(ArtifactId.parse(artifactId));
+    }
+
+    @Override
+    public Feature getFeature() {
+        return f;
+    }
+
+    @Override
+    public FeatureDescriptor getFeatureDescriptor() {
+        return null;
+    }
+
+    @Override
+    public BundleDescriptor getFrameworkDescriptor() {
+        return null;
+    }
+
+    @Override
+    public Map<String, String> getConfiguration() {
+        return configuration;
+    }
+
+    public void putConfigurationValue(String key, String value) {
+        configuration.put(key, value);
+    }
+
+    @Override
+    public FeatureProvider getFeatureProvider() {
+        return null;
+    }
+
+    @Override
+    public void reportWarning(String message) {
+    }
+
+    @Override
+    public void reportArtifactWarning(ArtifactId artifactId, String message) {
+
+    }
+
+    @Override
+    public void reportArtifactError(ArtifactId artifactId, String message) {
+        errors.add(message);
+    }
+
+    @Override
+    public void reportExtensionWarning(String extension, String message) {
+
+    }
+
+    @Override
+    public void reportExtensionError(String extension, String message) {
+        errors.add(message);
+    }
+
+    @Override
+    public void reportError(String message) {
+        errors.add(message);
+    }
+
+    public List<String> getErrors() {
+        return this.errors;
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckFeatureIdTest.java b/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckFeatureIdTest.java
new file mode 100644
index 0000000..fdde3a8
--- /dev/null
+++ b/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckFeatureIdTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.analyser.task.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.sling.feature.analyser.task.AnalyserTask;
+import org.junit.Before;
+import org.junit.Test;
+
+public class CheckFeatureIdTest {
+
+    private AnalyserTaskContextImpl ctx;
+    private AnalyserTask task;
+
+    @Before
+    public void setUp() {
+        ctx = new AnalyserTaskContextImpl("myGroupId:myArtifactId:jar:myClassifier");
+        task = new CheckFeatureId();
+    }
+ 
+    @Test
+    public void testValidFeatureId() throws Exception {
+        ctx.getConfiguration().put(CheckFeatureId.CONFIG_KEY_ACCEPTED_FEATURE_IDS, "myGroupId:*:jar:myClassifier");
+        task.execute(ctx);
+        assertTrue(ctx.getErrors().isEmpty());
+    }
+
+    @Test
+    public void testInValidFeatureId() throws Exception {
+        ctx.getConfiguration().put(CheckFeatureId.CONFIG_KEY_ACCEPTED_FEATURE_IDS, "myGroupId:*:jar:myOtherClassifier");
+        task.execute(ctx);
+        assertEquals(1, ctx.getErrors().size());
+    }
+}
diff --git a/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckRepoinitTest.java b/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckRepoinitTest.java
index 0cf89bc..74a87c6 100644
--- a/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckRepoinitTest.java
+++ b/src/test/java/org/apache/sling/feature/analyser/task/impl/CheckRepoinitTest.java
@@ -20,21 +20,11 @@ package org.apache.sling.feature.analyser.task.impl;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.sling.feature.ArtifactId;
 import org.apache.sling.feature.Configuration;
 import org.apache.sling.feature.Extension;
 import org.apache.sling.feature.ExtensionState;
 import org.apache.sling.feature.ExtensionType;
-import org.apache.sling.feature.Feature;
 import org.apache.sling.feature.analyser.task.AnalyserTask;
-import org.apache.sling.feature.analyser.task.AnalyserTaskContext;
-import org.apache.sling.feature.builder.FeatureProvider;
-import org.apache.sling.feature.scanner.BundleDescriptor;
-import org.apache.sling.feature.scanner.FeatureDescriptor;
 import org.junit.Test;
 
 public class CheckRepoinitTest {
@@ -104,69 +94,4 @@ public class CheckRepoinitTest {
         task.execute(ctx);
         assertEquals(1, ctx.getErrors().size());
     }
-
-    public static class AnalyserTaskContextImpl implements AnalyserTaskContext {
-
-        private final Feature f = new Feature(ArtifactId.parse("g:a:1"));
-
-        private final List<String> errors = new ArrayList<>();
-
-        @Override
-        public Feature getFeature() {
-            return f;
-        }
-
-        @Override
-        public FeatureDescriptor getFeatureDescriptor() {
-            return null;
-        }
-
-        @Override
-        public BundleDescriptor getFrameworkDescriptor() {
-            return null;
-        }
-
-        @Override
-        public Map<String, String> getConfiguration() {
-            return null;
-        }
-
-        @Override
-        public FeatureProvider getFeatureProvider() {
-            return null;
-        }
-
-        @Override
-        public void reportWarning(String message) {
-        }
-
-        @Override
-        public void reportArtifactWarning(ArtifactId artifactId, String message) {
-
-        }
-
-        @Override
-        public void reportArtifactError(ArtifactId artifactId, String message) {
-            errors.add(message);
-        }
-
-        @Override
-        public void reportExtensionWarning(String extension, String message) {
-
-        }
-
-        @Override
-        public void reportExtensionError(String extension, String message) {
-            errors.add(message);
-        }
-
-        @Override
-        public void reportError(String message) {
-            errors.add(message);
-        }
-
-        public List<String> getErrors() {
-            return this.errors;
-        }
-    }
 }