Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
name: Phase 2 Integration Tests

on:
push:
branches: [ main, maven-index ]
pull_request:
branches: [ main ]

jobs:
unit-tests:
name: Unit Tests (Phase 1)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
cache: maven

- name: Run unit tests
run: mvn clean integration-test

- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: unit-test-results
path: |
**/target/surefire-reports/*.xml
**/target/surefire-reports/*.txt

jdtls-integration-tests:
name: JDT.LS Integration Tests (Phase 2)
runs-on: ubuntu-latest
needs: unit-tests

steps:
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.23.9'

- name: Install Podman
run: |
sudo apt-get update
sudo apt-get -y install podman

- name: Verify Podman installation
run: |
podman --version
podman info

- name: Build JDT.LS container image with Podman
run: |
podman build -t jdtls-analyzer:test .

Comment on lines +58 to +61
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: Dockerfile inconsistency between CI and local environments.

Line 60 builds from the default Dockerfile, but the local test script (run_local.sh line 32) and Makefile (line 92) explicitly use Dockerfile.test. This environment drift will cause CI and local test runs to use different container configurations, potentially masking issues.

Apply this diff to align with local scripts:

       - name: Build JDT.LS container image with Podman
         run: |
-          podman build -t jdtls-analyzer:test .
+          podman build -t jdtls-analyzer:test -f Dockerfile.test .
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Build JDT.LS container image with Podman
run: |
podman build -t jdtls-analyzer:test .
- name: Build JDT.LS container image with Podman
run: |
podman build -t jdtls-analyzer:test -f Dockerfile.test .
🤖 Prompt for AI Agents
.github/workflows/integration-tests.yml around lines 58 to 61: the workflow
builds the container using the default Dockerfile which differs from local
scripts; update the podman build command to explicitly use the test Dockerfile
(e.g., add -f Dockerfile.test or --file Dockerfile.test) so CI uses the same
Dockerfile.test as run_local.sh and the Makefile, ensuring consistent container
configuration across environments.

- name: Run Phase 2 integration tests in container
run: |
podman run --rm \
-v $(pwd)/java-analyzer-bundle.test:/tests:Z \
-e WORKSPACE_DIR=/tests/projects \
-e JDTLS_PATH=/jdtls \
--workdir /tests/integration \
--entrypoint /bin/sh \
jdtls-analyzer:test \
-c "microdnf install -y golang && cd /tests/integration && go mod download && go test -v"
timeout-minutes: 15
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ target/
*.iml
.DS_Store
.gradle/
*/projects/.metadata
12 changes: 6 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM registry.access.redhat.com/ubi9/ubi AS jdtls-download
WORKDIR /jdtls
RUN curl -s -o jdtls.tar.gz https://download.eclipse.org/jdtls/milestones/1.38.0/jdt-language-server-1.38.0-202408011337.tar.gz &&\
RUN curl -s -o jdtls.tar.gz https://www.eclipse.org/downloads/download.php?file=/jdtls/milestones/1.51.0/jdt-language-server-1.51.0-202510022025.tar.gz &&\
tar -xvf jdtls.tar.gz --no-same-owner &&\
chmod 755 /jdtls/bin/jdtls &&\
rm -rf jdtls.tar.gz
Expand All @@ -22,8 +22,8 @@ FROM registry.access.redhat.com/ubi9/ubi AS addon-build
RUN dnf install -y maven-openjdk17 && dnf clean all && rm -rf /var/cache/dnf
WORKDIR /app
COPY ./ /app/
RUN export JAVA_HOME=/usr/lib/jvm/java-17-openjdk
RUN JAVA_HOME=/usr/lib/jvm/java-17-openjdk mvn clean install -DskipTests=true
ENV JAVA_HOME /usr/lib/jvm/java-17-openjdk
RUN mvn clean install -DskipTests=true

FROM registry.access.redhat.com/ubi9/ubi-minimal AS index-download
RUN microdnf install -y wget zip && microdnf clean all && rm -rf /var/cache/dnf
Expand All @@ -33,8 +33,8 @@ RUN wget --quiet https://github.com/konveyor/maven-search-index/releases/downloa

FROM registry.access.redhat.com/ubi9/ubi-minimal
# Java 1.8 is required for backwards compatibility with older versions of Gradle
RUN microdnf install -y python39 java-1.8.0-openjdk-devel java-17-openjdk-devel tar gzip zip --nodocs --setopt=install_weak_deps=0 && microdnf clean all && rm -rf /var/cache/dnf
ENV JAVA_HOME /usr/lib/jvm/java-17-openjdk
RUN microdnf install -y python39 java-1.8.0-openjdk-devel java-21-openjdk-devel tar gzip zip --nodocs --setopt=install_weak_deps=0 && microdnf clean all && rm -rf /var/cache/dnf
ENV JAVA_HOME /usr/lib/jvm/java-21-openjdk
# Specify Java 1.8 home for usage with gradle wrappers
ENV JAVA8_HOME /usr/lib/jvm/java-1.8.0-openjdk
RUN curl -fsSL -o /tmp/apache-maven.tar.gz https://dlcdn.apache.org/maven/maven-3/3.9.11/binaries/apache-maven-3.9.11-bin.tar.gz && \
Expand All @@ -49,7 +49,7 @@ COPY ./gradle/build.gradle /usr/local/etc/task.gradle
COPY ./gradle/build-v9.gradle /usr/local/etc/task-v9.gradle

COPY --from=jdtls-download /jdtls /jdtls/
COPY --from=addon-build /root/.m2/repository/io/konveyor/tackle/java-analyzer-bundle.core/1.0.0-SNAPSHOT/java-analyzer-bundle.core-1.0.0-SNAPSHOT.jar /jdtls/java-analyzer-bundle/java-analyzer-bundle.core/target/
COPY --from=addon-build /root/.m2/repository/io/konveyor/tackle/java-analyzer-bundle.core/1.0.0-SNAPSHOT/java-analyzer-bundle.core-1.0.0-SNAPSHOT.jar /jdtls/plugins/
COPY --from=fernflower /output/fernflower.jar /bin/fernflower.jar
COPY --from=maven-index /maven.default.index /usr/local/etc/maven.default.index
COPY --from=index-download /maven-index-data/central.archive-metadata.txt /usr/local/etc/maven-index.txt
Expand Down
53 changes: 53 additions & 0 deletions Dockerfile.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
FROM registry.access.redhat.com/ubi9/ubi AS jdtls-download
WORKDIR /jdtls
RUN curl -s -o jdtls.tar.gz https://download.eclipse.org/jdtls/milestones/1.50.0/jdt-language-server-1.50.0-202509041425.tar.gz &&\
tar -xvf jdtls.tar.gz --no-same-owner &&\
chmod 755 /jdtls/bin/jdtls &&\
rm -rf jdtls.tar.gz

COPY jdtls-bin-override/jdtls.py /jdtls/bin/jdtls.py

FROM registry.access.redhat.com/ubi9/ubi AS maven-index
COPY hack/maven.default.index /maven.default.index

FROM registry.access.redhat.com/ubi9/ubi AS fernflower
RUN dnf install -y maven-openjdk17 wget --setopt=install_weak_deps=False && dnf clean all && rm -rf /var/cache/dnf
RUN wget --quiet https://github.com/JetBrains/intellij-community/archive/refs/tags/idea/231.9011.34.tar.gz -O intellij-community.tar && tar xf intellij-community.tar intellij-community-idea-231.9011.34/plugins/java-decompiler/engine && rm -rf intellij-community.tar
WORKDIR /intellij-community-idea-231.9011.34/plugins/java-decompiler/engine
RUN export JAVA_HOME=/usr/lib/jvm/java-17-openjdk
RUN ./gradlew build -x test && rm -rf /root/.gradle
RUN mkdir /output && cp ./build/libs/fernflower.jar /output

FROM registry.access.redhat.com/ubi9/ubi-minimal AS index-download
RUN microdnf install -y wget zip && microdnf clean all && rm -rf /var/cache/dnf
WORKDIR /maven-index-data
#TODO: get latest release when we get to update them periodically
RUN wget --quiet https://github.com/konveyor/maven-search-index/releases/download/v0.0.1/maven-index-data-v0.0.1.zip -O maven-index-data.zip && unzip maven-index-data.zip && rm maven-index-data.zip

FROM registry.access.redhat.com/ubi9/ubi-minimal
# Java 1.8 is required for backwards compatibility with older versions of Gradle
RUN microdnf install -y python39 java-1.8.0-openjdk-devel java-21-openjdk-devel tar gzip zip --nodocs --setopt=install_weak_deps=0 && microdnf clean all && rm -rf /var/cache/dnf
ENV JAVA_HOME /usr/lib/jvm/java-21-openjdk
# Specify Java 1.8 home for usage with gradle wrappers
ENV JAVA8_HOME /usr/lib/jvm/java-1.8.0-openjdk
RUN curl -fsSL -o /tmp/apache-maven.tar.gz https://dlcdn.apache.org/maven/maven-3/3.9.11/binaries/apache-maven-3.9.11-bin.tar.gz && \
tar -xzf /tmp/apache-maven.tar.gz -C /usr/local/ && \
ln -s /usr/local/apache-maven-3.9.11/bin/mvn /usr/bin/mvn && \
rm /tmp/apache-maven.tar.gz
ENV M2_HOME /usr/local/apache-maven-3.9.11

# Copy "download sources" gradle task. This is needed to download project sources.
RUN mkdir /root/.gradle
COPY ./gradle/build.gradle /usr/local/etc/task.gradle
COPY ./gradle/build-v9.gradle /usr/local/etc/task-v9.gradle

COPY --from=jdtls-download /jdtls /jdtls/
COPY --from=fernflower /output/fernflower.jar /bin/fernflower.jar
COPY --from=maven-index /maven.default.index /usr/local/etc/maven.default.index
COPY --from=index-download /maven-index-data/central.archive-metadata.txt /usr/local/etc/maven-index.txt
COPY --from=index-download /maven-index-data/central.archive-metadata.idx /usr/local/etc/maven-index.idx
RUN microdnf install -y golang

RUN ln -sf /root/.m2 /.m2 && chgrp -R 0 /root && chmod -R g=u /root
COPY java-analyzer-bundle.core/target/java-analyzer-bundle.core-1.0.0-SNAPSHOT.jar /jdtls/plugins/
CMD [ "/jdtls/bin/jdtls" ]
141 changes: 141 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# Makefile for Java Analyzer Bundle
# Replicates GitHub Actions CI/CD pipeline for local verification

.PHONY: help all ci clean clean-containers clean-go phase1 phase2 unit-tests build-container run-integration-tests

# Detect container runtime (prefer Podman, fallback to Docker)
CONTAINER_RUNTIME := $(shell command -v podman 2>/dev/null || command -v docker 2>/dev/null)
ifeq ($(CONTAINER_RUNTIME),)
$(error Neither podman nor docker is installed)
endif

# Set volume flags based on container runtime
ifeq ($(findstring podman,$(CONTAINER_RUNTIME)),podman)
VOLUME_FLAGS := :Z
else
VOLUME_FLAGS :=
endif

# Variables
IMAGE_NAME := jdtls-analyzer:test
REPO_ROOT := $(shell pwd)
GO_MODULE := java-analyzer-bundle.test/integration

# Default target
help:
@echo "======================================================================"
@echo "Java Analyzer Bundle - CI/CD Verification Makefile"
@echo "======================================================================"
@echo ""
@echo "Available targets:"
@echo ""
@echo " make ci - Run complete CI/CD pipeline (Phase 1 + 2)"
@echo " make phase1 - Run Phase 1: Unit tests only"
@echo " make phase2 - Run Phase 2: Integration tests only"
@echo ""
@echo "Phase 1 targets:"
@echo " make unit-tests - Run Maven unit tests"
@echo ""
@echo "Phase 2 targets:"
@echo " make build-container - Build JDT.LS container image"
@echo " make run-integration-tests - Run integration tests in container"
@echo ""
@echo "Utility targets:"
@echo " make clean - Clean all build artifacts"
@echo " make clean-containers - Remove container images"
@echo " make clean-go - Clean Go build artifacts"
@echo ""
@echo "Container runtime: $(CONTAINER_RUNTIME)"
@echo "======================================================================"

# Run complete CI/CD pipeline
ci: phase1 phase2
@echo ""
@echo "======================================================================"
@echo "✓ Complete CI/CD Pipeline Succeeded!"
@echo "======================================================================"

# Alias for consistency
all: ci

# Phase 1: Unit Tests
phase1: unit-tests
@echo ""
@echo "======================================================================"
@echo "✓ Phase 1 Complete: Unit tests passed"
@echo "======================================================================"

# Phase 2: Integration Tests
phase2: build-container run-integration-tests
@echo ""
@echo "======================================================================"
@echo "✓ Phase 2 Complete: Integration tests passed"
@echo "======================================================================"

# Phase 1 Targets
unit-tests:
@echo "======================================================================"
@echo "Phase 1: Running Unit Tests"
@echo "======================================================================"
@echo ""
mvn clean integration-test

# Phase 2 Targets
build-container:
@echo ""
@echo "======================================================================"
@echo "Phase 2: Building JDT.LS Container Image"
@echo "======================================================================"
@echo ""
@echo "Using container runtime: $(CONTAINER_RUNTIME)"
@echo ""
$(CONTAINER_RUNTIME) build -t $(IMAGE_NAME) -f Dockerfile.test .
@echo ""
@echo "✓ Container image built: $(IMAGE_NAME)"

run-integration-tests:
@echo ""
@echo "======================================================================"
@echo "Phase 2: Running Integration Tests in Container"
@echo "======================================================================"
@echo ""
@echo "Installing Go and running tests inside container..."
$(CONTAINER_RUNTIME) run --rm \
-v $(REPO_ROOT)/java-analyzer-bundle.test:/tests$(VOLUME_FLAGS) \
-e WORKSPACE_DIR=/tests/projects \
-e JDTLS_PATH=/jdtls \
--workdir /tests/integration \
--entrypoint /bin/sh \
$(IMAGE_NAME) \
-c "microdnf install -y golang && go mod download && go test -v"
@echo ""
@echo "✓ Integration tests passed"

# Clean targets
clean: clean-go
@echo "======================================================================"
@echo "Cleaning Build Artifacts"
@echo "======================================================================"
mvn clean
@echo ""
@echo "✓ Maven artifacts cleaned"

clean-containers:
@echo "======================================================================"
@echo "Removing Container Images"
@echo "======================================================================"
-$(CONTAINER_RUNTIME) rmi $(IMAGE_NAME) 2>/dev/null || true
@echo ""
@echo "✓ Container images removed"

clean-go:
@echo "Cleaning Go build artifacts..."
cd $(GO_MODULE) && go clean -testcache
@echo "✓ Go artifacts cleaned"

# Development targets
.PHONY: test test-phase1 test-phase2 verify
test: ci
test-phase1: phase1
test-phase2: phase2
verify: ci
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.CompilationUnit;
Expand All @@ -26,9 +27,8 @@
import org.eclipse.jdt.core.search.SearchPattern;
import org.eclipse.jdt.internal.core.search.JavaSearchParticipant;
import org.eclipse.jdt.ls.core.internal.IDelegateCommandHandler;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin;
import org.eclipse.jdt.ls.core.internal.JDTUtils;
import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin;
import org.eclipse.jdt.ls.core.internal.JobHelpers;
import org.eclipse.jdt.ls.core.internal.ProjectUtils;
import org.eclipse.jdt.ls.core.internal.ResourceUtils;
Expand Down Expand Up @@ -162,6 +162,8 @@ private static SearchPattern mapLocationToSearchPatternLocation(int location, St
*/
private static SearchPattern getPatternSingleQuery(int location, String query) throws Exception {
var pattern = SearchPattern.R_PATTERN_MATCH;
// Package searches (location 11) always use PATTERN_MATCH because Eclipse JDT
// package matching is more flexible than exact matching
if ((!query.contains("?") && !query.contains("*")) && (location != 11)) {
logInfo("Using full match");
pattern = SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE;
Expand All @@ -178,23 +180,29 @@ private static SearchPattern getPatternSingleQuery(int location, String query) t
return SearchPattern.createPattern(query, IJavaSearchConstants.TYPE, IJavaSearchConstants.IMPLEMENTORS, pattern);
case 7:
case 9:
return SearchPattern.createPattern(query, IJavaSearchConstants.TYPE, IJavaSearchConstants.REFERENCES, pattern);
// Include R_ERASURE_MATCH to match parameterized types (e.g., List<String> when searching for java.util.List)
return SearchPattern.createPattern(query, IJavaSearchConstants.TYPE, IJavaSearchConstants.REFERENCES, pattern | SearchPattern.R_ERASURE_MATCH);
case 2:
if (query.contains(".")) {
return SearchPattern.createPattern(query, IJavaSearchConstants.METHOD, IJavaSearchConstants.QUALIFIED_REFERENCE, SearchPattern.R_PATTERN_MATCH | SearchPattern.R_ERASURE_MATCH);
}
// Switched back to referenced
return SearchPattern.createPattern(query, IJavaSearchConstants.METHOD, IJavaSearchConstants.REFERENCES, SearchPattern.R_PATTERN_MATCH | SearchPattern.R_ERASURE_MATCH);
case 3:
return SearchPattern.createPattern(query, IJavaSearchConstants.CONSTRUCTOR, IJavaSearchConstants.ALL_OCCURRENCES, pattern);
// Include R_ERASURE_MATCH to match parameterized constructor calls (e.g., ArrayList<String> when searching for java.util.ArrayList)
return SearchPattern.createPattern(query, IJavaSearchConstants.CONSTRUCTOR, IJavaSearchConstants.ALL_OCCURRENCES, pattern | SearchPattern.R_ERASURE_MATCH);
case 11:
return SearchPattern.createPattern(query, IJavaSearchConstants.PACKAGE, IJavaSearchConstants.ALL_OCCURRENCES, pattern);
case 12:
return SearchPattern.createPattern(query, IJavaSearchConstants.TYPE, IJavaSearchConstants.FIELD_DECLARATION_TYPE_REFERENCE, pattern);
// Include R_ERASURE_MATCH to match parameterized field types (e.g., List<String> when searching for java.util.List)
return SearchPattern.createPattern(query, IJavaSearchConstants.TYPE, IJavaSearchConstants.FIELD_DECLARATION_TYPE_REFERENCE, pattern | SearchPattern.R_ERASURE_MATCH);
case 13:
return SearchPattern.createPattern(query, IJavaSearchConstants.METHOD, IJavaSearchConstants.DECLARATIONS, SearchPattern.R_EXACT_MATCH | SearchPattern.R_PATTERN_MATCH);
case 14:
return SearchPattern.createPattern(query, IJavaSearchConstants.CLASS, IJavaSearchConstants.DECLARATIONS, SearchPattern.R_EXACT_MATCH | SearchPattern.R_PATTERN_MATCH);
case 6:
// Enum constants are fields, so we search for FIELD references
return SearchPattern.createPattern(query, IJavaSearchConstants.FIELD, IJavaSearchConstants.ALL_OCCURRENCES, pattern);
}
throw new Exception("unable to create search pattern");
}
Expand Down Expand Up @@ -343,7 +351,7 @@ private static List<SymbolInformation> search(String projectName, ArrayList<Stri

SearchEngine searchEngine = new SearchEngine();

SymbolInformationTypeRequestor requestor = new SymbolInformationTypeRequestor(symbols, 0, monitor, location, query, annotationQuery);
SymbolInformationTypeRequestor requestor = new SymbolInformationTypeRequestor(symbols, 0, monitor, location, query, annotationQuery, pattern);

//Use the default search participents
SearchParticipant participent = new JavaSearchParticipant();
Expand Down Expand Up @@ -416,4 +424,4 @@ public static Location getLocationForImport(ICompilationUnit icu, ImportDeclarat
return null;
}
}
}
}
Loading
Loading