Skip to content

Commit f524e7d

Browse files
committed
feat: added tests and refactor App.java
Signed-off-by: Ruben Romero Montes <rromerom@redhat.com>
1 parent c6dd451 commit f524e7d

8 files changed

Lines changed: 417 additions & 95 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
# Maven
2323
target
2424
.flattened-pom.xml
25+
dependency-reduced-pom.xml
2526

2627
# Gradle
2728
.gradle

src/main/java/com/redhat/exhort/Cli.java renamed to src/main/java/com/redhat/exhort/cli/App.java

Lines changed: 63 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,16 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
package com.redhat.exhort;
16+
package com.redhat.exhort.cli;
17+
18+
import static com.redhat.exhort.cli.AppUtils.exitWithError;
19+
import static com.redhat.exhort.cli.AppUtils.printException;
20+
import static com.redhat.exhort.cli.AppUtils.printLine;
1721

1822
import com.fasterxml.jackson.annotation.JsonInclude;
1923
import com.fasterxml.jackson.core.JsonProcessingException;
2024
import com.fasterxml.jackson.databind.ObjectMapper;
25+
import com.redhat.exhort.Api;
2126
import com.redhat.exhort.api.v4.AnalysisReport;
2227
import com.redhat.exhort.api.v4.ProviderReport;
2328
import com.redhat.exhort.api.v4.Source;
@@ -29,25 +34,15 @@
2934
import java.util.concurrent.CompletableFuture;
3035
import java.util.concurrent.ExecutionException;
3136

32-
public class Cli {
37+
public class App {
3338

3439
private static final ObjectMapper MAPPER = new ObjectMapper();
40+
private static final String CLI_HELPTXT = "cli_help.txt";
3541

3642
static {
3743
MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL);
3844
}
3945

40-
private enum Command {
41-
STACK,
42-
COMPONENT
43-
}
44-
45-
private enum OutputFormat {
46-
JSON,
47-
SUMMARY,
48-
HTML
49-
}
50-
5146
public static void main(String[] args) {
5247
if (args.length == 0 || isHelpRequested(args)) {
5348
printHelp();
@@ -57,15 +52,14 @@ public static void main(String[] args) {
5752
try {
5853
CliArgs cliArgs = parseArgs(args);
5954
String result = executeCommand(cliArgs).get();
60-
System.out.println(result);
55+
printLine(result);
6156
} catch (IllegalArgumentException e) {
62-
System.err.println("Error: " + e.getMessage());
63-
System.err.println();
57+
printException(e);
6458
printHelp();
65-
System.exit(1);
59+
exitWithError();
6660
} catch (IOException | InterruptedException | ExecutionException e) {
67-
System.err.println("Unexpected error: " + e.getMessage());
68-
System.exit(1);
61+
printException(e);
62+
exitWithError();
6963
}
7064
}
7165

@@ -83,56 +77,58 @@ private static CliArgs parseArgs(String[] args) {
8377
throw new IllegalArgumentException("Missing required arguments");
8478
}
8579

86-
String commandStr = args[0].toLowerCase();
87-
Command command;
80+
Command command = parseCommand(args[0]);
81+
82+
Path path = validateFile(args[1]);
8883

84+
OutputFormat outputFormat = parseOutputFormat(command, args[2]);
85+
86+
return new CliArgs(command, path, outputFormat);
87+
}
88+
89+
private static Command parseCommand(String commandStr) {
8990
switch (commandStr) {
9091
case "stack":
91-
command = Command.STACK;
92-
break;
92+
return Command.STACK;
9393
case "component":
94-
command = Command.COMPONENT;
95-
break;
94+
return Command.COMPONENT;
9695
default:
9796
throw new IllegalArgumentException(
9897
"Unknown command: " + commandStr + ". Use 'stack' or 'component'");
9998
}
99+
}
100100

101-
String filePath = args[1];
102-
Path path = Paths.get(filePath);
101+
private static OutputFormat parseOutputFormat(Command command, String formatArg) {
102+
if (formatArg == null) {
103+
return OutputFormat.JSON;
104+
}
105+
106+
switch (formatArg) {
107+
case "--summary":
108+
return OutputFormat.SUMMARY;
109+
case "--html":
110+
if (command != Command.STACK) {
111+
throw new IllegalArgumentException("HTML format is only supported for stack command");
112+
}
113+
return OutputFormat.HTML;
114+
default:
115+
throw new IllegalArgumentException(
116+
"Unknown option for " + command + " command: " + formatArg);
117+
}
118+
}
103119

120+
private static Path validateFile(String filePath) {
121+
Path path = Paths.get(filePath);
104122
if (!Files.exists(path)) {
105123
throw new IllegalArgumentException("File does not exist: " + filePath);
106124
}
107-
108125
if (!Files.isRegularFile(path)) {
109-
throw new IllegalArgumentException("Path is not a file: " + filePath);
126+
throw new IllegalArgumentException("File is not a regular file: " + filePath);
110127
}
111-
112-
OutputFormat outputFormat = OutputFormat.JSON; // default
113-
114-
// Parse additional options for stack command
115-
if (args.length > 2) {
116-
for (int i = 2; i < args.length; i++) {
117-
switch (args[i]) {
118-
case "--summary":
119-
outputFormat = OutputFormat.SUMMARY;
120-
break;
121-
case "--html":
122-
if (command != Command.STACK) {
123-
throw new IllegalArgumentException("HTML format is only supported for stack command");
124-
}
125-
outputFormat = OutputFormat.HTML;
126-
break;
127-
default:
128-
throw new IllegalArgumentException("Unknown option for stack command: " + args[i]);
129-
}
130-
}
131-
} else if (command == Command.COMPONENT && args.length > 2) {
132-
throw new IllegalArgumentException("Component command does not accept additional options");
128+
if (!Files.isReadable(path)) {
129+
throw new IllegalArgumentException("File is not readable: " + filePath);
133130
}
134-
135-
return new CliArgs(command, path, outputFormat);
131+
return path;
136132
}
137133

138134
private static CompletableFuture<String> executeCommand(CliArgs args) throws IOException {
@@ -152,13 +148,13 @@ private static CompletableFuture<String> executeStackAnalysis(
152148
Api api = new ExhortApi();
153149
switch (outputFormat) {
154150
case JSON:
155-
return api.stackAnalysis(filePath).thenApply(Cli::toJsonString);
151+
return api.stackAnalysis(filePath).thenApply(App::toJsonString);
156152
case HTML:
157153
return api.stackAnalysisHtml(filePath).thenApply(bytes -> new String(bytes));
158154
case SUMMARY:
159155
return api.stackAnalysis(filePath)
160-
.thenApply(Cli::extractSummary)
161-
.thenApply(Cli::toJsonString);
156+
.thenApply(App::extractSummary)
157+
.thenApply(App::toJsonString);
162158
default:
163159
throw new AssertionError();
164160
}
@@ -169,9 +165,9 @@ private static CompletableFuture<String> executeComponentAnalysis(
169165
Api api = new ExhortApi();
170166
CompletableFuture<AnalysisReport> analysis = api.componentAnalysis(filePath);
171167
if (outputFormat.equals(OutputFormat.SUMMARY)) {
172-
analysis = analysis.thenApply(Cli::extractSummary);
168+
analysis = analysis.thenApply(App::extractSummary);
173169
}
174-
return analysis.thenApply(Cli::toJsonString);
170+
return analysis.thenApply(App::toJsonString);
175171
}
176172

177173
private static String toJsonString(Object obj) {
@@ -213,44 +209,16 @@ private static AnalysisReport extractSummary(AnalysisReport report) {
213209
}
214210

215211
private static void printHelp() {
216-
System.out.println("Exhort Java API CLI");
217-
System.out.println();
218-
System.out.println("USAGE:");
219-
System.out.println(" java -jar exhort-java-api.jar <COMMAND> <FILE_PATH> [OPTIONS]");
220-
System.out.println();
221-
System.out.println("COMMANDS:");
222-
System.out.println(" stack <file_path> [--summary|--html]");
223-
System.out.println(" Perform stack analysis on the specified manifest file");
224-
System.out.println(" Options:");
225-
System.out.println(" --summary Output summary in JSON format");
226-
System.out.println(" --html Output full report in HTML format");
227-
System.out.println(" (default) Output full report in JSON format");
228-
System.out.println();
229-
System.out.println(" component <file_path> [--summary]");
230-
System.out.println(" Perform component analysis on the specified manifest file");
231-
System.out.println(" Options:");
232-
System.out.println(" --summary Output summary in JSON format");
233-
System.out.println(" (default) Output full report in JSON format");
234-
System.out.println();
235-
System.out.println("OPTIONS:");
236-
System.out.println(" -h, --help Show this help message");
237-
System.out.println();
238-
System.out.println("EXAMPLES:");
239-
System.out.println(" java -jar exhort-java-api.jar stack /path/to/pom.xml");
240-
System.out.println(" java -jar exhort-java-api.jar stack /path/to/package.json --summary");
241-
System.out.println(" java -jar exhort-java-api.jar stack /path/to/build.gradle --html");
242-
System.out.println(" java -jar exhort-java-api.jar component /path/to/requirements.txt");
243-
}
244-
245-
private static class CliArgs {
246-
final Command command;
247-
final Path filePath;
248-
final OutputFormat outputFormat;
212+
try (var inputStream = App.class.getClassLoader().getResourceAsStream(CLI_HELPTXT)) {
213+
if (inputStream == null) {
214+
AppUtils.printError("Help file not found.");
215+
return;
216+
}
249217

250-
CliArgs(Command command, Path filePath, OutputFormat outputFormat) {
251-
this.command = command;
252-
this.filePath = filePath;
253-
this.outputFormat = outputFormat;
218+
String helpText = new String(inputStream.readAllBytes());
219+
printLine(helpText);
220+
} catch (IOException e) {
221+
AppUtils.printError("Error reading help file: " + e.getMessage());
254222
}
255223
}
256224
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright © 2025 Red Hat, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.redhat.exhort.cli;
17+
18+
public class AppUtils {
19+
public static void exitWithError() {
20+
System.exit(1);
21+
}
22+
23+
public static void exitWithSuccess() {
24+
System.exit(0);
25+
}
26+
27+
public static void printLine(String message) {
28+
System.out.println(message);
29+
}
30+
31+
public static void printLine() {
32+
System.out.println();
33+
}
34+
35+
public static void printError(String message) {
36+
System.err.println(message);
37+
System.err.println();
38+
}
39+
40+
public static void printException(Exception e) {
41+
printError("Error: " + e.getMessage());
42+
}
43+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright © 2025 Red Hat, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.redhat.exhort.cli;
17+
18+
import java.nio.file.Path;
19+
20+
public class CliArgs {
21+
public final Command command;
22+
public final Path filePath;
23+
public final OutputFormat outputFormat;
24+
25+
public CliArgs(Command command, Path filePath, OutputFormat outputFormat) {
26+
this.command = command;
27+
this.filePath = filePath;
28+
this.outputFormat = outputFormat;
29+
}
30+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright © 2025 Red Hat, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.redhat.exhort.cli;
17+
18+
public enum Command {
19+
STACK,
20+
COMPONENT
21+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright © 2025 Red Hat, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.redhat.exhort.cli;
17+
18+
public enum OutputFormat {
19+
JSON,
20+
SUMMARY,
21+
HTML
22+
}

src/main/resources/cli_help.txt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
Exhort Java API CLI
2+
3+
USAGE:
4+
java -jar exhort-java-api.jar <COMMAND> <FILE_PATH> [OPTIONS]
5+
6+
COMMANDS:
7+
stack <file_path> [--summary|--html]
8+
Perform stack analysis on the specified manifest file
9+
Options:
10+
--summary Output summary in JSON format
11+
--html Output full report in HTML format
12+
(default) Output full report in JSON format
13+
14+
component <file_path> [--summary]
15+
Perform component analysis on the specified manifest file
16+
Options:
17+
--summary Output summary in JSON format
18+
(default) Output full report in JSON format
19+
20+
OPTIONS:
21+
-h, --help Show this help message
22+
23+
EXAMPLES:
24+
java -jar exhort-java-api.jar stack /path/to/pom.xml
25+
java -jar exhort-java-api.jar stack /path/to/package.json --summary
26+
java -jar exhort-java-api.jar stack /path/to/build.gradle --html
27+
java -jar exhort-java-api.jar component /path/to/requirements.txt

0 commit comments

Comments
 (0)