Skip to content

Commit ce849fc

Browse files
committed
Initial implementation of Picocli usage
Introduced new Config-Objects to abstract away cli-arguments to config transformation. Will also be needed for YAML/JSON configuration in the future
1 parent b21f651 commit ce849fc

File tree

10 files changed

+621
-1
lines changed

10 files changed

+621
-1
lines changed

pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@
6161
<artifactId>logback-classic</artifactId>
6262
<version>1.2.3</version>
6363
</dependency>
64+
<dependency>
65+
<groupId>info.picocli</groupId>
66+
<artifactId>picocli</artifactId>
67+
<version>4.0.0-beta-1b</version>
68+
</dependency>
6469
<dependency>
6570
<groupId>com.oracle.jdbc</groupId>
6671
<artifactId>ojdbc8</artifactId>

src/main/java/org/utplsql/cli/LoggerConfiguration.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import com.zaxxer.hikari.HikariDataSource;
1010
import org.slf4j.LoggerFactory;
1111

12-
class LoggerConfiguration {
12+
public class LoggerConfiguration {
1313

1414
public enum ConfigLevel {
1515
BASIC, NONE, DEBUG
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
package org.utplsql.cli;
2+
3+
import org.utplsql.cli.config.FileMapperConfig;
4+
import org.utplsql.cli.config.ReporterConfig;
5+
import org.utplsql.cli.config.RunCommandConfig;
6+
import picocli.CommandLine.*;
7+
8+
import java.util.*;
9+
import java.util.concurrent.Callable;
10+
11+
@Command( name = "run", description = "run tests")
12+
public class RunPicocliCommand implements Callable<RunCommandConfig> {
13+
14+
@Parameters(description = ConnectionInfo.COMMANDLINE_PARAM_DESCRIPTION)
15+
private String connectionString;
16+
17+
@Option(names = {"-p", "--path"},
18+
description = "run suites/tests by path, format: " +
19+
"-p=[schema|schema:[suite ...][.test]|schema[.suite ...][.test]")
20+
private List<String> paths = new ArrayList<>();
21+
22+
23+
@Option(
24+
names = {"-c", "--color"},
25+
description = "enables printing of test results in colors as defined by ANSICONSOLE standards")
26+
private boolean colorConsole = false;
27+
28+
@Option(
29+
names = {"-d", "--debug"},
30+
description = "Outputs a load of debug information to console")
31+
private boolean logDebug = false;
32+
33+
@Option(
34+
names = {"-q", "--quiet"},
35+
description = "Does not output the informational messages normally printed to console")
36+
private boolean logSilent = false;
37+
38+
@Option(
39+
names = {"--failure-exit-code"},
40+
description = "override the exit code on failure, default = 1")
41+
private int failureExitCode = 1;
42+
43+
44+
@Option(
45+
names = {"-scc", "--skip-compatibility-check"},
46+
description = "Skips the check for compatibility with database framework. CLI expects the framework to be " +
47+
"most actual. Use this if you use CLI with a development version of utPLSQL-framework")
48+
private boolean skipCompatibilityCheck = false;
49+
50+
@Option(
51+
names = {"-t", "--timeout"},
52+
description = "Sets the timeout in minutes after which the cli will abort. Default 60")
53+
private int timeoutInMinutes = 60;
54+
55+
@Option(
56+
names = {"-include"},
57+
description = "Comma-separated object list to include in the coverage report. " +
58+
"Format: [schema.]package[,[schema.]package ...]. See coverage reporting options in framework documentation"
59+
)
60+
private String includeObjects = null;
61+
62+
@Option(
63+
names = {"-exclude"},
64+
description = "Comma-separated object list to exclude from the coverage report. " +
65+
"Format: [schema.]package[,[schema.]package ...]. See coverage reporting options in framework documentation"
66+
)
67+
private String excludeObjects = null;
68+
69+
70+
@Option(
71+
names = {"-D", "--dbms_output"},
72+
description = "Enables DBMS_OUTPUT for the TestRunner (default: DISABLED)"
73+
)
74+
private boolean enableDbmsOutput = false;
75+
76+
// RandomTestOrder
77+
@Option(
78+
names = {"-r", "--random-test-order"},
79+
description = "Enables random order of test executions (default: DISABLED)"
80+
)
81+
private boolean randomTestOrder = false;
82+
83+
@Option(
84+
names = {"-seed", "--random-test-order-seed"},
85+
description = "Sets the seed to use for random test execution order. If set, it sets --random-test-order to true"
86+
)
87+
private Integer randomTestOrderSeed;
88+
89+
@ArgGroup(exclusive = false, multiplicity = "0..*")
90+
private List<Format> reporters = new ArrayList<>();
91+
92+
static class Format {
93+
@Option(names={"-f", "--format"}, required = true, description = "Enables specified format reporting")
94+
String format;
95+
@Option(names={"-o"}, description = "Outputs format to file")
96+
String outputFile;
97+
@Option(names={"-s"}, description = "Outputs to screen even when an output file is specified")
98+
boolean outputToScreen = false;
99+
}
100+
101+
// FileMappings
102+
@ArgGroup(exclusive = false, multiplicity = "0..2")
103+
private List<FileMappingComposite> fileMappings;
104+
105+
static class FileMappingComposite {
106+
107+
static class TestOrSourcePath {
108+
@Option(names="-source_path", required = true)
109+
String sourcePath;
110+
@Option(names="-test_path", required = true)
111+
String testPath;
112+
113+
String getPath() {
114+
return ( isSourcePath() ) ? sourcePath : testPath;
115+
}
116+
117+
boolean isSourcePath() {
118+
return sourcePath != null;
119+
}
120+
}
121+
122+
static class FileMapping {
123+
@Option(names="-owner")
124+
String owner;
125+
@Option(names="-regex_expression")
126+
String regexExpression;
127+
@Option(names="-type_mapping")
128+
String typeMapping;
129+
@Option(names="-owner_subexpression")
130+
Integer ownerSubExpression;
131+
@Option(names="-type_subexpression")
132+
Integer typeSubExpression;
133+
@Option(names="-name_subexpression")
134+
Integer nameSubExpression;
135+
}
136+
137+
@ArgGroup(exclusive = true, multiplicity = "1")
138+
TestOrSourcePath testOrSourcePath;
139+
140+
@ArgGroup(exclusive = false, multiplicity = "1")
141+
FileMapping mapping;
142+
143+
144+
FileMapperConfig toFileMapperConfig() {
145+
Map<String, String> typeMap = new HashMap<>();
146+
147+
if ( mapping.typeMapping != null && !mapping.typeMapping.isEmpty()) {
148+
for ( String keyVal : mapping.typeMapping.split("/")) {
149+
String[] values = keyVal.split("=");
150+
typeMap.put(values[0], values[1]);
151+
}
152+
}
153+
154+
return new FileMapperConfig(
155+
testOrSourcePath.getPath(),
156+
mapping.owner,
157+
mapping.regexExpression,
158+
typeMap,
159+
mapping.ownerSubExpression,
160+
mapping.typeSubExpression,
161+
mapping.nameSubExpression
162+
);
163+
}
164+
}
165+
166+
private String[] splitOrEmpty(String value) {
167+
if ( value == null || value.isEmpty() ) {
168+
return new String[0];
169+
}
170+
else {
171+
return value.split(",");
172+
}
173+
}
174+
175+
@Override
176+
public RunCommandConfig call() throws Exception {
177+
178+
// Prepare path elements
179+
ArrayList<String> suitePaths = new ArrayList<>();
180+
for ( String pathElem : paths ) {
181+
suitePaths.addAll(Arrays.asList(pathElem.split(",")));
182+
}
183+
184+
// Prepare LogLevelConfig
185+
LoggerConfiguration.ConfigLevel loggerConfigLevel = LoggerConfiguration.ConfigLevel.BASIC;
186+
if ( logSilent ) {
187+
loggerConfigLevel = LoggerConfiguration.ConfigLevel.NONE;
188+
}
189+
else if ( logDebug ) {
190+
loggerConfigLevel = LoggerConfiguration.ConfigLevel.DEBUG;
191+
}
192+
193+
// Prepare Reporter configs
194+
List<ReporterConfig> reporterConfigs = new ArrayList<>();
195+
for ( Format format : reporters ) {
196+
reporterConfigs.add(new ReporterConfig(format.format, format.outputFile, format.outputToScreen));
197+
}
198+
199+
// Prepare TypeMappings
200+
FileMapperConfig sourceFileMapping = null;
201+
FileMapperConfig testFileMapping = null;
202+
if ( fileMappings != null ) {
203+
for ( FileMappingComposite fmc : fileMappings ) {
204+
if ( fmc.testOrSourcePath.isSourcePath() ) {
205+
sourceFileMapping = fmc.toFileMapperConfig();
206+
}
207+
else {
208+
testFileMapping = fmc.toFileMapperConfig();
209+
}
210+
}
211+
}
212+
213+
return new RunCommandConfig(
214+
connectionString,
215+
suitePaths.toArray(new String[0]),
216+
reporterConfigs.toArray(new ReporterConfig[0]),
217+
colorConsole,
218+
failureExitCode,
219+
skipCompatibilityCheck,
220+
splitOrEmpty(includeObjects),
221+
splitOrEmpty(excludeObjects),
222+
sourceFileMapping,
223+
testFileMapping,
224+
loggerConfigLevel,
225+
timeoutInMinutes,
226+
enableDbmsOutput,
227+
randomTestOrder,
228+
randomTestOrderSeed);
229+
}
230+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package org.utplsql.cli;
2+
3+
import picocli.CommandLine;
4+
5+
@CommandLine.Command(
6+
name = "utplsql",
7+
description = "utPLSQL cli",
8+
subcommands = { RunPicocliCommand.class })
9+
public class UtplsqlPicocliCommand {
10+
11+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.utplsql.cli.config;
2+
3+
import java.beans.ConstructorProperties;
4+
5+
public class ConnectionConfig {
6+
7+
private final String connectString;
8+
9+
@ConstructorProperties({"connectString"})
10+
public ConnectionConfig(String connectString) {
11+
this.connectString = connectString;
12+
}
13+
14+
public String getConnectString() {
15+
return connectString;
16+
}
17+
18+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package org.utplsql.cli.config;
2+
3+
import java.beans.ConstructorProperties;
4+
import java.util.Map;
5+
6+
public class FileMapperConfig {
7+
8+
private final String path;
9+
private final String owner;
10+
private final String regexExpression;
11+
private final Map<String, String> typeMapping;
12+
private final Integer ownerSubexpression;
13+
private final Integer nameSubexpression;
14+
private final Integer typeSubexpression;
15+
16+
@ConstructorProperties({"path", "owner", "regexExpression", "typeMapping", "ownerSubexpression", "nameSubexpression", "typeSubexpression"})
17+
public FileMapperConfig(String path, String owner, String regexExpression, Map<String, String> typeMapping, Integer ownerSubexpression, Integer nameSubexpression, Integer typeSubexpression) {
18+
this.path = path;
19+
this.owner = owner;
20+
this.regexExpression = regexExpression;
21+
this.typeMapping = typeMapping;
22+
this.ownerSubexpression = ownerSubexpression;
23+
this.nameSubexpression = nameSubexpression;
24+
this.typeSubexpression = typeSubexpression;
25+
}
26+
27+
public String getPath() {
28+
return path;
29+
}
30+
31+
public String getOwner() {
32+
return owner;
33+
}
34+
35+
public String getRegexExpression() {
36+
return regexExpression;
37+
}
38+
39+
public Map<String, String> getTypeMapping() {
40+
return typeMapping;
41+
}
42+
43+
public Integer getOwnerSubexpression() {
44+
return ownerSubexpression;
45+
}
46+
47+
public Integer getNameSubexpression() {
48+
return nameSubexpression;
49+
}
50+
51+
public Integer getTypeSubexpression() {
52+
return typeSubexpression;
53+
}
54+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package org.utplsql.cli.config;
2+
3+
import java.beans.ConstructorProperties;
4+
5+
public class ReporterConfig {
6+
7+
private final String name;
8+
private final String output;
9+
private boolean screen = false;
10+
11+
@ConstructorProperties({"name", "output", "screen"})
12+
public ReporterConfig( String name, String output, Boolean screen ) {
13+
this.name = name;
14+
this.output = output;
15+
if ( screen != null ) this.screen = screen;
16+
}
17+
18+
public String getName() {
19+
return name;
20+
}
21+
22+
public String getOutput() {
23+
return output;
24+
}
25+
26+
public boolean isScreen() {
27+
return screen;
28+
}
29+
}

0 commit comments

Comments
 (0)