Skip to content

Commit 1a9a2b4

Browse files
committed
feat: exposing analysis as service by splitting env variable injections into request configs and reuse it on both container and post bodies
1 parent da8434a commit 1a9a2b4

File tree

9 files changed

+951
-377
lines changed

9 files changed

+951
-377
lines changed

build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ dependencies {
1919
implementation 'io.quarkus:quarkus-container-image-jib'
2020
implementation 'io.quarkus:quarkus-vertx'
2121
implementation 'io.quarkus:quarkus-rest'
22+
implementation 'io.quarkus:quarkus-rest-jackson'
2223
implementation 'io.quarkus:quarkus-grpc'
2324

2425
implementation 'com.google.protobuf:protobuf-java-util'

src/main/java/net/explorviz/code/analysis/GitAnalysis.java

Lines changed: 47 additions & 345 deletions
Large diffs are not rendered by default.
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
package net.explorviz.code.analysis.api;
2+
3+
import java.util.Optional;
4+
import net.explorviz.code.analysis.service.AnalysisConfig;
5+
6+
/**
7+
* Request object for triggering a Git analysis.
8+
*/
9+
public class AnalysisRequest {
10+
11+
private String repoPath;
12+
private String repoRemoteUrl;
13+
private String remoteStoragePath;
14+
private String username;
15+
private String password;
16+
private String branch;
17+
private String sourceDirectory;
18+
private String restrictAnalysisToFolders;
19+
private boolean fetchRemoteData = true;
20+
private boolean sendToRemote = true;
21+
private boolean calculateMetrics = true;
22+
private String startCommit;
23+
private String endCommit;
24+
private boolean saveCrashedFiles;
25+
private String landscapeToken = "";
26+
private String applicationName = "";
27+
28+
public AnalysisRequest() {
29+
}
30+
31+
public String getRepoPath() {
32+
return repoPath;
33+
}
34+
35+
public void setRepoPath(final String repoPath) {
36+
this.repoPath = repoPath;
37+
}
38+
39+
public String getRepoRemoteUrl() {
40+
return repoRemoteUrl;
41+
}
42+
43+
public void setRepoRemoteUrl(final String repoRemoteUrl) {
44+
this.repoRemoteUrl = repoRemoteUrl;
45+
}
46+
47+
public String getSourceDirectory() {
48+
return sourceDirectory;
49+
}
50+
51+
public void setSourceDirectory(final String sourceDirectory) {
52+
this.sourceDirectory = sourceDirectory;
53+
}
54+
55+
public String getRestrictAnalysisToFolders() {
56+
return restrictAnalysisToFolders;
57+
}
58+
59+
public void setRestrictAnalysisToFolders(final String restrictAnalysisToFolders) {
60+
this.restrictAnalysisToFolders = restrictAnalysisToFolders;
61+
}
62+
63+
public boolean isFetchRemoteData() {
64+
return fetchRemoteData;
65+
}
66+
67+
public void setFetchRemoteData(final boolean fetchRemoteData) {
68+
this.fetchRemoteData = fetchRemoteData;
69+
}
70+
71+
public boolean isSendToRemote() {
72+
return sendToRemote;
73+
}
74+
75+
public void setSendToRemote(final boolean sendToRemote) {
76+
this.sendToRemote = sendToRemote;
77+
}
78+
79+
public boolean isCalculateMetrics() {
80+
return calculateMetrics;
81+
}
82+
83+
public void setCalculateMetrics(final boolean calculateMetrics) {
84+
this.calculateMetrics = calculateMetrics;
85+
}
86+
87+
public String getStartCommit() {
88+
return startCommit;
89+
}
90+
91+
public void setStartCommit(final String startCommit) {
92+
this.startCommit = startCommit;
93+
}
94+
95+
public String getEndCommit() {
96+
return endCommit;
97+
}
98+
99+
public void setEndCommit(final String endCommit) {
100+
this.endCommit = endCommit;
101+
}
102+
103+
public boolean isSaveCrashedFiles() {
104+
return saveCrashedFiles;
105+
}
106+
107+
public void setSaveCrashedFiles(final boolean saveCrashedFiles) {
108+
this.saveCrashedFiles = saveCrashedFiles;
109+
}
110+
111+
public String getLandscapeToken() {
112+
return landscapeToken;
113+
}
114+
115+
public void setLandscapeToken(final String landscapeToken) {
116+
this.landscapeToken = landscapeToken;
117+
}
118+
119+
public String getApplicationName() {
120+
return applicationName;
121+
}
122+
123+
public void setApplicationName(final String applicationName) {
124+
this.applicationName = applicationName;
125+
}
126+
127+
/**
128+
* Converts this request to an AnalysisConfig.
129+
*
130+
* @return The analysis configuration
131+
*/
132+
public AnalysisConfig toConfig() {
133+
return new AnalysisConfig.Builder()
134+
.repoPath(Optional.ofNullable(repoPath))
135+
.repoRemoteUrl(Optional.ofNullable(repoRemoteUrl))
136+
.remoteStoragePath(Optional.ofNullable(remoteStoragePath))
137+
.gitUsername(Optional.ofNullable(username))
138+
.gitPassword(Optional.ofNullable(password))
139+
.branch(Optional.ofNullable(branch))
140+
.sourceDirectory(Optional.ofNullable(sourceDirectory))
141+
.restrictAnalysisToFolders(Optional.ofNullable(restrictAnalysisToFolders))
142+
.fetchRemoteData(fetchRemoteData)
143+
.sendToRemote(sendToRemote)
144+
.calculateMetrics(calculateMetrics)
145+
.startCommit(Optional.ofNullable(startCommit))
146+
.endCommit(Optional.ofNullable(endCommit))
147+
.saveCrashedFiles(saveCrashedFiles)
148+
.landscapeToken(landscapeToken != null ? landscapeToken : "")
149+
.applicationName(applicationName != null ? applicationName : "")
150+
.build();
151+
}
152+
}
153+
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package net.explorviz.code.analysis.api;
2+
3+
import jakarta.inject.Inject;
4+
import jakarta.ws.rs.Consumes;
5+
import jakarta.ws.rs.POST;
6+
import jakarta.ws.rs.Path;
7+
import jakarta.ws.rs.Produces;
8+
import jakarta.ws.rs.core.MediaType;
9+
import jakarta.ws.rs.core.Response;
10+
import java.io.IOException;
11+
import net.explorviz.code.analysis.exceptions.NotFoundException;
12+
import net.explorviz.code.analysis.exceptions.PropertyNotDefinedException;
13+
import net.explorviz.code.analysis.export.DataExporter;
14+
import net.explorviz.code.analysis.export.GrpcExporter;
15+
import net.explorviz.code.analysis.export.JsonExporter;
16+
import net.explorviz.code.analysis.service.AnalysisConfig;
17+
import net.explorviz.code.analysis.service.AnalysisService;
18+
import org.eclipse.jgit.api.errors.GitAPIException;
19+
import org.eclipse.microprofile.config.inject.ConfigProperty;
20+
import org.slf4j.Logger;
21+
import org.slf4j.LoggerFactory;
22+
23+
/**
24+
* REST resource for triggering Git analysis operations.
25+
*/
26+
@Path("/api/analysis")
27+
public class AnalysisResource {
28+
29+
private static final Logger LOGGER = LoggerFactory.getLogger(AnalysisResource.class);
30+
31+
@ConfigProperty(name = "explorviz.gitanalysis.send-to-remote", defaultValue = "true")
32+
/* default */ boolean sendToRemoteProperty; // NOCS
33+
34+
@Inject
35+
/* default */ AnalysisService analysisService; // NOCS
36+
37+
@Inject
38+
/* default */ GrpcExporter grpcExporter; // NOCS
39+
40+
/**
41+
* Triggers a Git repository analysis with the provided configuration.
42+
*
43+
* @param request The analysis request containing configuration
44+
* @return Response indicating success or failure
45+
*/
46+
@POST
47+
@Path("/trigger")
48+
@Consumes(MediaType.APPLICATION_JSON)
49+
@Produces(MediaType.TEXT_PLAIN)
50+
public Response triggerAnalysis(final AnalysisRequest request) {
51+
if (request == null) {
52+
LOGGER.error("Request body is null or invalid");
53+
return Response.status(Response.Status.BAD_REQUEST)
54+
.entity("Request body is required")
55+
.build();
56+
}
57+
58+
try {
59+
final String repoInfo = request.getRepoPath() != null ? request.getRepoPath()
60+
: (request.getRepoRemoteUrl() != null ? request.getRepoRemoteUrl() : "unknown");
61+
LOGGER.info("Triggering analysis for repository: {}", repoInfo);
62+
63+
final AnalysisConfig config = request.toConfig();
64+
65+
final DataExporter exporter;
66+
if (sendToRemoteProperty) {
67+
exporter = grpcExporter;
68+
} else {
69+
exporter = new JsonExporter();
70+
}
71+
72+
analysisService.analyzeAndSendRepo(config, exporter);
73+
74+
LOGGER.info("Analysis completed successfully");
75+
return Response.ok("Analysis completed successfully").build();
76+
77+
} catch (IOException | GitAPIException | NotFoundException | PropertyNotDefinedException e) {
78+
LOGGER.error("Analysis failed: {}", e.getMessage(), e);
79+
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
80+
.entity("Analysis failed: " + e.getMessage())
81+
.build();
82+
}
83+
}
84+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package net.explorviz.code.analysis.api;
2+
3+
import jakarta.ws.rs.GET;
4+
import jakarta.ws.rs.Path;
5+
import jakarta.ws.rs.Produces;
6+
import jakarta.ws.rs.core.MediaType;
7+
8+
@Path("/api/health")
9+
public class HealthResource {
10+
@GET
11+
@Produces(MediaType.TEXT_PLAIN)
12+
public String health() {
13+
return "OK";
14+
}
15+
}
16+

src/main/java/net/explorviz/code/analysis/git/GitRepositoryHandler.java

Lines changed: 14 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import net.explorviz.code.analysis.FileIO;
1919
import net.explorviz.code.analysis.exceptions.NotFoundException;
2020
import net.explorviz.code.analysis.exceptions.PropertyNotDefinedException;
21+
import net.explorviz.code.analysis.service.AnalysisConfig;
2122
import net.explorviz.code.analysis.types.FileDescriptor;
2223
import net.explorviz.code.analysis.types.RemoteRepositoryObject;
2324
import net.explorviz.code.analysis.types.Triple;
@@ -64,24 +65,6 @@ public class GitRepositoryHandler { // NOPMD
6465
private static final String JAVA_PATH_SUFFIX = ".java";
6566
private static String repositoryPath;
6667

67-
@ConfigProperty(name = "explorviz.gitanalysis.local.storage-path")
68-
/* default */ Optional<String> repoPathProperty; // NOCS
69-
70-
@ConfigProperty(name = "explorviz.gitanalysis.remote.url")
71-
/* default */ Optional<String> repoUrlProperty; // NOCS
72-
73-
@ConfigProperty(name = "explorviz.gitanalysis.remote.storage-path")
74-
/* default */ Optional<String> repoLocalStoragePathProperty; // NOCS
75-
76-
@ConfigProperty(name = "explorviz.gitanalysis.remote.username")
77-
/* default */ Optional<String> usernameProperty; // NOCS
78-
79-
@ConfigProperty(name = "explorviz.gitanalysis.remote.password")
80-
/* default */ Optional<String> passwordProperty; // NOCS
81-
82-
@ConfigProperty(name = "explorviz.gitanalysis.branch")
83-
/* default */ Optional<String> repositoryBranchProperty; // NOCS
84-
8568
private Git git;
8669

8770
public static String getCurrentRepositoryPath() {
@@ -313,29 +296,32 @@ public Repository getGitRepository(final String localRepositoryPath,
313296
* directory will be created. <br> The branch given in {@code explorviz.gitanalysis.branch} will
314297
* be used if present, otherwise the default (remote) or current (local) will be used.
315298
*
299+
* @param config the analysis config
316300
* @return an opened Git {@link Repository}
317301
* @throws PropertyNotDefinedException gets thrown if a needed property is not present
318302
* @throws GitAPIException gets thrown if the git api encounters an error
319303
* @throws IOException gets thrown if JGit cannot open the Git repository.
320304
*/
321-
public Repository getGitRepository()
305+
public Repository getGitRepository(AnalysisConfig config)
322306
throws PropertyNotDefinedException, GitAPIException, IOException {
323-
if (repoUrlProperty.isEmpty() && repoPathProperty.isEmpty()) {
324-
throw new PropertyNotDefinedException("explorviz.gitanalysis.local.folder.path");
307+
if (config.getRepoPath().isEmpty() && config.getRepoRemoteUrl().isEmpty()) {
308+
throw new PropertyNotDefinedException("explorviz.gitanalysis.remote.url");
325309
}
326310

327311
final CredentialsProvider credentialsProvider;
328-
if (usernameProperty.isEmpty() || passwordProperty.isEmpty()) {
312+
if (config.getGitUsername().isEmpty() || config.getGitPassword().isEmpty()) {
329313
credentialsProvider = CredentialsProvider.getDefault();
330314
} else {
331-
credentialsProvider = new UsernamePasswordCredentialsProvider(usernameProperty.get(),
332-
passwordProperty.get());
315+
credentialsProvider = new UsernamePasswordCredentialsProvider(
316+
config.getGitUsername().get(),
317+
config.getGitPassword().get()
318+
);
333319
}
334320

335-
return getGitRepository(this.repoPathProperty.orElse(""),
336-
new RemoteRepositoryObject(this.repoUrlProperty.orElse(""),
337-
repoLocalStoragePathProperty.orElse(""), credentialsProvider,
338-
repositoryBranchProperty.orElse("")));
321+
return getGitRepository(config.getRepoPath().orElse(""),
322+
new RemoteRepositoryObject(config.getRepoRemoteUrl().orElse(""),
323+
config.getRemoteStoragePath().orElse(""), credentialsProvider,
324+
config.getBranch().orElse("")));
339325
}
340326

341327
/**

0 commit comments

Comments
 (0)