copiedArtifacts;
-
- /**
- * Extra dependencies that need to be installed on the local repository.
+ * Extra dependencies that need to be installed on the local repository.
+ *
* Format:
- *
*
* groupId:artifactId:version:type:classifier
*
- *
+ *
* Examples:
- *
*
* org.apache.maven.plugins:maven-clean-plugin:2.4:maven-plugin
* org.apache.maven.plugins:maven-clean-plugin:2.4:jar:javadoc
*
- *
+ *
* If the type is 'maven-plugin' the plugin will try to resolve the artifact using plugin remote repositories,
* instead of using artifact remote repositories.
+ *
+ * NOTICE all dependencies will be resolved with transitive dependencies in runtime
scope.
*
* @since 1.6
*/
@@ -159,19 +144,12 @@ public class InstallMojo extends AbstractMojo {
private String[] extraArtifacts;
/**
+ * Scope to resolve project artifacts.
+ *
+ * @since 3.5.0
*/
- @Component
- private DependencyResolver resolver;
-
- /**
- * if the local repository is not used as test repo, the parameter can force get artifacts from local repo
- * if available instead of download the artifacts again.
- * @since 3.2.1
- */
- @Parameter(property = "invoker.useLocalRepository", defaultValue = "false")
- private boolean useLocalRepository;
-
- private ProjectBuildingRequest projectBuildingRequest;
+ @Parameter(property = "invoker.install.scope", defaultValue = "runtime")
+ private String scope;
/**
* Performs this mojo's tasks.
@@ -184,377 +162,264 @@ public void execute() throws MojoExecutionException {
return;
}
- createTestRepository();
+ Map resolvedArtifacts = new LinkedHashMap<>();
- installedArtifacts = new HashSet<>();
- copiedArtifacts = new HashSet<>();
+ try {
- installProjectDependencies(project, reactorProjects);
- installProjectParents(project);
- installProjectArtifacts(project);
+ resolveProjectArtifacts(resolvedArtifacts);
+ resolveProjectPoms(project, resolvedArtifacts);
+ resolveProjectDependencies(resolvedArtifacts);
+ resolveExtraArtifacts(resolvedArtifacts);
+ installArtifacts(resolvedArtifacts);
- installExtraArtifacts(extraArtifacts);
+ } catch (DependencyResolutionException | InstallationException | ArtifactResolutionException e) {
+ throw new MojoExecutionException(e.getMessage(), e);
+ }
}
- /**
- * Creates the local repository for the integration tests. If the user specified a custom repository location, the
- * custom repository will have the same identifier, layout and policies as the real local repository. That means
- * apart from the location, the custom repository will be indistinguishable from the real repository such that its
- * usage is transparent to the integration tests.
- *
- * @throws MojoExecutionException If the repository could not be created.
- */
- private void createTestRepository() throws MojoExecutionException {
+ private void resolveProjectArtifacts(Map resolvedArtifacts) {
- if (!localRepositoryPath.exists() && !localRepositoryPath.mkdirs()) {
- throw new MojoExecutionException("Failed to create directory: " + localRepositoryPath);
+ // pom packaging doesn't have a main artifact
+ if (project.getArtifact() != null && project.getArtifact().getFile() != null) {
+ Artifact artifact = RepositoryUtils.toArtifact(project.getArtifact());
+ resolvedArtifacts.put(ArtifactIdUtils.toId(artifact), artifact);
}
- projectBuildingRequest =
- repositoryManager.setLocalRepositoryBasedir(session.getProjectBuildingRequest(), localRepositoryPath);
+
+ project.getAttachedArtifacts().stream()
+ .map(RepositoryUtils::toArtifact)
+ .forEach(a -> resolvedArtifacts.put(ArtifactIdUtils.toId(a), a));
}
- /**
- * Installs the specified artifact to the local repository. Note: This method should only be used for artifacts that
- * originate from the current (reactor) build. Artifacts that have been grabbed from the user's local repository
- * should be installed to the test repository via {@link #copyArtifact(File, Artifact)}.
- *
- * @param file The file associated with the artifact, must not be null
. This is in most cases the value
- * of artifact.getFile()
with the exception of the main artifact from a project with
- * packaging "pom". Projects with packaging "pom" have no main artifact file. They have however artifact
- * metadata (e.g. site descriptors) which needs to be installed.
- * @param artifact The artifact to install, must not be null
.
- * @throws MojoExecutionException If the artifact could not be installed (e.g. has no associated file).
- */
- private void installArtifact(File file, Artifact artifact) throws MojoExecutionException {
- try {
- if (file == null) {
- throw new IllegalStateException("Artifact has no associated file: " + artifact.getId());
- }
- if (!file.isFile()) {
- throw new IllegalStateException("Artifact is not fully assembled: " + file);
- }
+ private void resolveProjectPoms(MavenProject project, Map resolvedArtifacts)
+ throws ArtifactResolutionException {
- if (installedArtifacts.add(artifact.getId())) {
- artifact.setFile(file);
- installer.install(projectBuildingRequest, localRepositoryPath, Collections.singletonList(artifact));
- } else {
- getLog().debug("Not re-installing " + artifact + ", " + file);
- }
- } catch (Exception e) {
- throw new MojoExecutionException("Failed to install artifact: " + artifact, e);
+ if (project == null) {
+ return;
+ }
+
+ Artifact projectPom = RepositoryUtils.toArtifact(new ProjectArtifact(project));
+ if (projectPom.getFile() != null) {
+ resolvedArtifacts.put(projectPom.toString(), projectPom);
+ } else {
+ Artifact artifact = resolveArtifact(projectPom, project.getRemoteProjectRepositories());
+ resolvedArtifacts.put(ArtifactIdUtils.toId(artifact), artifact);
}
+ resolveProjectPoms(project.getParent(), resolvedArtifacts);
}
- /**
- * Installs the specified artifact to the local repository. This method serves basically the same purpose as
- * {@link #installArtifact(File, Artifact)} but is meant for artifacts that have been resolved
- * from the user's local repository (and not the current build outputs). The subtle difference here is that
- * artifacts from the repository have already undergone transformations and these manipulations should not be redone
- * by the artifact installer. For this reason, this method performs plain copy operations to install the artifacts.
- *
- * @param file The file associated with the artifact, must not be null
.
- * @param artifact The artifact to install, must not be null
.
- * @throws MojoExecutionException If the artifact could not be installed (e.g. has no associated file).
- */
- private void copyArtifact(File file, Artifact artifact) throws MojoExecutionException {
- try {
- if (file == null) {
- throw new IllegalStateException("Artifact has no associated file: " + artifact.getId());
- }
- if (!file.isFile()) {
- throw new IllegalStateException("Artifact is not fully assembled: " + file);
- }
+ private void resolveProjectDependencies(Map resolvedArtifacts)
+ throws ArtifactResolutionException, MojoExecutionException, DependencyResolutionException {
- if (copiedArtifacts.add(artifact.getId())) {
- File destination = new File(
- localRepositoryPath,
- repositoryManager.getPathForLocalArtifact(projectBuildingRequest, artifact));
+ DependencyFilter classpathFilter = DependencyFilterUtils.classpathFilter(scope);
- getLog().debug("Installing " + file + " to " + destination);
+ ArtifactTypeRegistry artifactTypeRegistry =
+ session.getRepositorySession().getArtifactTypeRegistry();
- copyFileIfDifferent(file, destination);
+ List managedDependencies = Optional.ofNullable(project.getDependencyManagement())
+ .map(DependencyManagement::getDependencies)
+ .orElseGet(Collections::emptyList)
+ .stream()
+ .map(d -> RepositoryUtils.toDependency(d, artifactTypeRegistry))
+ .collect(Collectors.toList());
- MetadataUtils.createMetadata(destination, artifact);
- } else {
- getLog().debug("Not re-installing " + artifact + ", " + file);
- }
- } catch (Exception e) {
- throw new MojoExecutionException("Failed to stage artifact: " + artifact, e);
- }
- }
+ List dependencies = project.getDependencies().stream()
+ .map(d -> RepositoryUtils.toDependency(d, artifactTypeRegistry))
+ .filter(d -> classpathFilter.accept(new DefaultDependencyNode(d), null))
+ .collect(Collectors.toList());
- private void copyFileIfDifferent(File src, File dst) throws IOException {
- if (src.lastModified() != dst.lastModified() || src.length() != dst.length()) {
- FileUtils.copyFile(src, dst);
- dst.setLastModified(src.lastModified());
- }
- }
+ CollectRequest collectRequest = new CollectRequest();
+ collectRequest.setRootArtifact(RepositoryUtils.toArtifact(project.getArtifact()));
+ collectRequest.setDependencies(dependencies);
+ collectRequest.setManagedDependencies(managedDependencies);
- /**
- * Installs the main artifact and any attached artifacts of the specified project to the local repository.
- *
- * @param mvnProject The project whose artifacts should be installed, must not be null
.
- * @throws MojoExecutionException If any artifact could not be installed.
- */
- private void installProjectArtifacts(MavenProject mvnProject) throws MojoExecutionException {
- try {
- // Install POM (usually attached as metadata but that happens only as a side effect of the Install Plugin)
- installProjectPom(mvnProject);
+ collectRequest.setRepositories(project.getRemoteProjectRepositories());
- // Install the main project artifact (if the project has one, e.g. has no "pom" packaging)
- Artifact mainArtifact = mvnProject.getArtifact();
- if (mainArtifact.getFile() != null) {
- installArtifact(mainArtifact.getFile(), mainArtifact);
- }
+ DependencyRequest request = new DependencyRequest(collectRequest, classpathFilter);
- // Install any attached project artifacts
- Collection attachedArtifacts = mvnProject.getAttachedArtifacts();
- for (Artifact attachedArtifact : attachedArtifacts) {
- installArtifact(attachedArtifact.getFile(), attachedArtifact);
- }
- } catch (Exception e) {
- throw new MojoExecutionException("Failed to install project artifacts: " + mvnProject, e);
- }
- }
+ DependencyResult dependencyResult =
+ repositorySystem.resolveDependencies(session.getRepositorySession(), request);
- /**
- * Installs the (locally reachable) parent POMs of the specified project to the local repository. The parent POMs
- * from the reactor must be installed or the forked IT builds will fail when using a clean repository.
- *
- * @param mvnProject The project whose parent POMs should be installed, must not be null
.
- * @throws MojoExecutionException If any POM could not be installed.
- */
- private void installProjectParents(MavenProject mvnProject) throws MojoExecutionException {
- try {
- for (MavenProject parent = mvnProject.getParent(); parent != null; parent = parent.getParent()) {
- if (parent.getFile() == null) {
- copyParentPoms(parent.getGroupId(), parent.getArtifactId(), parent.getVersion());
- break;
- }
- installProjectPom(parent);
- }
- } catch (Exception e) {
- throw new MojoExecutionException("Failed to install project parents: " + mvnProject, e);
- }
- }
+ List artifacts = dependencyResult.getArtifactResults().stream()
+ .map(ArtifactResult::getArtifact)
+ .collect(Collectors.toList());
- /**
- * Installs the POM of the specified project to the local repository.
- *
- * @param mvnProject The project whose POM should be installed, must not be null
.
- * @throws MojoExecutionException If the POM could not be installed.
- */
- private void installProjectPom(MavenProject mvnProject) throws MojoExecutionException {
- try {
- Artifact pomArtifact = null;
- if ("pom".equals(mvnProject.getPackaging())) {
- pomArtifact = mvnProject.getArtifact();
- }
- if (pomArtifact == null) {
- pomArtifact = artifactFactory.createProjectArtifact(
- mvnProject.getGroupId(), mvnProject.getArtifactId(), mvnProject.getVersion());
- }
- installArtifact(mvnProject.getFile(), pomArtifact);
- } catch (Exception e) {
- throw new MojoExecutionException("Failed to install POM: " + mvnProject, e);
- }
+ artifacts.forEach(a -> resolvedArtifacts.put(ArtifactIdUtils.toId(a), a));
+ resolvePomsForArtifacts(artifacts, resolvedArtifacts, collectRequest.getRepositories());
}
/**
- * Installs the dependent projects from the reactor to the local repository. The dependencies on other modules from
- * the reactor must be installed or the forked IT builds will fail when using a clean repository.
- *
- * @param mvnProject The project whose dependent projects should be installed, must not be null
.
- * @param reactorProjects The set of projects in the reactor build, must not be null
.
- * @throws MojoExecutionException If any dependency could not be installed.
+ * Resolve extra artifacts.
*/
- private void installProjectDependencies(MavenProject mvnProject, Collection reactorProjects)
- throws MojoExecutionException {
- // ... into dependencies that were resolved from reactor projects ...
- Collection dependencyProjects = new LinkedHashSet<>();
- collectAllProjectReferences(mvnProject, dependencyProjects);
-
- // index available reactor projects
- Map projects = new HashMap<>(reactorProjects.size());
- for (MavenProject reactorProject : reactorProjects) {
- String projectId = reactorProject.getGroupId()
- + ':'
- + reactorProject.getArtifactId()
- + ':'
- + reactorProject.getVersion();
-
- projects.put(projectId, reactorProject);
+ private void resolveExtraArtifacts(Map resolvedArtifacts)
+ throws MojoExecutionException, DependencyResolutionException, ArtifactResolutionException {
+
+ if (extraArtifacts == null) {
+ return;
}
- // group transitive dependencies (even those that don't contribute to the class path like POMs) ...
- Collection artifacts = mvnProject.getArtifacts();
- // ... and those that were resolved from the (local) repo
- Collection dependencyArtifacts = new LinkedHashSet<>();
+ DependencyFilter classpathFilter = DependencyFilterUtils.classpathFilter(JavaScopes.RUNTIME);
- for (Artifact artifact : artifacts) {
- // workaround for MNG-2961 to ensure the base version does not contain a timestamp
- artifact.isSnapshot();
+ for (String extraArtifact : extraArtifacts) {
+ String[] gav = extraArtifact.split(":");
+ if (gav.length < 3 || gav.length > 5) {
+ throw new MojoExecutionException("Invalid artifact " + extraArtifact);
+ }
- String projectId = artifact.getGroupId() + ':' + artifact.getArtifactId() + ':' + artifact.getBaseVersion();
+ String groupId = gav[0];
+ String artifactId = gav[1];
+ String version = gav[2];
- if (!projects.containsKey(projectId)) {
- dependencyArtifacts.add(artifact);
+ String type = "jar";
+ if (gav.length > 3) {
+ type = gav[3];
}
- }
- // install dependencies
- try {
- // copy dependencies that where resolved from the local repo
- for (Artifact artifact : dependencyArtifacts) {
- copyArtifact(artifact);
+ String classifier = null;
+ if (gav.length == 5) {
+ classifier = gav[4];
}
- // install dependencies that were resolved from the reactor
- for (String projectId : dependencyProjects) {
- MavenProject dependencyProject = projects.get(projectId);
- if (dependencyProject == null) {
- getLog().warn("skip dependencyProject null for projectId=" + projectId);
- continue;
- }
- installProjectArtifacts(dependencyProject);
- installProjectParents(dependencyProject);
- }
- } catch (Exception e) {
- throw new MojoExecutionException("Failed to install project dependencies: " + mvnProject, e);
- }
- }
+ ArtifactType artifactType =
+ session.getRepositorySession().getArtifactTypeRegistry().get(type);
- protected void collectAllProjectReferences(MavenProject project, Collection dependencyProjects) {
- for (MavenProject reactorProject : project.getProjectReferences().values()) {
- String projectId = reactorProject.getGroupId()
- + ':'
- + reactorProject.getArtifactId()
- + ':'
- + reactorProject.getVersion();
- if (dependencyProjects.add(projectId)) {
- collectAllProjectReferences(reactorProject, dependencyProjects);
- }
- }
- }
+ List remoteRepositories =
+ artifactType != null && "maven-plugin".equals(artifactType.getId())
+ ? project.getRemotePluginRepositories()
+ : project.getRemoteProjectRepositories();
- private void copyArtifact(Artifact artifact) throws MojoExecutionException {
- copyPoms(artifact);
+ Artifact artifact = new DefaultArtifact(groupId, artifactId, classifier, null, version, artifactType);
- Artifact depArtifact = artifactFactory.createArtifactWithClassifier(
- artifact.getGroupId(),
- artifact.getArtifactId(),
- artifact.getBaseVersion(),
- artifact.getType(),
- artifact.getClassifier());
+ resolvePomsForArtifacts(Collections.singletonList(artifact), resolvedArtifacts, remoteRepositories);
- File artifactFile = artifact.getFile();
+ CollectRequest collectRequest = new CollectRequest();
+ Dependency root = new Dependency(artifact, JavaScopes.COMPILE);
+ collectRequest.setRoot(root);
+ collectRequest.setRepositories(remoteRepositories);
- copyArtifact(artifactFile, depArtifact);
- }
+ DependencyRequest request = new DependencyRequest(collectRequest, classpathFilter);
+ DependencyResult dependencyResult =
+ repositorySystem.resolveDependencies(session.getRepositorySession(), request);
- private void copyPoms(Artifact artifact) throws MojoExecutionException {
- Artifact pomArtifact = artifactFactory.createProjectArtifact(
- artifact.getGroupId(), artifact.getArtifactId(), artifact.getBaseVersion());
+ List artifacts = dependencyResult.getArtifactResults().stream()
+ .map(ArtifactResult::getArtifact)
+ .collect(Collectors.toList());
- File pomFile = new File(localRepository.getBasedir(), localRepository.pathOf(pomArtifact));
+ artifacts.forEach(a -> resolvedArtifacts.put(ArtifactIdUtils.toId(a), a));
+ resolvePomsForArtifacts(artifacts, resolvedArtifacts, collectRequest.getRepositories());
+ }
+ }
+
+ private void resolvePomsForArtifacts(
+ List artifacts,
+ Map resolvedArtifacts,
+ List remoteRepositories)
+ throws ArtifactResolutionException, MojoExecutionException {
- if (pomFile.isFile()) {
- copyArtifact(pomFile, pomArtifact);
- copyParentPoms(pomFile);
+ for (Artifact a : artifacts) {
+ Artifact artifactResult = resolveArtifact(new SubArtifact(a, "", "pom"), remoteRepositories);
+ resolvePomWithParents(artifactResult, resolvedArtifacts, remoteRepositories);
}
}
- /**
- * Installs all parent POMs of the specified POM file that are available in the local repository.
- *
- * @param pomFile The path to the POM file whose parents should be installed, must not be null
.
- * @throws MojoExecutionException If any (existing) parent POM could not be installed.
- */
- private void copyParentPoms(File pomFile) throws MojoExecutionException {
- Model model = PomUtils.loadPom(pomFile);
+ private void resolvePomWithParents(
+ Artifact artifact, Map resolvedArtifacts, List remoteRepositories)
+ throws MojoExecutionException, ArtifactResolutionException {
+
+ if (resolvedArtifacts.containsKey(ArtifactIdUtils.toId(artifact))) {
+ return;
+ }
+
+ Model model = PomUtils.loadPom(artifact.getFile());
Parent parent = model.getParent();
if (parent != null) {
- copyParentPoms(parent.getGroupId(), parent.getArtifactId(), parent.getVersion());
+ DefaultArtifact pom =
+ new DefaultArtifact(parent.getGroupId(), parent.getArtifactId(), "", "pom", parent.getVersion());
+ Artifact resolvedPom = resolveArtifact(pom, remoteRepositories);
+ resolvePomWithParents(resolvedPom, resolvedArtifacts, remoteRepositories);
}
+
+ resolvedArtifacts.put(ArtifactIdUtils.toId(artifact), artifact);
+ }
+
+ private Artifact resolveArtifact(Artifact artifact, List remoteRepositories)
+ throws ArtifactResolutionException {
+
+ ArtifactRequest request = new ArtifactRequest();
+ request.setArtifact(artifact);
+ request.setRepositories(remoteRepositories);
+ ArtifactResult artifactResult = repositorySystem.resolveArtifact(session.getRepositorySession(), request);
+ return artifactResult.getArtifact();
}
/**
- * Installs the specified POM and all its parent POMs to the local repository.
- *
- * @param groupId The group id of the POM which should be installed, must not be null
.
- * @param artifactId The artifact id of the POM which should be installed, must not be null
.
- * @param version The version of the POM which should be installed, must not be null
.
- * @throws MojoExecutionException If any (existing) parent POM could not be installed.
+ * Install list of artifacts into local repository.
*/
- private void copyParentPoms(String groupId, String artifactId, String version) throws MojoExecutionException {
- Artifact pomArtifact = artifactFactory.createProjectArtifact(groupId, artifactId, version);
+ private void installArtifacts(Map resolvedArtifacts) throws InstallationException {
- if (installedArtifacts.contains(pomArtifact.getId()) || copiedArtifacts.contains(pomArtifact.getId())) {
- getLog().debug("Not re-installing " + pomArtifact);
- return;
- }
+ RepositorySystemSession systemSessionForLocalRepo = createSystemSessionForLocalRepo();
- File pomFile = new File(localRepository.getBasedir(), localRepository.pathOf(pomArtifact));
- if (pomFile.isFile()) {
- copyArtifact(pomFile, pomArtifact);
- copyParentPoms(pomFile);
- }
- }
+ // we can have on dependency two artifacts with the same groupId:artifactId
+ // with different version, in such case when we install both in one request
+ // metadata will contain only one version
- private void installExtraArtifacts(String[] extraArtifacts) throws MojoExecutionException {
- if (extraArtifacts == null) {
- return;
+ Map> collect = resolvedArtifacts.values().stream()
+ .filter(a -> !hasTheSamePathAsTarget(a, systemSessionForLocalRepo))
+ .collect(Collectors.groupingBy(
+ a -> String.format("%s:%s:%s", a.getGroupId(), a.getArtifactId(), a.getVersion()),
+ LinkedHashMap::new,
+ Collectors.toList()));
+
+ for (List artifacts : collect.values()) {
+ InstallRequest request = new InstallRequest();
+ request.setArtifacts(artifacts);
+ repositorySystem.install(systemSessionForLocalRepo, request);
}
+ }
- for (String extraArtifact : extraArtifacts) {
- String[] gav = extraArtifact.split(":");
- if (gav.length < 3 || gav.length > 5) {
- throw new MojoExecutionException("Invalid artifact " + extraArtifact);
+ private boolean hasTheSamePathAsTarget(Artifact artifact, RepositorySystemSession systemSession) {
+ try {
+ LocalRepositoryManager lrm = systemSession.getLocalRepositoryManager();
+ File targetBasedir = lrm.getRepository().getBasedir();
+ if (targetBasedir == null) {
+ return false;
}
-
- String groupId = gav[0];
- String artifactId = gav[1];
- String version = gav[2];
-
- String type = "jar";
- if (gav.length > 3) {
- type = gav[3];
+ File targetFile = new File(targetBasedir, lrm.getPathForLocalArtifact(artifact)).getCanonicalFile();
+ File sourceFile = artifact.getFile().getCanonicalFile();
+ if (Objects.equals(targetFile, sourceFile)) {
+ getLog().debug("Skip install the same target " + sourceFile);
+ return true;
}
+ return false;
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
- String classifier = null;
- if (gav.length == 5) {
- classifier = gav[4];
+ /**
+ * Create a new {@link RepositorySystemSession} connected with local repo.
+ */
+ private RepositorySystemSession createSystemSessionForLocalRepo() {
+ RepositorySystemSession repositorySystemSession = session.getRepositorySession();
+ if (localRepositoryPath != null) {
+ // "clone" repository session and replace localRepository
+ DefaultRepositorySystemSession newSession =
+ new DefaultRepositorySystemSession(session.getRepositorySession());
+ // Clear cache, since we're using a new local repository
+ newSession.setCache(new DefaultRepositoryCache());
+ // keep same repositoryType
+ String contentType = newSession.getLocalRepository().getContentType();
+ if ("enhanced".equals(contentType)) {
+ contentType = "default";
}
+ LocalRepositoryManager localRepositoryManager = repositorySystem.newLocalRepositoryManager(
+ newSession, new LocalRepository(localRepositoryPath, contentType));
- DefaultDependableCoordinate coordinate = new DefaultDependableCoordinate();
- try {
- coordinate.setGroupId(groupId);
- coordinate.setArtifactId(artifactId);
- coordinate.setVersion(version);
- coordinate.setType(type);
- coordinate.setClassifier(classifier);
-
- if (!localRepository.getBasedir().equals(localRepositoryPath.getPath()) && useLocalRepository) {
- String previousId = localRepository.getId();
- try {
- // using another request with the correct target repo
- ProjectBuildingRequest projectBuildingRequest = repositoryManager.setLocalRepositoryBasedir(
- session.getProjectBuildingRequest(), localRepositoryPath);
- projectBuildingRequest.setRemoteRepositories(Collections.singletonList(localRepository));
- resolver.resolveDependencies(
- projectBuildingRequest,
- coordinate,
- new PatternExclusionsFilter(Collections.emptyList()));
- } finally {
- localRepository.setId(previousId);
- }
- } else {
- resolver.resolveDependencies(
- projectBuildingRequest, coordinate, new PatternExclusionsFilter(Collections.emptyList()));
- }
- } catch (DependencyResolverException e) {
- throw new MojoExecutionException("Unable to resolve dependencies for: " + coordinate, e);
- }
+ newSession.setLocalRepositoryManager(localRepositoryManager);
+ repositorySystemSession = newSession;
+ getLog().debug("localRepoPath: "
+ + localRepositoryManager.getRepository().getBasedir());
}
+
+ return repositorySystemSession;
}
}
diff --git a/src/main/java/org/apache/maven/plugins/invoker/InterpolatorUtils.java b/src/main/java/org/apache/maven/plugins/invoker/InterpolatorUtils.java
new file mode 100644
index 00000000..a4804b9b
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugins/invoker/InterpolatorUtils.java
@@ -0,0 +1,62 @@
+/*
+ * 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.maven.plugins.invoker;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.interpolation.InterpolationException;
+import org.codehaus.plexus.interpolation.Interpolator;
+import org.codehaus.plexus.interpolation.MapBasedValueSource;
+import org.codehaus.plexus.interpolation.RegexBasedInterpolator;
+
+/**
+ * Helper component for interpolating values.
+ */
+@Named
+class InterpolatorUtils {
+
+ private final Interpolator atInterpolator;
+
+ /**
+ * A default constructor.
+ *
+ * @param mavenProject a MavenProject
+ */
+ @Inject
+ InterpolatorUtils(MavenProject mavenProject) {
+ atInterpolator = new RegexBasedInterpolator("[@\\$]\\{(.+?)", "}");
+ atInterpolator.addValueSource(new MapBasedValueSource(mavenProject.getProperties()));
+ }
+
+ public String interpolateAtPattern(String value) throws MojoExecutionException {
+
+ if (value == null || !(value.contains("@{") || value.contains("${"))) {
+ return value;
+ }
+
+ try {
+ return atInterpolator.interpolate(value);
+ } catch (InterpolationException e) {
+ throw new MojoExecutionException(e.getMessage(), e);
+ }
+ }
+}
diff --git a/src/main/java/org/apache/maven/plugins/invoker/InvokerProperties.java b/src/main/java/org/apache/maven/plugins/invoker/InvokerProperties.java
index 08721a0f..4bf09e71 100644
--- a/src/main/java/org/apache/maven/plugins/invoker/InvokerProperties.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/InvokerProperties.java
@@ -32,7 +32,8 @@
import java.util.regex.Pattern;
import org.apache.maven.shared.invoker.InvocationRequest;
-import org.codehaus.plexus.util.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Provides a convenient facade around the invoker.properties
.
@@ -40,10 +41,13 @@
* @author Benjamin Bentmann
*/
class InvokerProperties {
+
+ private final Logger logger = LoggerFactory.getLogger(InvokerProperties.class);
+
private static final String SELECTOR_PREFIX = "selector.";
private static final Pattern ENVIRONMENT_VARIABLES_PATTERN =
- Pattern.compile("invoker\\.environmentVariables\\.([A-Za-z][^.]+)(\\.([0-9]+))?");
+ Pattern.compile("invoker\\.environmentVariables\\.([A-Za-z][^.]+)(\\.(\\d+))?");
// default values from Mojo configuration
private Boolean defaultDebug;
@@ -55,6 +59,7 @@ class InvokerProperties {
private Map defaultEnvironmentVariables;
private File defaultMavenExecutable;
private Boolean defaultUpdateSnapshots;
+ private String defaultUserPropertiesFiles;
private enum InvocationProperty {
PROJECT("invoker.project"),
@@ -67,6 +72,7 @@ private enum InvocationProperty {
NON_RECURSIVE("invoker.nonRecursive"),
OFFLINE("invoker.offline"),
SYSTEM_PROPERTIES_FILE("invoker.systemPropertiesFile"),
+ USER_PROPERTIES_FILE("invoker.userPropertiesFile"),
DEBUG("invoker.debug"),
QUIET("invoker.quiet"),
SETTINGS_FILE("invoker.settingsFile"),
@@ -88,7 +94,7 @@ public String toString() {
private enum SelectorProperty {
JAVA_VERSION(".java.version"),
MAVEN_VERSION(".maven.version"),
- OS_FAMLY(".os.family");
+ OS_FAMILY(".os.family");
private final String suffix;
@@ -153,8 +159,10 @@ public void setDefaultProfiles(List defaultProfiles) {
* Default value for mavenExecutable
* @param defaultMavenExecutable a default value
*/
- public void setDefaultMavenExecutable(File defaultMavenExecutable) {
- this.defaultMavenExecutable = defaultMavenExecutable;
+ public void setDefaultMavenExecutable(String defaultMavenExecutable) {
+ if (Objects.nonNull(defaultMavenExecutable) && !defaultMavenExecutable.isEmpty()) {
+ this.defaultMavenExecutable = new File(defaultMavenExecutable);
+ }
}
/**
@@ -189,6 +197,14 @@ public void setDefaultUpdateSnapshots(boolean defaultUpdateSnapshots) {
this.defaultUpdateSnapshots = defaultUpdateSnapshots;
}
+ /**
+ * Default value for userPropertiesFile
+ * @param defaultUserPropertiesFiles a default value
+ */
+ public void setDefaultUserPropertiesFiles(String defaultUserPropertiesFiles) {
+ this.defaultUserPropertiesFiles = defaultUserPropertiesFiles;
+ }
+
/**
* Gets the invoker properties being wrapped.
*
@@ -279,7 +295,7 @@ public String getOsFamily() {
* @since 3.0.0
*/
public String getOsFamily(int index) {
- return this.properties.getProperty(SELECTOR_PREFIX + index + SelectorProperty.OS_FAMLY, getOsFamily());
+ return this.properties.getProperty(SELECTOR_PREFIX + index + SelectorProperty.OS_FAMILY, getOsFamily());
}
public Collection getToolchains() {
@@ -395,7 +411,7 @@ public void configureInvocation(InvocationRequest request, int index) {
setIfNotNull(
request::setGoals,
get(InvocationProperty.GOALS, index)
- .map(s -> StringUtils.split(s, ", \t\n\r\f"))
+ .map(s -> s.trim().split("\\s*[ ,]+\\s*"))
.map(Arrays::asList)
.filter(l -> !l.isEmpty())
.orElse(defaultGoals));
@@ -403,7 +419,7 @@ public void configureInvocation(InvocationRequest request, int index) {
setIfNotNull(
request::setProfiles,
get(InvocationProperty.PROFILES, index)
- .map(s -> StringUtils.split(s, ", \t\n\r\f"))
+ .map(s -> s.trim().split("\\s*[ ,]+\\s*"))
.map(Arrays::asList)
.filter(l -> !l.isEmpty())
.orElse(defaultProfiles));
@@ -466,13 +482,33 @@ public boolean isExpectedResult(int exitCode, int index) {
}
/**
- * Gets the path to the properties file used to set the system properties for the specified invocation.
+ * Gets the path to the properties file used to set the user properties for the specified invocation.
*
* @param index The index of the invocation, must not be negative.
* @return The path to the properties file or null
if not set.
*/
- public String getSystemPropertiesFile(int index) {
- return get(InvocationProperty.SYSTEM_PROPERTIES_FILE, index).orElse(null);
+ public String getUserPropertiesFile(int index) {
+ Optional userProperties = get(InvocationProperty.USER_PROPERTIES_FILE, index);
+ Optional systemProperties = get(InvocationProperty.SYSTEM_PROPERTIES_FILE, index);
+
+ if (userProperties.isPresent() && systemProperties.isPresent()) {
+ throw new IllegalArgumentException("only one property '" + InvocationProperty.USER_PROPERTIES_FILE
+ + "' or '" + InvocationProperty.SYSTEM_PROPERTIES_FILE + "' can be used");
+ }
+
+ if (userProperties.isPresent()) {
+ return userProperties.get();
+ }
+
+ if (systemProperties.isPresent()) {
+ logger.warn(
+ "property {} is deprecated - please use {}",
+ InvocationProperty.SYSTEM_PROPERTIES_FILE,
+ InvocationProperty.USER_PROPERTIES_FILE);
+ return systemProperties.get();
+ }
+
+ return defaultUserPropertiesFiles;
}
/**
diff --git a/src/main/java/org/apache/maven/plugins/invoker/InvokerReport.java b/src/main/java/org/apache/maven/plugins/invoker/InvokerReport.java
index bd3708de..ebc47b3d 100644
--- a/src/main/java/org/apache/maven/plugins/invoker/InvokerReport.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/InvokerReport.java
@@ -20,15 +20,10 @@
import java.io.File;
import java.io.IOException;
-import java.text.DecimalFormat;
-import java.text.DecimalFormatSymbols;
-import java.text.MessageFormat;
-import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
-import org.apache.maven.doxia.sink.Sink;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
@@ -37,8 +32,6 @@
import org.apache.maven.reporting.AbstractMavenReport;
import org.apache.maven.reporting.MavenReportException;
import org.codehaus.plexus.i18n.I18N;
-import org.codehaus.plexus.util.ReaderFactory;
-import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.xml.XmlStreamReader;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
@@ -53,12 +46,6 @@
@Mojo(name = "report", threadSafe = true)
public class InvokerReport extends AbstractMavenReport {
- /**
- * Internationalization component.
- */
- @Component
- protected I18N i18n;
-
/**
* Base directory where all build reports have been written to.
*/
@@ -66,61 +53,17 @@ public class InvokerReport extends AbstractMavenReport {
private File reportsDirectory;
/**
- * The number format used to print percent values in the report locale.
- */
- private NumberFormat percentFormat;
-
- /**
- * The number format used to print time values in the report locale.
- */
- private NumberFormat secondsFormat;
-
- /**
- * The format used to print build name and description.
+ * Internationalization component
*/
- private MessageFormat nameAndDescriptionFormat;
+ @Component
+ protected I18N i18n;
protected void executeReport(Locale locale) throws MavenReportException {
- DecimalFormatSymbols symbols = new DecimalFormatSymbols(locale);
- percentFormat = new DecimalFormat(getText(locale, "report.invoker.format.percent"), symbols);
- secondsFormat = new DecimalFormat(getText(locale, "report.invoker.format.seconds"), symbols);
- nameAndDescriptionFormat = new MessageFormat(getText(locale, "report.invoker.format.name_with_description"));
-
- Sink sink = getSink();
-
- sink.head();
-
- sink.title();
- sink.text(getText(locale, "report.invoker.result.title"));
- sink.title_();
-
- sink.head_();
-
- sink.body();
-
- sink.section1();
- sink.sectionTitle1();
- sink.text(getText(locale, "report.invoker.result.title"));
- sink.sectionTitle1_();
- sink.paragraph();
- sink.text(getText(locale, "report.invoker.result.description"));
- sink.paragraph_();
- sink.section1_();
-
- // ----------------------------------
- // build buildJob beans
- // ----------------------------------
- File[] reportFiles = ReportUtils.getReportFiles(reportsDirectory);
- if (reportFiles.length <= 0) {
- getLog().info("no invoker report files found, skip report generation");
- return;
- }
-
+ File[] reportFiles = getReportFiles();
BuildJobXpp3Reader buildJobReader = new BuildJobXpp3Reader();
-
List buildJobs = new ArrayList<>(reportFiles.length);
for (File reportFile : reportFiles) {
- try (XmlStreamReader xmlReader = ReaderFactory.newXmlReader(reportFile)) {
+ try (XmlStreamReader xmlReader = new XmlStreamReader(reportFile)) {
buildJobs.add(buildJobReader.read(xmlReader));
} catch (XmlPullParserException e) {
throw new MavenReportException("Failed to parse report file: " + reportFile, e);
@@ -128,193 +71,39 @@ protected void executeReport(Locale locale) throws MavenReportException {
throw new MavenReportException("Failed to read report file: " + reportFile, e);
}
}
-
- // ----------------------------------
- // summary
- // ----------------------------------
-
- constructSummarySection(buildJobs, locale);
-
- // ----------------------------------
- // per file/it detail
- // ----------------------------------
-
- sink.section2();
- sink.sectionTitle2();
-
- sink.text(getText(locale, "report.invoker.detail.title"));
-
- sink.sectionTitle2_();
-
- sink.section2_();
-
- // detail tests table header
- sink.table();
- sink.tableRows(null, false);
-
- sink.tableRow();
- // -------------------------------------------
- // name | Result | time | message
- // -------------------------------------------
- sinkTableHeader(sink, getText(locale, "report.invoker.detail.name"));
- sinkTableHeader(sink, getText(locale, "report.invoker.detail.result"));
- sinkTableHeader(sink, getText(locale, "report.invoker.detail.time"));
- sinkTableHeader(sink, getText(locale, "report.invoker.detail.message"));
-
- sink.tableRow_();
-
- for (BuildJob buildJob : buildJobs) {
- renderBuildJob(buildJob);
- }
-
- sink.tableRows_();
- sink.table_();
-
- sink.body_();
-
- sink.flush();
- sink.close();
+ InvokerReportRenderer r = new InvokerReportRenderer(getSink(), i18n, locale, getLog(), buildJobs);
+ r.render();
}
- private void constructSummarySection(List extends BuildJob> buildJobs, Locale locale) {
- Sink sink = getSink();
-
- sink.section2();
- sink.sectionTitle2();
-
- sink.text(getText(locale, "report.invoker.summary.title"));
-
- sink.sectionTitle2_();
- sink.section2_();
-
- // ------------------------------------------------------------------------
- // Building a table with
- // it number | succes nb | failed nb | Success rate | total time | avg time
- // ------------------------------------------------------------------------
-
- sink.table();
- sink.tableRows(null, false);
-
- sink.tableRow();
-
- sinkTableHeader(sink, getText(locale, "report.invoker.summary.number"));
- sinkTableHeader(sink, getText(locale, "report.invoker.summary.success"));
- sinkTableHeader(sink, getText(locale, "report.invoker.summary.failed"));
- sinkTableHeader(sink, getText(locale, "report.invoker.summary.skipped"));
- sinkTableHeader(sink, getText(locale, "report.invoker.summary.success.rate"));
- sinkTableHeader(sink, getText(locale, "report.invoker.summary.time.total"));
- sinkTableHeader(sink, getText(locale, "report.invoker.summary.time.avg"));
-
- int number = buildJobs.size();
- int success = 0;
- int failed = 0;
- int skipped = 0;
- double totalTime = 0;
-
- for (BuildJob buildJob : buildJobs) {
- if (BuildJob.Result.SUCCESS.equals(buildJob.getResult())) {
- success++;
- } else if (BuildJob.Result.SKIPPED.equals(buildJob.getResult())) {
- skipped++;
- } else {
- failed++;
- }
- totalTime += buildJob.getTime();
- }
-
- sink.tableRow_();
- sink.tableRow();
-
- sinkCell(sink, Integer.toString(number));
- sinkCell(sink, Integer.toString(success));
- sinkCell(sink, Integer.toString(failed));
- sinkCell(sink, Integer.toString(skipped));
-
- if (success + failed > 0) {
- sinkCell(sink, percentFormat.format((double) success / (success + failed)));
- } else {
- sinkCell(sink, "");
- }
-
- sinkCell(sink, secondsFormat.format(totalTime));
-
- sinkCell(sink, secondsFormat.format(totalTime / number));
-
- sink.tableRow_();
-
- sink.tableRows_();
- sink.table_();
- }
-
- private void renderBuildJob(BuildJob buildJob) {
- Sink sink = getSink();
- sink.tableRow();
- sinkCell(sink, getBuildJobReportName(buildJob));
- // FIXME image
- sinkCell(sink, buildJob.getResult());
- sinkCell(sink, secondsFormat.format(buildJob.getTime()));
- sinkCell(sink, buildJob.getFailureMessage());
- sink.tableRow_();
- }
-
- private String getBuildJobReportName(BuildJob buildJob) {
- String buildJobName = buildJob.getName();
- String buildJobDescription = buildJob.getDescription();
- boolean emptyJobName = StringUtils.isEmpty(buildJobName);
- boolean emptyJobDescription = StringUtils.isEmpty(buildJobDescription);
- boolean isReportJobNameComplete = !emptyJobName && !emptyJobDescription;
- if (isReportJobNameComplete) {
- return getFormattedName(buildJobName, buildJobDescription);
- } else {
- String buildJobProject = buildJob.getProject();
- if (!emptyJobName) {
- getLog().warn(incompleteNameWarning("description", buildJobProject));
- } else if (!emptyJobDescription) {
- getLog().warn(incompleteNameWarning("name", buildJobProject));
- }
- return buildJobProject;
- }
- }
-
- private static String incompleteNameWarning(String missing, String pom) {
- return String.format(
- "Incomplete job name-description: %s is missing. " + "POM (%s) will be used in place of job name.",
- missing, pom);
+ /**
+ * @param locale The locale
+ * @param key The key to search for
+ * @return The text appropriate for the locale.
+ */
+ private String getI18nString(Locale locale, String key) {
+ return i18n.getString("invoker-report", locale, "report.invoker." + key);
}
- private String getFormattedName(String name, String description) {
- return nameAndDescriptionFormat.format(new Object[] {name, description});
+ /** {@inheritDoc} */
+ public String getName(Locale locale) {
+ return getI18nString(locale, "name");
}
+ /** {@inheritDoc} */
public String getDescription(Locale locale) {
- return getText(locale, "report.invoker.result.description");
- }
-
- public String getName(Locale locale) {
- return getText(locale, "report.invoker.result.name");
+ return getI18nString(locale, "description");
}
public String getOutputName() {
- return "invoker-report";
+ return "invoker";
}
- public boolean canGenerateReport() {
- return ReportUtils.getReportFiles(reportsDirectory).length > 0;
+ private File[] getReportFiles() {
+ return ReportUtils.getReportFiles(reportsDirectory);
}
- private String getText(Locale locale, String key) {
- return i18n.getString("invoker-report", locale, key);
- }
-
- private void sinkTableHeader(Sink sink, String header) {
- sink.tableHeaderCell();
- sink.text(header);
- sink.tableHeaderCell_();
- }
-
- private void sinkCell(Sink sink, String text) {
- sink.tableCell();
- sink.text(text);
- sink.tableCell_();
+ @Override
+ public boolean canGenerateReport() {
+ return getReportFiles().length > 0;
}
}
diff --git a/src/main/java/org/apache/maven/plugins/invoker/InvokerReportRenderer.java b/src/main/java/org/apache/maven/plugins/invoker/InvokerReportRenderer.java
new file mode 100644
index 00000000..3958a0a2
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugins/invoker/InvokerReportRenderer.java
@@ -0,0 +1,182 @@
+/*
+ * 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.maven.plugins.invoker;
+
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.maven.doxia.sink.Sink;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.plugins.invoker.model.BuildJob;
+import org.apache.maven.reporting.AbstractMavenReportRenderer;
+import org.codehaus.plexus.i18n.I18N;
+
+public class InvokerReportRenderer extends AbstractMavenReportRenderer {
+ private final I18N i18n;
+ private final Locale locale;
+ private final Log log;
+ private final List buildJobs;
+
+ public InvokerReportRenderer(Sink sink, I18N i18n, Locale locale, Log log, List buildJobs) {
+ super(sink);
+ this.i18n = i18n;
+ this.locale = locale;
+ this.log = log;
+ this.buildJobs = buildJobs;
+ }
+
+ @Override
+ public String getTitle() {
+ return getI18nString("title");
+ }
+
+ /**
+ * @param key The key to translate.
+ * @return the translated key.
+ */
+ private String getI18nString(String key) {
+ return i18n.getString("invoker-report", locale, "report.invoker." + key);
+ }
+
+ /**
+ * @param key The key to translate.
+ * @param args The args to pass to translated string.
+ * @return the translated key.
+ */
+ private String formatI18nString(String key, Object... args) {
+ return i18n.format("invoker-report", locale, "report.invoker." + key, args);
+ }
+
+ @Override
+ protected void renderBody() {
+ startSection(getTitle());
+ paragraph(getI18nString("description"));
+
+ renderSectionSummary();
+
+ renderSectionDetails();
+
+ endSection();
+ }
+
+ private void renderSectionSummary() {
+ startSection(getI18nString("summary.title"));
+
+ startTable();
+
+ tableHeader(new String[] {
+ getI18nString("summary.builds"),
+ getI18nString("summary.success"),
+ getI18nString("summary.failures"),
+ getI18nString("summary.skipped"),
+ getI18nString("summary.successrate"),
+ getI18nString("summary.time")
+ });
+
+ int totalBuilds = buildJobs.size();
+ int totalSuccess = 0;
+ int totalFailures = 0;
+ int totalSkipped = 0;
+ float totalTime = 0.0f;
+
+ for (BuildJob buildJob : buildJobs) {
+ switch (buildJob.getResult()) {
+ case BuildJob.Result.SUCCESS:
+ totalSuccess++;
+ break;
+ case BuildJob.Result.SKIPPED:
+ totalSkipped++;
+ break;
+ default:
+ totalFailures++;
+ }
+ totalTime += buildJob.getTime();
+ }
+
+ tableRow(new String[] {
+ Integer.toString(totalBuilds),
+ Integer.toString(totalSuccess),
+ Integer.toString(totalFailures),
+ Integer.toString(totalSkipped),
+ (totalSuccess + totalFailures > 0)
+ ? formatI18nString("value.successrate", (totalSuccess / (float) (totalSuccess + totalFailures)))
+ : "",
+ formatI18nString("value.time", totalTime)
+ });
+
+ endTable();
+
+ endSection();
+ }
+
+ private void renderSectionDetails() {
+ startSection(getI18nString("detail.title"));
+
+ startTable();
+
+ tableHeader(new String[] {
+ getI18nString("detail.name"),
+ getI18nString("detail.result"),
+ getI18nString("detail.time"),
+ getI18nString("detail.message")
+ });
+
+ for (BuildJob buildJob : buildJobs) {
+ renderBuildJob(buildJob);
+ }
+
+ endTable();
+
+ endSection();
+ }
+
+ private void renderBuildJob(BuildJob buildJob) {
+ tableRow(new String[] {
+ getBuildJobReportName(buildJob),
+ // FIXME image
+ buildJob.getResult(),
+ formatI18nString("value.time", buildJob.getTime()),
+ buildJob.getFailureMessage()
+ });
+ }
+
+ private String getBuildJobReportName(BuildJob buildJob) {
+ String buildJobName = buildJob.getName();
+ String buildJobDescription = buildJob.getDescription();
+ boolean emptyJobName = buildJobName == null || buildJobName.isEmpty();
+ boolean emptyJobDescription = buildJobDescription == null || buildJobDescription.isEmpty();
+ boolean isReportJobNameComplete = !emptyJobName && !emptyJobDescription;
+ if (isReportJobNameComplete) {
+ return formatI18nString("text.name_with_description", buildJobName, buildJobDescription);
+ } else {
+ String buildJobProject = buildJob.getProject();
+ if (!emptyJobName) {
+ log.warn(incompleteNameWarning("description", buildJobProject));
+ } else if (!emptyJobDescription) {
+ log.warn(incompleteNameWarning("name", buildJobProject));
+ }
+ return buildJobProject;
+ }
+ }
+
+ private static String incompleteNameWarning(String missing, String pom) {
+ return "Incomplete job name-description: " + missing + " is missing. POM (" + pom
+ + ") will be used in place of job name!";
+ }
+}
diff --git a/src/main/java/org/apache/maven/plugins/invoker/InvokerSession.java b/src/main/java/org/apache/maven/plugins/invoker/InvokerSession.java
index 9f47c1eb..a6667449 100644
--- a/src/main/java/org/apache/maven/plugins/invoker/InvokerSession.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/InvokerSession.java
@@ -27,7 +27,7 @@
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.plugins.invoker.model.BuildJob;
-import org.apache.maven.shared.utils.io.IOUtil;
+import org.codehaus.plexus.util.IOUtil;
import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
@@ -38,7 +38,7 @@
*/
class InvokerSession {
private static final String SEPARATOR =
- buffer().strong("-------------------------------------------------").toString();
+ buffer().strong("-------------------------------------------------").build();
private List buildJobs;
diff --git a/src/main/java/org/apache/maven/plugins/invoker/InvokerToolchain.java b/src/main/java/org/apache/maven/plugins/invoker/InvokerToolchain.java
index a2e879b9..c132712c 100644
--- a/src/main/java/org/apache/maven/plugins/invoker/InvokerToolchain.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/InvokerToolchain.java
@@ -29,7 +29,7 @@
public class InvokerToolchain {
private final String type;
- private Map provides = new HashMap<>();
+ private final Map provides = new HashMap<>();
public InvokerToolchain(String type) {
this.type = type;
diff --git a/src/main/java/org/apache/maven/plugins/invoker/JobExecutor.java b/src/main/java/org/apache/maven/plugins/invoker/JobExecutor.java
index 3e2c3744..704e214a 100644
--- a/src/main/java/org/apache/maven/plugins/invoker/JobExecutor.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/JobExecutor.java
@@ -18,6 +18,7 @@
*/
package org.apache.maven.plugins.invoker;
+import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -49,7 +50,7 @@ interface ThrowableJobConsumer {
public void forEach(ThrowableJobConsumer jobConsumer) {
// group and sort jobs by ordinal
Map> groupedJobs = jobs.stream()
- .sorted((j1, j2) -> Integer.compare(j2.getOrdinal(), j1.getOrdinal()))
+ .sorted(Comparator.comparing(BuildJob::getOrdinal).reversed())
.collect(Collectors.groupingBy(BuildJob::getOrdinal, LinkedHashMap::new, Collectors.toList()));
ExecutorService executorService = Executors.newFixedThreadPool(threadsCount);
diff --git a/src/main/java/org/apache/maven/plugins/invoker/MetadataUtils.java b/src/main/java/org/apache/maven/plugins/invoker/MetadataUtils.java
deleted file mode 100644
index 13d2c4a4..00000000
--- a/src/main/java/org/apache/maven/plugins/invoker/MetadataUtils.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * 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.maven.plugins.invoker;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.Reader;
-import java.io.Writer;
-import java.text.SimpleDateFormat;
-import java.util.Collection;
-import java.util.Date;
-import java.util.LinkedHashSet;
-import java.util.Set;
-import java.util.TimeZone;
-
-import org.apache.maven.artifact.Artifact;
-import org.codehaus.plexus.util.ReaderFactory;
-import org.codehaus.plexus.util.WriterFactory;
-import org.codehaus.plexus.util.xml.Xpp3Dom;
-import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
-import org.codehaus.plexus.util.xml.Xpp3DomUtils;
-import org.codehaus.plexus.util.xml.Xpp3DomWriter;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
-
-/**
- * Provides utility methods for artifact metadata processing.
- *
- * @author Benjamin Bentmann
- */
-class MetadataUtils {
-
- /**
- * Creates local metadata files for the specified artifact. The goal is to simulate the installation of the artifact
- * by a local build, thereby decoupling the forked builds from the inderministic collection of remote repositories
- * that are available to the main build and from which the artifact was originally resolved.
- *
- * @param file The artifact's file in the local test repository, must not be null
.
- * @param artifact The artifact to create metadata for, must not be null
.
- * @throws IOException If the metadata could not be created.
- */
- public static void createMetadata(File file, Artifact artifact) throws IOException {
- TimeZone tz = java.util.TimeZone.getTimeZone("UTC");
- SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMddHHmmss");
- fmt.setTimeZone(tz);
- String timestamp = fmt.format(new Date());
-
- if (artifact.isSnapshot()) {
- File metadataFile = new File(file.getParentFile(), "maven-metadata-local.xml");
-
- Xpp3Dom metadata = new Xpp3Dom("metadata");
- addChild(metadata, "groupId", artifact.getGroupId());
- addChild(metadata, "artifactId", artifact.getArtifactId());
- addChild(metadata, "version", artifact.getBaseVersion());
- Xpp3Dom versioning = new Xpp3Dom("versioning");
- versioning.addChild(addChild(new Xpp3Dom("snapshot"), "localCopy", "true"));
- addChild(versioning, "lastUpdated", timestamp);
- metadata.addChild(versioning);
-
- writeMetadata(metadataFile, metadata);
- }
-
- File metadataFile = new File(file.getParentFile().getParentFile(), "maven-metadata-local.xml");
-
- Set allVersions = new LinkedHashSet<>();
-
- Xpp3Dom metadata = readMetadata(metadataFile);
-
- if (metadata != null) {
- Xpp3Dom versioning = metadata.getChild("versioning");
- if (versioning != null) {
- Xpp3Dom versions = versioning.getChild("versions");
- if (versions != null) {
-
- Xpp3Dom[] children = versions.getChildren("version");
- for (Xpp3Dom aChildren : children) {
- allVersions.add(aChildren.getValue());
- }
- }
- }
- }
-
- allVersions.add(artifact.getBaseVersion());
-
- metadata = new Xpp3Dom("metadata");
- addChild(metadata, "groupId", artifact.getGroupId());
- addChild(metadata, "artifactId", artifact.getArtifactId());
- Xpp3Dom versioning = new Xpp3Dom("versioning");
- versioning.addChild(addChildren(new Xpp3Dom("versions"), "version", allVersions));
- addChild(versioning, "lastUpdated", timestamp);
- metadata.addChild(versioning);
-
- metadata = Xpp3DomUtils.mergeXpp3Dom(metadata, readMetadata(metadataFile));
-
- writeMetadata(metadataFile, metadata);
- }
-
- private static Xpp3Dom addChild(Xpp3Dom parent, String childName, String childValue) {
- Xpp3Dom child = new Xpp3Dom(childName);
- child.setValue(childValue);
- parent.addChild(child);
- return parent;
- }
-
- private static Xpp3Dom addChildren(Xpp3Dom parent, String childName, Collection childValues) {
- for (String childValue : childValues) {
- addChild(parent, childName, childValue);
- }
- return parent;
- }
-
- private static Xpp3Dom readMetadata(File metadataFile) throws IOException {
- if (!metadataFile.isFile()) {
- return null;
- }
-
- try (Reader reader = ReaderFactory.newXmlReader(metadataFile)) {
- return Xpp3DomBuilder.build(reader);
- } catch (XmlPullParserException e) {
- throw new IOException(e.getMessage(), e);
- }
- }
-
- private static void writeMetadata(File metadataFile, Xpp3Dom metadata) throws IOException {
- metadataFile.getParentFile().mkdirs();
-
- try (Writer writer = WriterFactory.newXmlWriter(metadataFile)) {
- Xpp3DomWriter.write(writer, metadata);
- }
- }
-}
diff --git a/src/main/java/org/apache/maven/plugins/invoker/PomUtils.java b/src/main/java/org/apache/maven/plugins/invoker/PomUtils.java
index 17965c96..526ed7dd 100644
--- a/src/main/java/org/apache/maven/plugins/invoker/PomUtils.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/PomUtils.java
@@ -25,7 +25,7 @@
import org.apache.maven.model.Model;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.apache.maven.plugin.MojoExecutionException;
-import org.codehaus.plexus.util.ReaderFactory;
+import org.codehaus.plexus.util.xml.XmlStreamReader;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
/**
@@ -43,7 +43,7 @@ class PomUtils {
* @throws MojoExecutionException If the POM file could not be loaded.
*/
public static Model loadPom(File pomFile) throws MojoExecutionException {
- try (Reader reader = ReaderFactory.newXmlReader(pomFile)) {
+ try (Reader reader = new XmlStreamReader(pomFile)) {
return new MavenXpp3Reader().read(reader, false);
} catch (XmlPullParserException e) {
throw new MojoExecutionException("Failed to parse POM: " + pomFile, e);
diff --git a/src/main/java/org/apache/maven/plugins/invoker/SelectorUtils.java b/src/main/java/org/apache/maven/plugins/invoker/SelectorUtils.java
index fc062603..ded4fad3 100644
--- a/src/main/java/org/apache/maven/plugins/invoker/SelectorUtils.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/SelectorUtils.java
@@ -29,6 +29,7 @@
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
+import java.util.Objects;
import java.util.Properties;
import java.util.stream.Collectors;
@@ -37,7 +38,6 @@
import org.apache.maven.toolchain.MisconfiguredToolchainException;
import org.apache.maven.toolchain.ToolchainPrivate;
import org.codehaus.plexus.util.Os;
-import org.codehaus.plexus.util.StringUtils;
/**
* Provides utility methods for selecting build jobs based on environmental conditions.
@@ -47,7 +47,11 @@
class SelectorUtils {
static void parseList(String list, Collection includes, Collection excludes) {
- String[] tokens = (list != null) ? StringUtils.split(list, ",") : new String[0];
+ if (Objects.isNull(list)) {
+ return;
+ }
+
+ String[] tokens = list.split(",+");
for (String token1 : tokens) {
String token = token1.trim();
@@ -69,17 +73,10 @@ static boolean isOsFamily(String osSpec) {
}
static boolean isOsFamily(List families, boolean defaultMatch) {
- if (families != null && !families.isEmpty()) {
- for (String family : families) {
- if (Os.isFamily(family)) {
- return true;
- }
- }
-
- return false;
- } else {
+ if (families == null || families.isEmpty()) {
return defaultMatch;
}
+ return families.stream().anyMatch(Os::isFamily);
}
/**
@@ -99,7 +96,8 @@ static String getMavenVersion() {
.getClassLoader()
.getResourceAsStream("META-INF/maven/org.apache.maven/maven-core/pom.properties"));
// CHECKSTYLE_ON: LineLength
- return StringUtils.trim(properties.getProperty("version"));
+ String str = properties.getProperty("version");
+ return str == null ? null : str.trim();
} catch (Exception e) {
return null;
}
@@ -121,7 +119,8 @@ static String getMavenVersion(File mavenHome) throws IOException {
try (InputStream in = url.openStream()) {
Properties properties = new Properties();
properties.load(in);
- String version = StringUtils.trim(properties.getProperty("version"));
+ String str = properties.getProperty("version");
+ String version = str == null ? null : str.trim();
if (version != null) {
return version;
}
@@ -133,10 +132,6 @@ static String getMavenVersion(File mavenHome) throws IOException {
return null;
}
- static boolean isMavenVersion(String mavenSpec) {
- return isMavenVersion(mavenSpec, getMavenVersion());
- }
-
static boolean isMavenVersion(String mavenSpec, String actualVersion) {
List includes = new ArrayList<>();
List excludes = new ArrayList<>();
@@ -151,15 +146,6 @@ static String getJreVersion() {
return System.getProperty("java.version", "");
}
- static String getJreVersion(File javaHome) {
- // @todo detect actual version
- return null;
- }
-
- static boolean isJreVersion(String jreSpec) {
- return isJreVersion(jreSpec, getJreVersion());
- }
-
static boolean isJreVersion(String jreSpec, String actualJreVersion) {
List includes = new ArrayList<>();
List excludes = new ArrayList<>();
@@ -170,44 +156,39 @@ static boolean isJreVersion(String jreSpec, String actualJreVersion) {
return isJreVersion(jreVersion, includes, true) && !isJreVersion(jreVersion, excludes, false);
}
- static boolean isJreVersion(List jreVersion, List versionPatterns, boolean defaultMatch) {
- if (versionPatterns != null && !versionPatterns.isEmpty()) {
- for (String versionPattern : versionPatterns) {
- if (isJreVersion(jreVersion, versionPattern)) {
- return true;
- }
- }
-
- return false;
- } else {
+ static boolean isJreVersion(List jreVersions, List versionPatterns, boolean defaultMatch) {
+ if (versionPatterns == null || versionPatterns.isEmpty()) {
return defaultMatch;
}
+
+ return versionPatterns.stream().anyMatch(versionPattern -> isJreVersion(jreVersions, versionPattern));
}
- static boolean isJreVersion(List jreVersion, String versionPattern) {
+ static boolean isJreVersion(List jreVersions, String versionPattern) {
List checkVersion = parseVersion(versionPattern);
if (versionPattern.endsWith("+")) {
// 1.5+ <=> [1.5,)
- return compareVersions(jreVersion, checkVersion) >= 0;
+ return compareVersions(jreVersions, checkVersion) >= 0;
} else if (versionPattern.endsWith("-")) {
// 1.5- <=> (,1.5)
- return compareVersions(jreVersion, checkVersion) < 0;
+ return compareVersions(jreVersions, checkVersion) < 0;
} else {
// 1.5 <=> [1.5,1.6)
- return checkVersion.size() <= jreVersion.size()
- && checkVersion.equals(jreVersion.subList(0, checkVersion.size()));
+ return checkVersion.size() <= jreVersions.size()
+ && checkVersion.equals(jreVersions.subList(0, checkVersion.size()));
}
}
static List parseVersion(String version) {
- version = version.replaceAll("[^0-9]", ".");
-
- String[] tokens = StringUtils.split(version, ".");
+ version = version.replaceAll("\\D", ".");
- List numbers = Arrays.stream(tokens).map(Integer::valueOf).collect(Collectors.toList());
+ String[] tokens = version.split("\\s*\\.+\\s*");
- return numbers;
+ return Arrays.stream(tokens)
+ .filter(s -> !s.isEmpty())
+ .map(Integer::valueOf)
+ .collect(Collectors.toList());
}
static int compareVersions(List version1, List version2) {
diff --git a/src/main/java/org/apache/maven/plugins/invoker/VerifyMojo.java b/src/main/java/org/apache/maven/plugins/invoker/VerifyMojo.java
index 9bd6d823..b3a21cb0 100644
--- a/src/main/java/org/apache/maven/plugins/invoker/VerifyMojo.java
+++ b/src/main/java/org/apache/maven/plugins/invoker/VerifyMojo.java
@@ -29,7 +29,7 @@
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.invoker.model.io.xpp3.BuildJobXpp3Reader;
-import org.codehaus.plexus.util.ReaderFactory;
+import org.codehaus.plexus.util.xml.XmlStreamReader;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
/**
@@ -117,7 +117,7 @@ public void execute() throws MojoExecutionException, MojoFailureException {
InvokerSession invokerSession = new InvokerSession();
for (File reportFile : reportFiles) {
- try (Reader xmlReader = ReaderFactory.newXmlReader(reportFile)) {
+ try (Reader xmlReader = new XmlStreamReader(reportFile)) {
invokerSession.addJob(reader.read(xmlReader));
} catch (XmlPullParserException e) {
throw new MojoExecutionException("Failed to parse report file: " + reportFile, e);
diff --git a/src/main/mdo/invocation.mdo b/src/main/mdo/invocation.mdo
index 6529e7c6..f4af4252 100644
--- a/src/main/mdo/invocation.mdo
+++ b/src/main/mdo/invocation.mdo
@@ -86,7 +86,7 @@ under the License.
time
1.0.0
true
- double
+ float
The number of seconds that this build job took to complete.
@@ -126,7 +126,7 @@ under the License.
/**
* Creates a new build job with the specified project path.
- *
+ *
* @param project The path to the project.
*/
public BuildJob( String project )
diff --git a/src/main/resources/invoker-report.properties b/src/main/resources/invoker-report.properties
index 5fe569d2..9753d833 100644
--- a/src/main/resources/invoker-report.properties
+++ b/src/main/resources/invoker-report.properties
@@ -15,22 +15,25 @@
# specific language governing permissions and limitations
# under the License.
-report.invoker.result.description = The results of the Maven invocations.
-report.invoker.result.name = Invoker Build Results
-report.invoker.result.title = Invoker Report
-report.invoker.summary.title = Summary
-report.invoker.summary.number = Builds
-report.invoker.summary.success = Success
-report.invoker.summary.failed = Failures
-report.invoker.summary.skipped = Skipped
-report.invoker.summary.success.rate = Success Rate
-report.invoker.summary.time.total = Total Time
-report.invoker.summary.time.avg = Avg Time
-report.invoker.detail.title = Build Details
-report.invoker.detail.name = Name
-report.invoker.detail.result = Result
-report.invoker.detail.time = Time
-report.invoker.detail.message = Message
-report.invoker.format.percent = 0.0%
-report.invoker.format.seconds = 0.0\u00A0s
-report.invoker.format.name_with_description = {0}: {1}
+report.invoker.name=Invoker
+report.invoker.description=Report on the build results of the Maven invocations.
+report.invoker.title=Invoker Report
+report.invoker.summary.title=Summary
+report.invoker.summary.builds=Builds
+report.invoker.summary.success=Success
+report.invoker.summary.failures=Failures
+report.invoker.summary.skipped=Skipped
+report.invoker.summary.successrate=Success Rate
+report.invoker.summary.time=Time
+report.invoker.detail.title=Build Details
+report.invoker.detail.name=Name
+report.invoker.detail.result=Result
+report.invoker.detail.time=Time
+report.invoker.detail.message=Message
+report.invoker.value.successrate={0,choice,0#0%|0.0<{0,number,0.0%}|1#{0,number,0%}}
+# Rationale: The idea is to always display four digits for visually consistent output
+# Important:
+# * Keep in sync with org.apache.maven.plugins.invoker.AbstractInvokerMojo
+# * Needs to be copied into other bundles only if non-Latin script is used
+report.invoker.value.time={0,choice,0#0|0.0<{0,number,0.000}|10#{0,number,0.00}|100#{0,number,0.0}|1000#{0,number,0}} s
+report.invoker.text.name_with_description={0}: {1}
diff --git a/src/main/resources/invoker-report_de.properties b/src/main/resources/invoker-report_de.properties
index d1016e30..ed617c34 100644
--- a/src/main/resources/invoker-report_de.properties
+++ b/src/main/resources/invoker-report_de.properties
@@ -15,21 +15,18 @@
# specific language governing permissions and limitations
# under the License.
-report.invoker.result.description = Die Ergebnisse der Maven-Ausf\u00FChrungen.
-report.invoker.result.name = Invoker-Build-Ergebnisse
-report.invoker.result.title = Invoker-Bericht
-report.invoker.summary.title = Zusammenfassungen
-report.invoker.summary.number = Builds
-report.invoker.summary.success = Erfolge
-report.invoker.summary.failed = Fehlschl\u00E4ge
-report.invoker.summary.skipped = Ausgelassen
-report.invoker.summary.success.rate = Erfolgsrate
-report.invoker.summary.time.total = Gesamtzeit
-report.invoker.summary.time.avg = Durchschnittszeit
-report.invoker.detail.title = Build-Details
-report.invoker.detail.name = Name
-report.invoker.detail.result = Ergebnis
-report.invoker.detail.time = Zeit
-report.invoker.detail.message = Meldung
-report.invoker.format.percent = 0.0\u00A0%
-report.invoker.format.seconds = 0.0\u00A0s
+report.invoker.description=Bericht \u00FCber die Build-Ergebnisse der Maven-Ausf\u00FChrungen.
+report.invoker.title=Invoker-Bericht
+report.invoker.summary.title=Zusammenfassung
+report.invoker.summary.builds=Builds
+report.invoker.summary.success=Erfolge
+report.invoker.summary.failures=Fehlschl\u00E4ge
+report.invoker.summary.skipped=Ausgelassen
+report.invoker.summary.successrate=Erfolgsrate
+report.invoker.summary.time=Zeit
+report.invoker.detail.title=Build-Details
+report.invoker.detail.name=Name
+report.invoker.detail.result=Ergebnis
+report.invoker.detail.time=Zeit
+report.invoker.detail.message=Meldung
+report.invoker.value.successrate={0,choice,0#0 %|0.0<{0,number,0.0 %}|1#{0,number,0 %}}
diff --git a/src/main/resources/invoker-report_fr.properties b/src/main/resources/invoker-report_fr.properties
index 1d3393ab..75b52756 100644
--- a/src/main/resources/invoker-report_fr.properties
+++ b/src/main/resources/invoker-report_fr.properties
@@ -15,22 +15,19 @@
# specific language governing permissions and limitations
# under the License.
-report.invoker.result.description = Résultat des invocations de Maven
-report.invoker.result.name = Invoker Résultat de builds
-report.invoker.result.title = Invoker Rapport
-report.invoker.summary.title = Sommaire
-report.invoker.summary.number = Builds
-report.invoker.summary.success = Réussis
-report.invoker.summary.failed = Echecs
-report.invoker.summary.skipped = Ignorés
-report.invoker.summary.success.rate = Taux de réussite
-report.invoker.summary.time.total = Durée totale
-report.invoker.summary.time.avg = Durée moyenne
-report.invoker.detail.title = Détails de Build
-report.invoker.detail.name = Nom
-report.invoker.detail.result = Résultat
-report.invoker.detail.time = Durée
-report.invoker.detail.message = Message
-report.invoker.format.percent = 0.0%
-report.invoker.format.seconds = 0.0\u00A0s
-report.invoker.format.name_with_description = {0} : {1}
+report.invoker.description=Résultat des invocations de Maven
+report.invoker.title=Invoker Rapport
+report.invoker.summary.title=Sommaire
+report.invoker.summary.builds=Builds
+report.invoker.summary.success=Réussis
+report.invoker.summary.failures=Echecs
+report.invoker.summary.skipped=Ignorés
+report.invoker.summary.successrate=Taux de réussite
+report.invoker.summary.time=Durée
+report.invoker.detail.title=Détails de Build
+report.invoker.detail.name=Nom
+report.invoker.detail.result=Résultat
+report.invoker.detail.time=Durée
+report.invoker.detail.message=Message
+report.invoker.value.successrate={0,choice,0#0 %|0.0<{0,number,0.0 %}|1#{0,number,0 %}}
+report.invoker.text.name_with_description={0} : {1}
diff --git a/src/site/apt/examples/post-build-script.apt.vm b/src/site/apt/examples/post-build-script.apt.vm
deleted file mode 100644
index 93c15a8c..00000000
--- a/src/site/apt/examples/post-build-script.apt.vm
+++ /dev/null
@@ -1,97 +0,0 @@
- ------
- Using a Post-Build Script
- ------
- Paul Gier
- ------
- 2008-08-02
- ------
-
- ~~ 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.
-
- ~~ NOTE: For help with the syntax of this file, see:
- ~~ http://maven.apache.org/doxia/references/apt-format.html
-
-Using a Post-Build Script
-
- Here is an example of how the Invoker Plugin can be used to run a set of Maven projects and then verify their output
- with a {{{http://www.beanshell.org/}BeanShell}} or {{{http://groovy-lang.org/}Groovy}} script. The name of the
- script file in this case is <<>>.
-
-+------------------
-
-
-
-
- maven-invoker-plugin
- ${project.version}
-
- true
- src/it
- setup.bsh
- verify.bsh
-
-
-
- integration-test
-
- run
-
-
-
-
-
-
-
-+------------------
-
- Below is an example post-build BeanShell script (<<>>) that checks for the existence of a JAR file after
- the build has run. If the JAR file does not exist, the script throws an exception which causes the Invoker Plugin to
- log that the build failed. More precisely, any non-null return value which does not equal <<>> will be interpreted
- as a failure condition. And of course, if the script exits abnormally due to an exception, the plugin will flag the
- corresponding build as a failure, too.
-
-+------------------
-import java.io.*;
-
-File file = new File( basedir, "target/my-test-project-1.0-SNAPSHOT.jar" );
-if ( !file.isFile() )
-{
- throw new FileNotFoundException( "Could not find generated JAR: " + file );
-}
-+------------------
-
- Complementary to the post-build hook script, you can also create a pre-build hook script that will be run before
- the invocation of Maven. This can be used to do some preparations for the build.
-
- To allow the scripts to access some useful data about the test project, the following global variables will be
- defined by the Invoker Plugin before running the script:
-
-*--------------------------+----------------------+-----------------------------------------------------------+--------+
-|| Name || Type || Description || Since |
-*--------------------------+----------------------+-----------------------------------------------------------+--------+
-| <<>> | <<>> | The absolute path to the base directory of the test project. | 1.0 |
-*--------------------------+----------------------+-----------------------------------------------------------+--------+
-| <<>>| <<>> | The absolute path to the local repository used for the Maven invocation on the test project. | 1.3 |
-*--------------------------+----------------------+-----------------------------------------------------------+--------+
-| <<>> | <<>> | The storage of key-value pairs used to pass data from the pre-build hook script to the post-build hook script. | 1.4 |
-*--------------------------+----------------------+-----------------------------------------------------------+--------+
-| <<>> | <<>> | The version of Maven executing on the test project. | 1.9 |
-*--------------------------+----------------------+-----------------------------------------------------------+--------+
-
- Additional variables that can be accessed in the hook scripts can be defined through the
- <<<{{{../run-mojo.html#scriptVariables}scriptVariables}}>>> parameter in the Invoker Plugin's configuration.
\ No newline at end of file
diff --git a/src/site/apt/examples/pre-post-build-script.apt.vm b/src/site/apt/examples/pre-post-build-script.apt.vm
new file mode 100644
index 00000000..8a8e0948
--- /dev/null
+++ b/src/site/apt/examples/pre-post-build-script.apt.vm
@@ -0,0 +1,151 @@
+ ------
+ Using Pre and Post Build Script
+ ------
+ Paul Gier
+ ------
+ 2008-08-02
+ ------
+
+ ~~ 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.
+
+ ~~ NOTE: For help with the syntax of this file, see:
+ ~~ http://maven.apache.org/doxia/references/apt-format.html
+
+Using a Pre-Build Script
+
+ Complementary to the post-build hook script, you can also create a pre-build hook script that will be run before
+ the invocation of Maven. This can be used to do some preparations for the build.
+
+ Default name of Pre-Build script is <<>>, you can use name <<>> or <<>>
+ according to chosen script language.
+
+ In Pre-Build scripts you can prepare a test resources for your project.
+
+ You can also define a user properties which will be added to executed test project by <<<-D>>> Maven argument.
+
+ Here is an example of groovy script:
+
++------------------
+def userProperties = context.get('userProperties')
+
+def server = new MockServer()
+userProperties.put('serverHost', server.getHost())
+userProperties.put('serverPort', server.getPort())
++------------------
+
+ Now you can use it in test project:
+
++------------------
+
+
+
+
+ org.example
+ my-maven-plugin
+ @project.version@
+
+ ${serverHost}:${serverPort}
+
+
+ ....
+
+
+
+
+
++------------------
+
+Using a Post-Build Script
+
+ Here is an example of how the Invoker Plugin can be used to run a set of Maven projects and then verify their output
+ with a {{{https://beanshell.github.io/}BeanShell}} or {{{https://groovy-lang.org/}Groovy}} script. The name of the
+ script file in this case is <<>> - default value is <<>>.
+
++------------------
+
+
+
+
+ maven-invoker-plugin
+ ${project.version}
+
+ true
+ src/it
+ setup
+ verify
+
+
+
+ integration-test
+
+ run
+
+
+
+
+
+
+
++------------------
+
+ Below is an example post-build BeanShell script (<<>>) that checks for the existence of a JAR file after
+ the build has run. If the JAR file does not exist, the script throws an exception which causes the Invoker Plugin to
+ log that the build failed. More precisely, any non-null return value which does not equal <<>> will be interpreted
+ as a failure condition. And of course, if the script exits abnormally due to an exception, the plugin will flag the
+ corresponding build as a failure, too.
+
+ Example <<>>
+
++------------------
+import java.io.*;
+
+File file = new File( basedir, "target/my-test-project-1.0-SNAPSHOT.jar" );
+if ( !file.isFile() )
+{
+ throw new FileNotFoundException( "Could not find generated JAR: " + file );
+}
++------------------
+
+ and similar <<>>
+
++------------------
+def file = new File( basedir, "target/my-test-project-1.0-SNAPSHOT.jar" )
+assert file.isFile()
++------------------
+
+Predefined global variables
+
+ To allow the scripts to access some useful data about the test project, the following global variables will be
+ defined by the Invoker Plugin before running the script:
+
+*-------------------------------------+----------------------------+-----------------------------------------------------------+--------+
+|| Name || Type || Description || Since |
+*-------------------------------------+----------------------------+-----------------------------------------------------------+--------+
+| <<>> | <<>> | The absolute path to the base directory of the test project. | 1.0 |
+*-------------------------------------+----------------------------+-----------------------------------------------------------+--------+
+| <<>> | <<>> | The absolute path to the local repository used for the Maven invocation on the test project. | 1.3 |
+*-------------------------------------+----------------------------+-----------------------------------------------------------+--------+
+| <<>> | <<>> | The storage of key-value pairs used to pass data from the pre-build hook script to the post-build hook script. | 1.4 |
+*-------------------------------------+----------------------------+-----------------------------------------------------------+--------+
+| <<>> | <<>> | The user properties for executing project | 3.7.0 |
+*-------------------------------------+----------------------------+-----------------------------------------------------------+--------+
+| <<>> | <<>> | The version of Maven executing on the test project. | 1.9 |
+*-------------------------------------+----------------------------+-----------------------------------------------------------+--------+
+
+ Additional variables that can be accessed in the hook scripts can be defined through the
+ <<<{{{../run-mojo.html#scriptVariables}scriptVariables}}>>> parameter in the Invoker Plugin's configuration.
diff --git a/src/site/apt/examples/selector-scripts.apt.vm b/src/site/apt/examples/selector-scripts.apt.vm
index 43072dfe..806a2223 100644
--- a/src/site/apt/examples/selector-scripts.apt.vm
+++ b/src/site/apt/examples/selector-scripts.apt.vm
@@ -85,4 +85,7 @@ Selector Scripts
If the script returns any value other than <<>>, then the project will not be executed.
If the script throws an exception, then the project will be marked as being in ERROR.
-
+
+Predefined global variables
+
+ In Selector Scripts the same global variables are defined as in {{{./pre-post-build-script.html#predefined-global-variables}Pre and Post Build Script}}
diff --git a/src/site/apt/groovy-version.apt.vm b/src/site/apt/groovy-version.apt.vm
index bc1d17f9..959886c6 100644
--- a/src/site/apt/groovy-version.apt.vm
+++ b/src/site/apt/groovy-version.apt.vm
@@ -33,11 +33,11 @@ Groovy version and extensions
Plugin <<>> in version <<<3.4.0>>> has only dependency on <<>> core add common extensions:
- * <<>>
+ * <<>>
- * <<>>
+ * <<>>
- * <<>>
+ * <<>>
[]
@@ -56,7 +56,7 @@ Groovy version and extensions
org.apache.groovy
groovy-yaml
- 3.0.10
+ ${groovyVersion}