Skip to content

Commit 4c8c0ee

Browse files
authored
Merge pull request #156 from entur/feature/cli
Feature: CLI module
2 parents 6485b2b + 2f0a391 commit 4c8c0ee

File tree

20 files changed

+1058
-1
lines changed

20 files changed

+1058
-1
lines changed

.github/workflows/build-external.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,7 @@ jobs:
2626
${{ runner.os }}-
2727
- name: Run maven build
2828
run: mvn install -PprettierCheck -Dprettier.nodePath=node -Dprettier.npmPath=npm
29+
- name: codecov
30+
uses: codecov/codecov-action@v5
31+
with:
32+
files: ./**/target/site/jacoco/jacoco.xml

.github/workflows/build.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ jobs:
3131
${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
3232
${{ runner.os }}-maven-
3333
${{ runner.os }}-
34-
3534
- name: Run maven build
3635
run: mvn verify -s .github/workflows/settings.xml -PprettierCheck -Dprettier.nodePath=node -Dprettier.npmPath=npm
3736
- name: Sonar Scan
@@ -47,6 +46,10 @@ jobs:
4746
-Dsonar.projectName=${SONAR_PROJECT_NAME} \
4847
-Dsonar.host.url=https://sonarcloud.io \
4948
-Dsonar.token=${SONAR_TOKEN}
49+
- name: codecov
50+
uses: codecov/codecov-action@v5
51+
with:
52+
files: ./**/target/site/jacoco/jacoco.xml
5053
- name: Upload artifact
5154
uses: actions/[email protected]
5255
with:

.github/workflows/deploy.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ jobs:
5656
-Dsonar.projectName=${SONAR_PROJECT_NAME} \
5757
-Dsonar.host.url=https://sonarcloud.io \
5858
-Dsonar.token=${SONAR_TOKEN}
59+
- name: codecov
60+
uses: codecov/codecov-action@v5
61+
with:
62+
files: ./**/target/site/jacoco/jacoco.xml
5963
- name: Upload artifact
6064
uses: actions/[email protected]
6165
with:

gbfs-validator-java-cli/pom.xml

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
<parent>
7+
<groupId>org.entur.gbfs</groupId>
8+
<artifactId>gbfs-validator-java-parent</artifactId>
9+
<version>2.0.57-SNAPSHOT</version>
10+
</parent>
11+
12+
<artifactId>gbfs-validator-java-cli</artifactId>
13+
<packaging>jar</packaging>
14+
<name>GBFS Validator CLI</name>
15+
<description>Command-line interface for GBFS validation</description>
16+
<url>https://github.com/entur/gbfs-validator-java</url>
17+
18+
<properties>
19+
<maven.compiler.source>17</maven.compiler.source>
20+
<maven.compiler.target>17</maven.compiler.target>
21+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
22+
<picocli.version>4.7.7</picocli.version>
23+
<jackson.version>2.15.2</jackson.version>
24+
<junit.version>5.10.2</junit.version>
25+
<jacoco-maven-plugin.version>0.8.13</jacoco-maven-plugin.version>
26+
<!-- empty argLine property, the value is set up by Jacoco during unit tests execution -->
27+
<argLine></argLine>
28+
</properties>
29+
30+
<dependencies>
31+
<!-- Internal dependencies -->
32+
<dependency>
33+
<groupId>org.entur.gbfs</groupId>
34+
<artifactId>gbfs-validator-java</artifactId>
35+
<version>${project.version}</version>
36+
</dependency>
37+
<dependency>
38+
<groupId>org.entur.gbfs</groupId>
39+
<artifactId>gbfs-validator-java-loader</artifactId>
40+
<version>${project.version}</version>
41+
</dependency>
42+
43+
<!-- Picocli for CLI parsing -->
44+
<dependency>
45+
<groupId>info.picocli</groupId>
46+
<artifactId>picocli</artifactId>
47+
<version>${picocli.version}</version>
48+
</dependency>
49+
50+
<!-- Jackson for JSON output -->
51+
<dependency>
52+
<groupId>com.fasterxml.jackson.core</groupId>
53+
<artifactId>jackson-databind</artifactId>
54+
<version>${jackson.version}</version>
55+
</dependency>
56+
57+
<!-- SLF4J simple logger for CLI (runtime only) -->
58+
<dependency>
59+
<groupId>org.slf4j</groupId>
60+
<artifactId>slf4j-simple</artifactId>
61+
<version>2.0.17</version>
62+
</dependency>
63+
64+
<!-- Test dependencies -->
65+
<dependency>
66+
<groupId>org.junit.jupiter</groupId>
67+
<artifactId>junit-jupiter</artifactId>
68+
<version>${junit.version}</version>
69+
<scope>test</scope>
70+
</dependency>
71+
<dependency>
72+
<groupId>org.mockito</groupId>
73+
<artifactId>mockito-junit-jupiter</artifactId>
74+
<version>5.11.0</version>
75+
<scope>test</scope>
76+
</dependency>
77+
<dependency>
78+
<groupId>com.github.tomakehurst</groupId>
79+
<artifactId>wiremock-jre8</artifactId>
80+
<version>2.35.1</version>
81+
<scope>test</scope>
82+
</dependency>
83+
</dependencies>
84+
85+
<build>
86+
<resources>
87+
<resource>
88+
<directory>src/main/resources</directory>
89+
<filtering>true</filtering>
90+
</resource>
91+
</resources>
92+
<plugins>
93+
<!-- Compiler with Picocli annotation processor -->
94+
<plugin>
95+
<artifactId>maven-compiler-plugin</artifactId>
96+
<version>3.14.1</version>
97+
<configuration>
98+
<source>17</source>
99+
<target>17</target>
100+
<encoding>UTF-8</encoding>
101+
<annotationProcessorPaths>
102+
<path>
103+
<groupId>info.picocli</groupId>
104+
<artifactId>picocli-codegen</artifactId>
105+
<version>${picocli.version}</version>
106+
</path>
107+
</annotationProcessorPaths>
108+
<compilerArgs>
109+
<arg>-Aproject=${project.groupId}/${project.artifactId}</arg>
110+
</compilerArgs>
111+
</configuration>
112+
</plugin>
113+
114+
<!-- Maven Shade Plugin for executable uber-JAR -->
115+
<plugin>
116+
<groupId>org.apache.maven.plugins</groupId>
117+
<artifactId>maven-shade-plugin</artifactId>
118+
<version>3.6.1</version>
119+
<executions>
120+
<execution>
121+
<phase>package</phase>
122+
<goals>
123+
<goal>shade</goal>
124+
</goals>
125+
<configuration>
126+
<transformers>
127+
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
128+
<mainClass>org.entur.gbfs.validator.cli.GbfsValidatorCli</mainClass>
129+
</transformer>
130+
</transformers>
131+
<finalName>gbfs-validator-cli</finalName>
132+
<filters>
133+
<filter>
134+
<!-- Exclude signature files -->
135+
<artifact>*:*</artifact>
136+
<excludes>
137+
<exclude>META-INF/*.SF</exclude>
138+
<exclude>META-INF/*.DSA</exclude>
139+
<exclude>META-INF/*.RSA</exclude>
140+
</excludes>
141+
</filter>
142+
</filters>
143+
</configuration>
144+
</execution>
145+
</executions>
146+
</plugin>
147+
148+
<!-- Jacoco for code coverage -->
149+
<plugin>
150+
<groupId>org.jacoco</groupId>
151+
<artifactId>jacoco-maven-plugin</artifactId>
152+
<version>${jacoco-maven-plugin.version}</version>
153+
<executions>
154+
<execution>
155+
<id>default-prepare-agent</id>
156+
<goals>
157+
<goal>prepare-agent</goal>
158+
</goals>
159+
</execution>
160+
<execution>
161+
<id>default-report</id>
162+
<phase>prepare-package</phase>
163+
<goals>
164+
<goal>report</goal>
165+
</goals>
166+
</execution>
167+
<execution>
168+
<id>default-check</id>
169+
<goals>
170+
<goal>check</goal>
171+
</goals>
172+
<configuration>
173+
<rules />
174+
</configuration>
175+
</execution>
176+
</executions>
177+
</plugin>
178+
179+
<!-- Surefire for tests -->
180+
<plugin>
181+
<groupId>org.apache.maven.plugins</groupId>
182+
<artifactId>maven-surefire-plugin</artifactId>
183+
<version>3.0.0</version>
184+
</plugin>
185+
</plugins>
186+
</build>
187+
</project>
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package org.entur.gbfs.validator.cli;
2+
3+
import picocli.CommandLine.ArgGroup;
4+
import picocli.CommandLine.Option;
5+
6+
public class AuthOptions {
7+
8+
@Option(
9+
names = { "--auth-type" },
10+
description = "Authentication type: basic, bearer, or oauth"
11+
)
12+
AuthType authType;
13+
14+
@ArgGroup(exclusive = false)
15+
BasicAuthOptions basicAuth;
16+
17+
@ArgGroup(exclusive = false)
18+
BearerAuthOptions bearerAuth;
19+
20+
@ArgGroup(exclusive = false)
21+
OAuthOptions oauthOptions;
22+
23+
public static class BasicAuthOptions {
24+
25+
@Option(
26+
names = { "--username" },
27+
description = "Username for Basic Authentication",
28+
required = true
29+
)
30+
String username;
31+
32+
@Option(
33+
names = { "--password" },
34+
description = "Password for Basic Authentication",
35+
required = true
36+
)
37+
String password;
38+
}
39+
40+
public static class BearerAuthOptions {
41+
42+
@Option(
43+
names = { "--token" },
44+
description = "Bearer token",
45+
required = true
46+
)
47+
String token;
48+
}
49+
50+
public static class OAuthOptions {
51+
52+
@Option(
53+
names = { "--client-id" },
54+
description = "OAuth client ID",
55+
required = true
56+
)
57+
String clientId;
58+
59+
@Option(
60+
names = { "--client-secret" },
61+
description = "OAuth client secret",
62+
required = true
63+
)
64+
String clientSecret;
65+
66+
@Option(
67+
names = { "--token-url" },
68+
description = "OAuth token endpoint URL",
69+
required = true
70+
)
71+
String tokenUrl;
72+
}
73+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package org.entur.gbfs.validator.cli;
2+
3+
public enum AuthType {
4+
BASIC,
5+
BEARER,
6+
OAUTH,
7+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package org.entur.gbfs.validator.cli;
2+
3+
import org.entur.gbfs.validator.loader.auth.Authentication;
4+
import org.entur.gbfs.validator.loader.auth.BasicAuth;
5+
import org.entur.gbfs.validator.loader.auth.BearerTokenAuth;
6+
import org.entur.gbfs.validator.loader.auth.OAuthClientCredentialsGrantAuth;
7+
8+
public class AuthenticationHandler {
9+
10+
public static Authentication buildAuthentication(AuthOptions authOptions) {
11+
if (authOptions == null || authOptions.authType == null) {
12+
return null;
13+
}
14+
15+
return switch (authOptions.authType) {
16+
case BASIC -> {
17+
if (authOptions.basicAuth == null) {
18+
throw new IllegalArgumentException(
19+
"Basic auth selected but --username and --password not provided"
20+
);
21+
}
22+
yield new BasicAuth(
23+
authOptions.basicAuth.username,
24+
authOptions.basicAuth.password
25+
);
26+
}
27+
case BEARER -> {
28+
if (authOptions.bearerAuth == null) {
29+
throw new IllegalArgumentException(
30+
"Bearer auth selected but --token not provided"
31+
);
32+
}
33+
yield new BearerTokenAuth(authOptions.bearerAuth.token);
34+
}
35+
case OAUTH -> {
36+
if (authOptions.oauthOptions == null) {
37+
throw new IllegalArgumentException(
38+
"OAuth auth selected but credentials not provided"
39+
);
40+
}
41+
yield new OAuthClientCredentialsGrantAuth(
42+
authOptions.oauthOptions.clientId,
43+
authOptions.oauthOptions.clientSecret,
44+
authOptions.oauthOptions.tokenUrl
45+
);
46+
}
47+
};
48+
}
49+
}

0 commit comments

Comments
 (0)