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
7 changes: 7 additions & 0 deletions cli/flamingock-cli-executor/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,18 @@ plugins {

description = "Flamingock CLI for executing changes in applications"

val jacksonVersion = "2.16.0"

dependencies {
// CLI Framework
implementation("info.picocli:picocli:4.7.5")
annotationProcessor("info.picocli:picocli-codegen:4.7.5")

// Core dependencies for response handling
implementation(project(":core:flamingock-core-commons"))
implementation(project(":utils:general-util"))
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:$jacksonVersion")

// Test dependencies
testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.2")
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.9.2")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package io.flamingock.cli.executor;

import io.flamingock.cli.executor.command.AuditCommand;
import io.flamingock.cli.executor.command.ExecuteCommand;
import io.flamingock.cli.executor.handler.ExecutorExceptionHandler;
import io.flamingock.cli.executor.util.VersionProvider;
Expand All @@ -41,11 +42,12 @@
"",
"@|bold Examples:|@",
" flamingock execute apply --jar ./app.jar",
" flamingock audit list --jar ./app.jar",
" flamingock --verbose execute apply --jar ./my-app.jar",
"",
"For detailed help on any command, use: flamingock <command> --help"
},
subcommands = {ExecuteCommand.class},
subcommands = {ExecuteCommand.class, AuditCommand.class},
mixinStandardHelpOptions = true,
versionProvider = VersionProvider.class
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,19 @@
import io.flamingock.cli.executor.FlamingockExecutorCli;
import io.flamingock.cli.executor.output.ConsoleFormatter;
import io.flamingock.cli.executor.process.JvmLauncher;
import io.flamingock.cli.executor.result.ResponseResultReader;
import io.flamingock.cli.executor.result.ResponseResultReader.ResponseResult;
import io.flamingock.cli.executor.util.VersionProvider;
import io.flamingock.internal.common.core.response.data.ExecuteResponseData;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import picocli.CommandLine.ParentCommand;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.Callable;

/**
Expand Down Expand Up @@ -54,6 +60,11 @@ public class ApplyCommand implements Callable<Integer> {
*/
public static final int EXIT_JAR_NOT_FOUND = 126;

/**
* Operation string for EXECUTE operation (matches FlamingockArguments parsing).
*/
private static final String OPERATION_EXECUTE = "EXECUTE";

@ParentCommand
private ExecuteCommand parent;

Expand Down Expand Up @@ -87,20 +98,55 @@ public Integer call() {
ConsoleFormatter.printVerbose("JAR file: " + jarFile.getAbsolutePath(), verbose);
ConsoleFormatter.printInfo("Launching Flamingock execution...");

// Launch the Spring Boot application with CLI mode enabled
JvmLauncher launcher = new JvmLauncher(verbose);
int exitCode = launcher.launch(jarFile.getAbsolutePath());
Path outputFile = null;
try {
outputFile = Files.createTempFile("flamingock-response-", ".json");
ConsoleFormatter.printVerbose("Response file: " + outputFile, verbose);

JvmLauncher launcher = new JvmLauncher(verbose);
int exitCode = launcher.launch(jarFile.getAbsolutePath(), OPERATION_EXECUTE, outputFile.toString());

if (exitCode == 0 && Files.exists(outputFile)) {
ResponseResultReader reader = new ResponseResultReader();
ResponseResult<ExecuteResponseData> result = reader.readTyped(outputFile, ExecuteResponseData.class);

if (result.isSuccess()) {
if (!quiet) {
ConsoleFormatter.printSuccess();
if (result.getData() != null && result.getData().getMessage() != null) {
ConsoleFormatter.printInfo(result.getData().getMessage());
}
ConsoleFormatter.printInfo("Duration: " + result.getDurationMs() + "ms");
}
} else {
ConsoleFormatter.printError("Error: " + result.getErrorMessage());
return 1;
}
} else if (exitCode != 0) {
if (Files.exists(outputFile)) {
ResponseResultReader reader = new ResponseResultReader();
ResponseResult<ExecuteResponseData> result = reader.readTyped(outputFile, ExecuteResponseData.class);
if (!result.isSuccess()) {
ConsoleFormatter.printError("Error [" + result.getErrorCode() + "]: " + result.getErrorMessage());
}
}
ConsoleFormatter.printFailure();
return exitCode;
}

// Print result message
if (exitCode == 0) {
if (!quiet) {
ConsoleFormatter.printSuccess();
return 0;

} catch (IOException e) {
ConsoleFormatter.printError("Failed to create temporary file: " + e.getMessage());
return 1;
} finally {
if (outputFile != null) {
try {
Files.deleteIfExists(outputFile);
} catch (IOException ignored) {
}
}
} else {
ConsoleFormatter.printFailure();
}

return exitCode;
}

private FlamingockExecutorCli getRootCommand() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright 2025 Flamingock (https://www.flamingock.io)
*
* Licensed 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 io.flamingock.cli.executor.command;

import picocli.CommandLine;
import picocli.CommandLine.Command;

/**
* Parent command for audit operations.
*
* <p>Groups subcommands related to audit inspection:</p>
* <ul>
* <li>{@code list} - List audit entries</li>
* </ul>
*/
@Command(
name = "audit",
description = "Audit operations for inspecting change history",
subcommands = {ListCommand.class},
mixinStandardHelpOptions = true
)
public class AuditCommand implements Runnable {

@CommandLine.ParentCommand
private Object parent;

@Override
public void run() {
// Show help when no subcommand is specified
new CommandLine(this).usage(System.out);
}
}
Loading
Loading