This is an automated email from the ASF dual-hosted git repository.
rombert pushed a commit to branch master
in repository
https://gitbox.apache.org/repos/asf/sling-feature-launcher-maven-plugin.git
The following commit(s) were added to refs/heads/master by this push:
new 4fb58e1 SLING-12790 - Allow launching from a feature that is not
attached to the project (#18)
4fb58e1 is described below
commit 4fb58e18a6ae2f0197174e5cabf19004c2a8696c
Author: Robert Munteanu <[email protected]>
AuthorDate: Tue May 20 13:11:50 2025 +0200
SLING-12790 - Allow launching from a feature that is not attached to the
project (#18)
Add a 'featureFile' parameter to the launch configuration.
---
src/it/feature-file-it/pom.xml | 55 ++++++++++++++++++++++
src/it/feature-file-it/src/model.json | 14 ++++++
src/it/feature-file-it/verify.groovy | 21 +++++++++
.../sling/maven/feature/launcher/Launch.java | 30 ++++++++++--
.../sling/maven/feature/launcher/StartMojo.java | 24 +++++++---
.../sling/maven/feature/launcher/LaunchTest.java | 44 +++++++++++++++--
6 files changed, 173 insertions(+), 15 deletions(-)
diff --git a/src/it/feature-file-it/pom.xml b/src/it/feature-file-it/pom.xml
new file mode 100644
index 0000000..0f04f72
--- /dev/null
+++ b/src/it/feature-file-it/pom.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.apache.sling</groupId>
+ <artifactId>feature-file-it</artifactId>
+ <version>1.0-SNAPSHOT</version>
+
+ <description>An IT verifying using a local feature file
works.</description>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>@project.groupId@</groupId>
+ <artifactId>@project.artifactId@</artifactId>
+ <version>@project.version@</version>
+ <configuration>
+ <launches>
+ <launch>
+ <id>model</id>
+
<featureFile>${project.basedir}/src/model.json</featureFile>
+ <startTimeoutSeconds>180</startTimeoutSeconds>
+ </launch>
+ </launches>
+ <toLaunch>
+ </toLaunch>
+ </configuration>
+ <executions>
+ <execution>
+ <goals>
+ <goal>start</goal>
+ <goal>stop</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/src/it/feature-file-it/src/model.json
b/src/it/feature-file-it/src/model.json
new file mode 100644
index 0000000..ee05e71
--- /dev/null
+++ b/src/it/feature-file-it/src/model.json
@@ -0,0 +1,14 @@
+{
+ "id":"${project.groupId}:${project.artifactId}:model:${project.version}",
+ "bundles": [
+ "org.apache.felix/org.apache.felix.scr/2.1.20",
+ "org.apache.felix/org.apache.felix.log/1.2.2",
+ "org.apache.felix/org.apache.felix.configadmin/1.9.16",
+ "org.osgi/org.osgi.util.promise/1.1.1",
+ "org.osgi/org.osgi.util.function/1.1.0",
+ "org.osgi/org.osgi.util.converter/1.0.1",
+ "org.apache.commons/commons-lang3/3.9",
+ "org.apache.felix/org.apache.felix.http.jetty/4.0.16",
+ "org.apache.felix/org.apache.felix.http.servlet-api/1.1.2"
+ ]
+}
\ No newline at end of file
diff --git a/src/it/feature-file-it/verify.groovy
b/src/it/feature-file-it/verify.groovy
new file mode 100644
index 0000000..e9b7465
--- /dev/null
+++ b/src/it/feature-file-it/verify.groovy
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+File touchFile = new File( basedir, "build.log" );
+
+assert touchFile.isFile()
diff --git a/src/main/java/org/apache/sling/maven/feature/launcher/Launch.java
b/src/main/java/org/apache/sling/maven/feature/launcher/Launch.java
index bf4aaca..0e4b3ff 100644
--- a/src/main/java/org/apache/sling/maven/feature/launcher/Launch.java
+++ b/src/main/java/org/apache/sling/maven/feature/launcher/Launch.java
@@ -18,11 +18,13 @@
*/
package org.apache.sling.maven.feature.launcher;
+import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.regex.Pattern;
import org.apache.maven.model.Dependency;
@@ -33,6 +35,7 @@ public class Launch {
private String id;
private Dependency feature;
+ private String featureFile;
private LauncherArguments launcherArguments = new LauncherArguments();
private int startTimeoutSeconds = 30;
private boolean skip = false;
@@ -47,13 +50,21 @@ public class Launch {
this.id = id;
}
- public Dependency getFeature() {
- return feature;
+ public Optional<Dependency> getFeature() {
+ return Optional.ofNullable(feature);
}
public void setFeature(Dependency feature) {
this.feature = feature;
}
+
+ public Optional<File> getFeatureFile() {
+ return Optional.ofNullable(featureFile).map(File::new);
+ }
+
+ public void setFeatureFile(String featureFile) {
+ this.featureFile = featureFile;
+ }
public LauncherArguments getLauncherArguments() {
return launcherArguments;
@@ -107,10 +118,19 @@ public class Launch {
if ( startTimeoutSeconds < 0 )
throwInvalid("startTimeout value '" + startTimeoutSeconds + "' is
negative" );
- if ( feature == null )
- throwInvalid("required field 'feature' is missing");
+ boolean hasFeature = feature != null;
+ boolean hasFeatureFile = featureFile != null &&
!featureFile.trim().isEmpty();
+
+ if ( hasFeature && hasFeatureFile )
+ throwInvalid("Only one of 'feature' and 'featureFile' is allowed,
but both are set");
+
+ if ( !hasFeature && !hasFeatureFile )
+ throwInvalid("Neither 'feature' nor 'featureFile' are set");
+
+ if ( hasFeatureFile && ! new File(featureFile).exists() )
+ throwInvalid("Feature file '" + featureFile + "' does not exist");
- if ( ! "slingosgifeature".equals(feature.getType()) )
+ if ( hasFeature && ! "slingosgifeature".equals(feature.getType()) )
throwInvalid("type must be 'slingosgifeature' but is '" +
feature.getType()+"'");
}
diff --git
a/src/main/java/org/apache/sling/maven/feature/launcher/StartMojo.java
b/src/main/java/org/apache/sling/maven/feature/launcher/StartMojo.java
index dc18b84..e7a1734 100644
--- a/src/main/java/org/apache/sling/maven/feature/launcher/StartMojo.java
+++ b/src/main/java/org/apache/sling/maven/feature/launcher/StartMojo.java
@@ -85,8 +85,9 @@ public class StartMojo extends AbstractMojo {
/**
* List of {@link Launch} objects to start. Each is having the following
format:
* <pre>{@code
- * <id>...</id> <!-- the id of the launch, must be unique within the list,
is mandatory -->
- * <dependency>...</dependency> <!-- the Maven coordinates of the feature
model -->
+ * <id>...</id> <!-- the id of the launch, must be unique within the list,
is mandatory-->
+ * <feature>...</feature> <!-- the Maven coordinates of the feature model,
mandatory unless featureFile is used -->
+ * <featureFile>...</featureFile> <!-- the path to the feature model,
mandatory unless feature is used -->
* <launcherArguments> <!-- additional arguments to pass to the launcher
-->
* <frameworkProperties>
* <org.osgi.service.http.port>8090</org.osgi.service.http.port>
@@ -185,12 +186,13 @@ public class StartMojo extends AbstractMojo {
}
launch.validate();
-
- Artifact artifact = toArtifact(launch.getFeature());
- ArtifactResult result =
resolver.resolveArtifact(repositorySession, new ArtifactRequest(artifact,
remoteRepos, null));
- File featureFile = result.getArtifact().getFile();
-
+ File featureFile = launch.getFeature().
+ map( this::toArtifact )
+ .map( a -> uncheckedResolveArtifact(repositorySession, a) )
+ .map( r -> r.getArtifact().getFile())
+ .orElseGet( () -> launch.getFeatureFile().get() ); // the
Launch is guaranteed to either have a feature or a featureFile set
+
String javahome = System.getenv(JAVA_HOME);
if (javahome == null || javahome.isEmpty()) {
// SLING-9843 fallback to java.home system property if
JAVA_HOME env variable is not set
@@ -318,6 +320,14 @@ public class StartMojo extends AbstractMojo {
}
}
+ private ArtifactResult uncheckedResolveArtifact(RepositorySystemSession
repositorySession, Artifact artifact) {
+ try {
+ return resolver.resolveArtifact(repositorySession, new
ArtifactRequest(artifact, remoteRepos, null));
+ } catch (ArtifactResolutionException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
private Artifact toArtifact(Dependency dependency) {
return new DefaultArtifact(dependency.getGroupId(),
dependency.getArtifactId(), dependency.getClassifier(), dependency.getType(),
dependency.getVersion());
}
diff --git
a/src/test/java/org/apache/sling/maven/feature/launcher/LaunchTest.java
b/src/test/java/org/apache/sling/maven/feature/launcher/LaunchTest.java
index e512d13..1218f5c 100644
--- a/src/test/java/org/apache/sling/maven/feature/launcher/LaunchTest.java
+++ b/src/test/java/org/apache/sling/maven/feature/launcher/LaunchTest.java
@@ -18,26 +18,37 @@
*/
package org.apache.sling.maven.feature.launcher;
+import java.io.File;
+import java.io.IOException;
+
import org.apache.maven.model.Dependency;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
public class LaunchTest {
+
+ @Rule
+ public TemporaryFolder tmp = new TemporaryFolder();
private Dependency validDep;
-
+ private File validFeatureFile;
+
@Before
- public void prepare() {
+ public void prepare() throws IOException {
validDep = new Dependency();
validDep.setGroupId("org.apache.sling");
validDep.setArtifactId("org.apache.sling.starter");
validDep.setVersion("12");
validDep.setClassifier("oak_tar");
validDep.setType("slingosgifeature");
+
+ validFeatureFile = tmp.newFile("feature.json");
}
@Test
- public void validLaunch() {
+ public void validLaunch_withFeature() {
Launch launch = new Launch();
launch.setFeature(validDep);
@@ -45,6 +56,15 @@ public class LaunchTest {
launch.validate();
}
+ @Test
+ public void validLaunch_withFeatureFile() {
+
+ Launch launch = new Launch();
+ launch.setFeatureFile(validFeatureFile.getAbsolutePath());
+ launch.setId("feature");
+ launch.validate();
+ }
+
@Test(expected = IllegalArgumentException.class)
public void invalidLaunch_noId() {
@@ -91,5 +111,23 @@ public class LaunchTest {
launch.setStartTimeoutSeconds(-10);
launch.validate();
}
+
+ @Test(expected = IllegalArgumentException.class)
+ public void invalidLaunch_bothFeatureAndFeatureFile() {
+
+ Launch launch = new Launch();
+ launch.setId("feature");
+ launch.setFeature(validDep);
+ launch.setFeatureFile(validFeatureFile.getAbsolutePath());
+ launch.validate();
+ }
+ @Test(expected = IllegalArgumentException.class)
+ public void invalidLaunch_missingFeatureFile() {
+
+ Launch launch = new Launch();
+ launch.setId("feature");
+ launch.setFeatureFile(validFeatureFile.getAbsolutePath() + ".missing");
+ launch.validate();
+ }
}