This is an automated email from the ASF dual-hosted git repository. rombert pushed a commit to branch issue/SLING-12790 in repository https://gitbox.apache.org/repos/asf/sling-feature-launcher-maven-plugin.git
commit 21ac67591aa34aff321ce645dfc82d50aea4a68b Author: Robert Munteanu <[email protected]> AuthorDate: Tue May 20 12:54:13 2025 +0200 SLING-12790 - Allow launching from a feature that is not attached to the project 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(); + } }
