Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .asf.yaml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
#
#
# 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.
Expand All @@ -16,7 +16,7 @@
#
# see https://s.apache.org/asfyaml
github:
description: "Apache Maven Verifier"
description: "Apache Maven Verifier (deprecated)"
homepage: https://maven.apache.org/shared/maven-verifier/
labels:
- java
Expand Down
247 changes: 142 additions & 105 deletions MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@

## ⚠️ Deprecation Notice

**Apache Maven Verifier is deprecated and will be replaced by [maven-executor](https://github.com/apache/maven/tree/master/impl/maven-executor).**
**Apache Maven Verifier is deprecated. [maven-executor](https://github.com/apache/maven-executor) was released and has its own repository.**

New projects should use maven-executor. Existing projects should plan migration to maven-executor.
New projects should use maven-executor. Existing projects should plan migration to maven-executor. This project will be retired soon.

See [Issue #186](https://github.com/apache/maven-verifier/issues/186) for more details.

Expand Down Expand Up @@ -65,14 +65,14 @@ Both have issues:
**Add:**
```xml
<dependency>
<groupId>org.apache.maven</groupId>
<groupId>org.apache.maven.executor</groupId>
<artifactId>maven-executor</artifactId>
<version>4.0.0-rc-5</version> <!-- Use latest version -->
<version>x.y.z</version> <!-- Use the latest released version from https://github.com/apache/maven-executor -->
<scope>test</scope>
</dependency>
```

> **Note**: maven-executor location may change as it might be moved out of Maven 4 core to become a standalone project. Check the latest documentation.
> **Note**: The externalized standalone maven-executor groupId is `org.apache.maven.executor` — different from the former Maven 4 core artifact `org.apache.maven:maven-executor`. Always check https://github.com/apache/maven-executor for the latest released version and coordinates.

### 2. Code Migration Examples

Expand All @@ -87,76 +87,88 @@ public class MyTest {
public void testBuild() throws Exception {
String baseDir = "/path/to/project";
Verifier verifier = new Verifier(baseDir);

// Configure
verifier.setAutoclean(false);
verifier.setMavenDebug(true);
verifier.addCliArgument("-DskipTests=true");

// Execute
verifier.addCliArgument("package");
verifier.execute();

// Verify
verifier.verifyErrorFreeLog();
verifier.verifyFilePresent("target/my-app-1.0.jar");
verifier.resetStreams();
}
}
```

#### After (maven-executor):

```java
import org.apache.maven.api.cli.Executor;
import org.apache.maven.api.cli.ExecutorRequest;
import org.apache.maven.cling.executor.forked.ForkedExecutor;
import org.apache.maven.cling.executor.embedded.EmbeddedExecutor;
import org.apache.maven.executor.ExecutorHelper;
import org.apache.maven.executor.ExecutorRequest;
import org.apache.maven.executor.ExecutorResult;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;

public class MyTest {
@Test
public void testBuild() throws Exception {
Path mavenHome = Paths.get(System.getProperty("maven.home"));
Path baseDir = Paths.get("/path/to/project");

// Choose executor type: Forked or Embedded
Executor executor = new ForkedExecutor();
// OR: Executor executor = new EmbeddedExecutor();

// Build request with CLI arguments
ExecutorRequest request = ExecutorRequest.builder()
.cwd(baseDir)
.arguments(Arrays.asList("package", "-DskipTests=true", "-X"))
.build();

// Execute
int exitCode = executor.execute(request);

// Verify
assertEquals(0, exitCode, "Build should succeed");
assertTrue(Files.exists(baseDir.resolve("target/my-app-1.0.jar")),
"JAR file should exist");

// ExecutorHelper selects embedded or forked automatically (Mode.AUTO),
// or use Mode.FORKED / Mode.EMBEDDED explicitly.
// It implements AutoCloseable — use try-with-resources.
try (ExecutorHelper executor = ExecutorHelper.forMavenInstallation(mavenHome, ExecutorHelper.Mode.AUTO)) {
ExecutorRequest request = ExecutorRequest.mavenBuilder()
.cwd(baseDir)
.arguments("package", "-DskipTests=true", "-X")
.build();

ExecutorResult result = executor.execute(request);

// Verify
assertTrue(result.success(), "Build should succeed");
assertTrue(Files.exists(baseDir.resolve("target/my-app-1.0.jar")),
"JAR file should exist");
}
}
}
```

If you need to choose the executor type explicitly:

```java
import org.apache.maven.executor.forked.ForkedMavenExecutor;
import org.apache.maven.executor.embedded.EmbeddedMavenExecutor;

// Forked: spawns a separate Maven process
try (ForkedMavenExecutor executor = new ForkedMavenExecutor(mavenHome)) { ... }

// Embedded: runs Maven inside the same JVM
try (EmbeddedMavenExecutor executor = new EmbeddedMavenExecutor(mavenHome)) { ... }
```

### 3. Key API Mapping

| maven-verifier Concept | maven-executor Equivalent |
|------------------------|---------------------------|
| `new Verifier(baseDir)` | `ExecutorRequest.builder().cwd(baseDir).build()` |
| `verifier.addCliArgument(arg)` | Add to `arguments` list in ExecutorRequest |
| `new Verifier(baseDir)` | `ExecutorRequest.mavenBuilder().cwd(baseDir).build()` |
| `verifier.addCliArgument(arg)` | `.argument(arg)` or `.arguments(arg1, arg2, ...)` on the builder |
| `verifier.setMavenDebug(true)` | Add `-X` to arguments |
| `verifier.setAutoclean(false)` | Manage manually or via arguments |
| `verifier.setForkJvm(true)` | Use `ForkedExecutor` |
| `verifier.setForkJvm(false)` | Use `EmbeddedExecutor` |
| `verifier.execute()` | `executor.execute(request)` |
| `verifier.verifyErrorFreeLog()` | Check `exitCode == 0` |
| `verifier.verifyFilePresent(path)` | Use `Files.exists(Paths.get(...))` |
| `verifier.verifyTextInLog(text)` | Capture and parse executor output |
| `verifier.setAutoclean(false)` | Manage clean goal manually in the arguments list |
| `verifier.setForkJvm(true)` | `new ForkedMavenExecutor(mavenHome)` or `Mode.FORKED` |
| `verifier.setForkJvm(false)` | `new EmbeddedMavenExecutor(mavenHome)` or `Mode.EMBEDDED` |
| `verifier.execute()` | `executor.execute(request)` → returns `ExecutorResult` |
| `verifier.verifyErrorFreeLog()` | `result.success()` returns `true` when exit code is 0 |
| `result exit code` | `result.exitCode()` returns `Optional<Integer>` |
| `verifier.verifyFilePresent(path)` | `Files.exists(baseDir.resolve(path))` |
| `verifier.verifyTextInLog(text)` | `result.stdOutString().orElse("").contains(text)` (requires `.grabOutputAsString(true)`) |

### 4. Environment Variables

Expand All @@ -168,40 +180,44 @@ verifier.setEnvironmentVariable("MAVEN_OPTS", "-Xmx1024m");

**After:**
```java
Map<String, String> env = new HashMap<>();
env.put("JAVA_HOME", "/path/to/java");
env.put("MAVEN_OPTS", "-Xmx1024m");

ExecutorRequest request = ExecutorRequest.builder()
.cwd(baseDir)
.arguments(args)
.environmentVariables(env)
.build();
ExecutorRequest request = ExecutorRequest.mavenBuilder()
.cwd(baseDir)
.arguments("package")
.environmentVariable("JAVA_HOME", "/path/to/java")
.environmentVariable("MAVEN_OPTS", "-Xmx1024m")
.build();
```

### 5. Verification Helpers

maven-verifier included many helper methods like `verifyFilePresent()`, `verifyTextInLog()`, etc. These are not part of maven-executor's core responsibility. Instead:
maven-verifier included many helper methods like `verifyFilePresent()`, `verifyTextInLog()`, etc.
These are not part of maven-executor's core responsibility.

**Extract verification to separate utilities:**
**Capturing output and verifying log content:**
```java
public class MavenTestUtils {
public static void assertFileExists(Path base, String relativePath) {
Path file = base.resolve(relativePath);
assertTrue(Files.exists(file),
"Expected file does not exist: " + file);
}

public static void assertLogContains(String log, String expectedText) {
assertTrue(log.contains(expectedText),
"Log does not contain expected text: " + expectedText);
}

public static void assertErrorFreeLog(String log) {
assertFalse(log.contains("[ERROR]"),
"Log contains errors");
}
}
ExecutorRequest request = ExecutorRequest.mavenBuilder()
.cwd(baseDir)
.arguments("package")
.grabOutputAsString(true) // captures stdout as a String in ExecutorResult
.build();

ExecutorResult result = executor.execute(request);

// Check build success
assertTrue(result.success(), "Build should succeed");

// Check log content
String output = result.stdOutString().orElse("");
assertTrue(output.contains("BUILD SUCCESS"), "Expected BUILD SUCCESS in output");
assertFalse(output.contains("[ERROR]"), "Expected no errors in output");
```

**File existence checks:**
```java
assertTrue(Files.exists(baseDir.resolve("target/my-app-1.0.jar")),
"Expected JAR was not built");
assertFalse(Files.exists(baseDir.resolve("target/should-not-exist.txt")),
"Unexpected file was created");
```

### 6. Settings and Local Repository
Expand All @@ -214,14 +230,14 @@ verifier.setUserSettingsFile("/path/to/settings.xml");

**After:**
```java
ExecutorRequest request = ExecutorRequest.builder()
.cwd(baseDir)
.arguments(Arrays.asList(
"package",
"-Dmaven.repo.local=/custom/repo",
"-s", "/path/to/settings.xml"
))
.build();
ExecutorRequest request = ExecutorRequest.mavenBuilder()
.cwd(baseDir)
.arguments(
"package",
"-Dmaven.repo.local=/custom/repo",
"-s", "/path/to/settings.xml"
)
.build();
```

## Migration Checklist
Expand All @@ -230,7 +246,7 @@ ExecutorRequest request = ExecutorRequest.builder()
- [ ] Update POM dependencies to use maven-executor
- [ ] Replace Verifier instantiation with ExecutorRequest builder pattern
- [ ] Convert `addCliArgument()` calls to arguments list
- [ ] Choose between ForkedExecutor and EmbeddedExecutor
- [ ] Choose between `ForkedMavenExecutor`, `EmbeddedMavenExecutor`, or `ExecutorHelper` (with `Mode.AUTO/FORKED/EMBEDDED`)
- [ ] Replace verification methods with standard Java file checks or custom utilities
- [ ] Update environment variable configuration
- [ ] Update local repository and settings configuration
Expand All @@ -248,56 +264,77 @@ For large codebases, consider a gradual approach:

## Example Adapter Pattern

For gradual migration, you can create an adapter:
For gradual migration, you can create an adapter that wraps maven-executor with a Verifier-like interface:

```java
public class MavenExecutorAdapter {
import org.apache.maven.executor.ExecutorException;
import org.apache.maven.executor.ExecutorHelper;
import org.apache.maven.executor.ExecutorRequest;
import org.apache.maven.executor.ExecutorResult;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MavenExecutorAdapter implements AutoCloseable {
private final Path baseDir;
private final List<String> arguments = new ArrayList<>();
private final Map<String, String> env = new HashMap<>();
private Executor executor = new ForkedExecutor();
public MavenExecutorAdapter(String baseDir) {
private final ExecutorHelper executor;

public MavenExecutorAdapter(Path mavenHome, String baseDir) {
this.baseDir = Paths.get(baseDir);
// Mode.AUTO selects embedded when possible, falls back to forked
this.executor = ExecutorHelper.forMavenInstallation(mavenHome, ExecutorHelper.Mode.AUTO);
}


public MavenExecutorAdapter(Path mavenHome, String baseDir, ExecutorHelper.Mode mode) {
this.baseDir = Paths.get(baseDir);
this.executor = ExecutorHelper.forMavenInstallation(mavenHome, mode);
}

public void addCliArgument(String arg) {
arguments.add(arg);
}

public void setEnvironmentVariable(String key, String value) {
env.put(key, value);
}

public void setForkJvm(boolean fork) {
executor = fork ? new ForkedExecutor() : new EmbeddedExecutor();
}

public void execute() throws Exception {
ExecutorRequest request = ExecutorRequest.builder()
.cwd(baseDir)
.arguments(arguments)
.environmentVariables(env)
.build();

int exitCode = executor.execute(request);
if (exitCode != 0) {
throw new Exception("Maven execution failed with exit code: " + exitCode);

/** Executes Maven; throws ExecutorException if the build fails. */
public ExecutorResult execute() throws ExecutorException {
ExecutorRequest request = ExecutorRequest.mavenBuilder()
.cwd(baseDir)
.arguments(arguments)
.environmentVariables(env)
.build();

ExecutorResult result = executor.execute(request);
if (!result.success()) {
throw new ExecutorException(
"Maven execution failed with exit code: " + result.exitCode().orElse(-1));
}
return result;
}

@Override
public void close() throws ExecutorException {
executor.close();
}

// Add other adapter methods as needed
}
```

## Resources

- [maven-executor source](https://github.com/apache/maven/tree/master/impl/maven-executor)
- [Maven 4 IT Verifier implementation](https://github.com/apache/maven/blob/master/its/core-it-support/maven-it-helper/src/main/java/org/apache/maven/it/Verifier.java)
- [maven-executor project](https://github.com/apache/maven-executor)
- [maven-executor releases](https://github.com/apache/maven-executor/releases)
- [Issue #186 discussion](https://github.com/apache/maven-verifier/issues/186)

## Support & Questions

For migration questions or issues:
- Post to [Maven Dev Mailing List](https://maven.apache.org/mailing-lists.html)
- Open issues on [maven-executor GitHub](https://github.com/apache/maven/issues)
- Open issues on [maven-executor GitHub](https://github.com/apache/maven-executor/issues)
Loading
Loading