Skip to content

Commit 70a1175

Browse files
committed
v1.3.1
1 parent 87ecd21 commit 70a1175

File tree

6 files changed

+398
-43
lines changed

6 files changed

+398
-43
lines changed

CHANGELOG.md

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,104 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [1.3.1] - 2025-06-02
9+
10+
### 🐛 Bug Fixes - Windows Path Compatibility
11+
- **Log File Path Handling**: Fixed Windows path compatibility issues in logging system
12+
- **Relative Path Recording**: Changed from absolute to relative paths in unresolved case logs
13+
- **Cross-platform File Names**: Enhanced filename sanitization to handle Windows path separators
14+
- **Log File Creation**: Added project name sanitization for safe log file creation
15+
16+
### 🔧 Technical Improvements
17+
- **Enhanced Filename Sanitization**: Updated regex pattern from `[^a-zA-Z0-9.-]` to `[^a-zA-Z0-9._-]`
18+
- **Relative Path Storage**: Log entries now store `src/test/java/com/example/Test.java` instead of full paths
19+
- **Project Name Cleaning**: Automatic removal of invalid characters from project names in log filenames
20+
21+
### 🌍 Cross-Platform Benefits
22+
-**Windows**: Log files now correctly handle `C:\Users\...` style paths
23+
-**Unix/Linux/macOS**: Maintains full backward compatibility
24+
-**JSON Compatibility**: Eliminates escaping issues with backslashes in JSON output
25+
26+
### 📋 Log File Improvements
27+
```json
28+
{
29+
"unresolvedCases": [
30+
{
31+
"fileName": "src/test/java/com/example/Test.java", // ✅ Relative path
32+
"className": "com.example.Test",
33+
"methodName": "testMethod"
34+
}
35+
]
36+
}
37+
```
38+
39+
**Before (v1.3.0)**: `"fileName": "C:\\Users\\user\\project\\src\\test\\java\\Test.java"`
40+
**After (v1.3.1)**: `"fileName": "src/test/java/Test.java"`
41+
42+
## [1.3.0] - 2025-06-02
43+
44+
### 🚀 Major Features
45+
- **Runtime Logging System**: Added comprehensive analysis session logging
46+
- **Execution Time Tracking**: Automatic recording of start time, end time, and duration
47+
- **Test Case Statistics**: Total and processed test case counts
48+
- **Unresolved Invocation Detection**: Automatic detection and detailed tracking of unresolved method calls
49+
- **Structured Log Output**: JSON format log files saved to `<output_dir>/<project_name>-log.json`
50+
51+
### ✨ New Features
52+
- **LogData Class**: Dedicated data structure for logging analysis session information
53+
- **Smart Status Tracking**: RUNNING → COMPLETED/FAILED/INTERRUPTED status progression
54+
- **Unresolved Code Analysis**: Identifies and catalogues:
55+
- `UNRESOLVED_INVOCATION` - Method calls that couldn't be resolved
56+
- `UNRESOLVED_CONSTRUCTOR` - Constructor calls that couldn't be resolved
57+
- `UNRESOLVED_METHOD_REF` - Method references that couldn't be resolved
58+
- `METHOD_NOT_FOUND_IN_SOURCE` - Methods not found in source code
59+
- `SOURCE_FILE_NOT_FOUND` - Source files that couldn't be located
60+
- **Graceful Interruption Handling**: Shutdown hooks to save logs even when interrupted
61+
- **Project Context Integration**: LogData integrated into ProjectCtx for task access
62+
63+
### 🔧 Technical Improvements
64+
- **Exception Handling**: Robust error handling with detailed error message logging
65+
- **Cross-platform Compatibility**: All logging functionality works on Windows/Linux/macOS
66+
- **Memory Efficient**: Streaming JSON output without memory overhead
67+
- **Thread Safe**: Volatile flags for proper multi-threading support
68+
69+
### 📊 Log File Structure
70+
```json
71+
{
72+
"projectName": "example-project",
73+
"taskName": "ParseTestCaseToLlmContext",
74+
"startTime": "2025-06-02T01:42:33",
75+
"endTime": "2025-06-02T01:42:34",
76+
"durationMs": 1243,
77+
"totalTestCases": 3,
78+
"processedTestCases": 3,
79+
"unresolvedInvocationCount": 2,
80+
"unresolvedCases": [
81+
{
82+
"className": "com.example.SampleTest",
83+
"methodName": "testWithUnresolvedCode",
84+
"fileName": "/path/to/SampleTest.java",
85+
"startLine": 14,
86+
"endLine": 22,
87+
"unresolvedCount": 2,
88+
"unresolvedInvocations": [
89+
"UNRESOLVED_CONSTRUCTOR: new SomeUnknownClass()#[17-17]",
90+
"UNRESOLVED_INVOCATION: unknown.someMethod()#[18-18]"
91+
]
92+
}
93+
],
94+
"status": "COMPLETED"
95+
}
96+
```
97+
98+
### 🎯 Use Cases
99+
- **Performance Monitoring**: Track analysis execution time across different projects
100+
- **Quality Assessment**: Identify test cases with resolution issues
101+
- **Problem Debugging**: Pinpoint exact locations of unresolved method calls
102+
- **Project Analytics**: Generate reports on test coverage and code quality
103+
104+
## [1.2.2] - 2024-12-08
105+
8106
## [1.1.2] - 2024-05-30
9107

10108
### 🐛 Bug Fixes

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ application {
1717
}
1818

1919
group = 'edu.stevens'
20-
version = '1.1.2'
20+
version = '1.3.1'
2121

2222
dependencies {
2323
// Use JitPack dependency for release builds

src/main/java/edu/stevens/swe/research/java/cli/Main.java

Lines changed: 88 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@
1414
import edu.stevens.swe.research.java.cli.analyzer.TaskManager;
1515
import edu.stevens.swe.research.java.cli.analyzer.TaskResult;
1616
import edu.stevens.swe.research.java.cli.analyzer.ResultFormatter;
17+
import edu.stevens.swe.research.java.cli.analyzer.LogData;
1718

18-
@Command(name = "analyzer", mixinStandardHelpOptions = true, version = "Analyzer CLI 1.1.2",
19+
@Command(name = "analyzer", mixinStandardHelpOptions = true, version = "Analyzer CLI 1.3.1",
1920
description = "Analyzes Java source code based on specified tasks.")
2021
public class Main implements Callable<Integer> {
2122

@@ -47,16 +48,25 @@ public class Main implements Callable<Integer> {
4748
private File pluginPath;
4849

4950
private TaskManager taskManager;
51+
private LogData logData;
52+
private volatile boolean normalExit = false; // Flag to track normal exit
5053

5154
public Main() {
5255
// TaskManager will be initialized in call() after ProjectCtx is created
5356
}
5457

5558
@Override
5659
public Integer call() throws Exception {
60+
// Extract project name from directory
61+
String projectName = projectDir.getName();
62+
63+
// Initialize logging
64+
logData = new LogData(projectName, taskName);
65+
5766
System.out.println("Analyzer CLI starting...");
5867
System.out.println("Task: " + taskName);
5968
System.out.println("Project Directory: " + projectDir.getAbsolutePath());
69+
System.out.println("Project Name: " + projectName);
6070
System.out.println("Language: " + language);
6171
System.out.println("Threads: " + (threads == 0 ? "Default (CPU Cores)" : threads));
6272
if (configFile != null) {
@@ -78,42 +88,88 @@ public Integer call() throws Exception {
7888
}
7989
System.out.println("Output Directory: " + outputDir.getAbsolutePath());
8090

81-
// 1. Create ProjectCtx
82-
ProjectCtx projectCtx = new ProjectCtx(projectDir.toPath(), language);
83-
// Set the output directory in ProjectCtx
84-
projectCtx.setOutputDirectory(outputDir.toPath());
85-
// TODO: Populate ProjectCtx further from configFile if provided
86-
// For example, load source roots, classpath, specific task configs etc.
91+
// Add shutdown hook to handle interruption
92+
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
93+
if (logData != null && !normalExit) {
94+
try {
95+
logData.finish("INTERRUPTED", "Process was interrupted by user");
96+
logData.writeToFile(outputDir.toPath(), projectName);
97+
} catch (Exception e) {
98+
System.err.println("Error writing log during shutdown: " + e.getMessage());
99+
}
100+
}
101+
}));
102+
103+
try {
104+
// 1. Create ProjectCtx
105+
ProjectCtx projectCtx = new ProjectCtx(projectDir.toPath(), language);
106+
// Set the output directory in ProjectCtx
107+
projectCtx.setOutputDirectory(outputDir.toPath());
108+
// Add log data to project context for tasks to access
109+
projectCtx.setLogData(logData);
110+
// TODO: Populate ProjectCtx further from configFile if provided
111+
// For example, load source roots, classpath, specific task configs etc.
112+
113+
// 2. Initialize TaskManager
114+
this.taskManager = new TaskManager(projectCtx, threads);
115+
116+
// 3. Get the specified task
117+
// AnalyzerTask task = taskManager.getTask(taskName); // This is done in TaskManager.executeTask
118+
119+
// 4. Execute the task
120+
System.out.println("Executing task via TaskManager: " + taskName);
121+
TaskResult result = taskManager.executeTask(taskName);
122+
123+
if (result == null) {
124+
System.err.println("Task execution failed or returned null result for task: " + taskName);
125+
logData.finish("FAILED", "Task execution returned null result");
126+
// Create a minimal result to avoid NullPointerException with formatter
127+
result = new TaskResult(projectCtx.getProjectPath().toString(), taskName + " [Execution Failed]");
128+
} else {
129+
logData.finish("COMPLETED");
130+
}
131+
132+
// 5. Format and output results
133+
ResultFormatter formatter = new ResultFormatter(outputFormat);
134+
try (OutputStream os = (outputFile != null) ? new FileOutputStream(outputFile) : System.out) {
135+
formatter.format(result, os); // Use the actual result from taskManager
136+
} catch (Exception e) {
137+
System.err.println("Error formatting or writing results: " + e.getMessage());
138+
e.printStackTrace();
139+
logData.finish("FAILED", "Error formatting results: " + e.getMessage());
140+
return 1;
141+
}
142+
143+
// Write log file
144+
try {
145+
logData.writeToFile(outputDir.toPath(), projectName);
146+
} catch (Exception e) {
147+
System.err.println("Error writing analysis log: " + e.getMessage());
148+
e.printStackTrace();
149+
// Don't fail the entire process for log writing issues
150+
}
151+
152+
System.out.println("Analysis finished.");
153+
normalExit = true; // Mark as normal exit
154+
return 0;
87155

88-
// 2. Initialize TaskManager
89-
this.taskManager = new TaskManager(projectCtx, threads);
90-
91-
// 3. Get the specified task
92-
// AnalyzerTask task = taskManager.getTask(taskName); // This is done in TaskManager.executeTask
93-
94-
// 4. Execute the task
95-
System.out.println("Executing task via TaskManager: " + taskName);
96-
TaskResult result = taskManager.executeTask(taskName);
97-
98-
if (result == null) {
99-
System.err.println("Task execution failed or returned null result for task: " + taskName);
100-
// Create a minimal result to avoid NullPointerException with formatter
101-
result = new TaskResult(projectCtx.getProjectPath().toString(), taskName + " [Execution Failed]");
102-
}
103-
104-
// 5. Format and output results
105-
ResultFormatter formatter = new ResultFormatter(outputFormat);
106-
try (OutputStream os = (outputFile != null) ? new FileOutputStream(outputFile) : System.out) {
107-
formatter.format(result, os); // Use the actual result from taskManager
108156
} catch (Exception e) {
109-
System.err.println("Error formatting or writing results: " + e.getMessage());
157+
System.err.println("Error during analysis: " + e.getMessage());
110158
e.printStackTrace();
159+
if (logData != null) {
160+
try {
161+
logData.finish("FAILED", "Unexpected error: " + e.getMessage());
162+
logData.writeToFile(outputDir.toPath(), projectName);
163+
} catch (Exception logException) {
164+
System.err.println("Error writing error log: " + logException.getMessage());
165+
}
166+
}
111167
return 1;
168+
} finally {
169+
if (taskManager != null) {
170+
taskManager.shutdown(); // Shutdown the executor service
171+
}
112172
}
113-
114-
System.out.println("Analysis finished.");
115-
taskManager.shutdown(); // Shutdown the executor service
116-
return 0;
117173
}
118174

119175
public static void main(String[] args) {

0 commit comments

Comments
 (0)