diff --git a/demo-dep-output.yaml b/demo-dep-output.yaml
index 5242586f..177ed426 100644
--- a/demo-dep-output.yaml
+++ b/demo-dep-output.yaml
@@ -171,11 +171,6 @@
labels:
- konveyor.io/dep-source=downloadable
- konveyor.io/language=go
- - name: go
- version: "1.18"
- labels:
- - konveyor.io/dep-source=downloadable
- - konveyor.io/language=go
- name: go.etcd.io/etcd/client/pkg/v3
version: v3.5.1
labels:
diff --git a/demo-output.yaml b/demo-output.yaml
index c4c0f803..cde52196 100644
--- a/demo-output.yaml
+++ b/demo-output.yaml
@@ -577,6 +577,16 @@
lineNumber: 6
variables:
file: file:///examples/python/file_a.py
+ python-sample-rule-003:
+ description: ""
+ category: potential
+ incidents:
+ - uri: file:///examples/python/main.py
+ message: python sample rule 003
+ codeSnip: "19 # Create an instance of the API class\n20 api_instance = kubernetes.client.ApiextensionsV1Api(api_client)\n21 body = kubernetes.client.V1CustomResourceDefinition() # V1CustomResourceDefinition | \n22 pretty = 'pretty_example' # str | If 'true', then the output is pretty printed. (optional)\n23 dry_run = 'dry_run_example' # str | When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed (optional)\n24 field_manager = 'field_manager_example' # str | fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. (optional)\n25 field_validation = 'field_validation_example' # str | fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered. (optional)\n26 \n27 try:\n28 api_response = api_instance.create_custom_resource_definition(body, pretty=pretty, dry_run=dry_run, field_manager=field_manager, field_validation=field_validation)\n29 pprint(api_response)\n30 except ApiException as e:\n31 print(\"Exception when calling ApiextensionsV1Api->create_custom_resource_definition: %s\\n\" % e)\n"
+ lineNumber: 28
+ variables:
+ file: file:///examples/python/main.py
singleton-sessionbean-00001:
description: ""
category: potential
@@ -898,4 +908,3 @@
unmatched:
- file-002
- lang-ref-002
- - python-sample-rule-003
diff --git a/external-providers/generic-external-provider/go.mod b/external-providers/generic-external-provider/go.mod
index 53aad1b7..b168db2a 100644
--- a/external-providers/generic-external-provider/go.mod
+++ b/external-providers/generic-external-provider/go.mod
@@ -17,7 +17,7 @@ require (
github.com/PaesslerAG/gval v1.2.2 // indirect
github.com/cbroglie/mustache v1.4.0 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
- github.com/golang/protobuf v1.5.2 // indirect
+ github.com/golang/protobuf v1.5.3 // indirect
github.com/hashicorp/go-version v1.6.0 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/shopspring/decimal v1.3.1 // indirect
@@ -28,11 +28,10 @@ require (
go.opentelemetry.io/otel/exporters/jaeger v1.11.2 // indirect
go.opentelemetry.io/otel/sdk v1.11.2 // indirect
go.opentelemetry.io/otel/trace v1.11.2 // indirect
- golang.org/x/net v0.17.0 // indirect
- golang.org/x/sys v0.13.0 // indirect
- golang.org/x/text v0.13.0 // indirect
- google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect
- google.golang.org/grpc v1.62.1 // indirect
+ golang.org/x/net v0.20.0 // indirect
+ golang.org/x/sys v0.16.0 // indirect
+ golang.org/x/text v0.14.0 // indirect
+ google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 // indirect
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
)
diff --git a/external-providers/generic-external-provider/go.sum b/external-providers/generic-external-provider/go.sum
index d25e0af5..167c4e71 100644
--- a/external-providers/generic-external-provider/go.sum
+++ b/external-providers/generic-external-provider/go.sum
@@ -20,6 +20,7 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
@@ -71,16 +72,21 @@ go.opentelemetry.io/otel/trace v1.11.2 h1:Xf7hWSF2Glv0DE3MH7fBHvtpSBsjcBUe5MYAmZ
go.opentelemetry.io/otel/trace v1.11.2/go.mod h1:4N+yC7QEz7TTsG9BSRLNAa63eg5E06ObSbKPmxQ/pKA=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
+golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w=
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
+google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro=
google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag=
google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
+google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
diff --git a/external-providers/golang-dependency-provider/go.mod b/external-providers/golang-dependency-provider/go.mod
index 0b56f85e..739964c0 100644
--- a/external-providers/golang-dependency-provider/go.mod
+++ b/external-providers/golang-dependency-provider/go.mod
@@ -26,10 +26,10 @@ require (
go.opentelemetry.io/otel/metric v1.17.0 // indirect
go.opentelemetry.io/otel/sdk v1.17.0 // indirect
go.opentelemetry.io/otel/trace v1.17.0 // indirect
- golang.org/x/net v0.17.0 // indirect
- golang.org/x/sys v0.13.0 // indirect
- golang.org/x/text v0.13.0 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5 // indirect
+ golang.org/x/net v0.20.0 // indirect
+ golang.org/x/sys v0.16.0 // indirect
+ golang.org/x/text v0.14.0 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // indirect
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
diff --git a/external-providers/golang-dependency-provider/go.sum b/external-providers/golang-dependency-provider/go.sum
index 10ca506e..a96c5737 100644
--- a/external-providers/golang-dependency-provider/go.sum
+++ b/external-providers/golang-dependency-provider/go.sum
@@ -66,15 +66,20 @@ go.opentelemetry.io/otel/trace v1.17.0 h1:/SWhSRHmDPOImIAetP1QAeMnZYiQXrTy4fMMYO
go.opentelemetry.io/otel/trace v1.17.0/go.mod h1:I/4vKTgFclIsXRVucpH25X0mpFSczM7aHeaz0ZBLWjY=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
+golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5 h1:eSaPbMR4T7WfH9FvABk36NBMacoTUKdWCvV0dx+KfOg=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5/go.mod h1:zBEcrKX2ZOcEkHWxBPAIvYUWOKKMIhYcmNiUIu2ji3I=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80/go.mod h1:PAREbraiVEVGVdTZsVWjSbbTtSyGbAgIIvni8a8CD5s=
google.golang.org/grpc v1.58.0 h1:32JY8YpPMSR45K+c3o6b8VL73V+rR8k+DeMIr4vRH8o=
google.golang.org/grpc v1.58.0/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
+google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
diff --git a/external-providers/java-external-provider/examples/gradle-multi-project-example/.gitignore b/external-providers/java-external-provider/examples/gradle-multi-project-example/.gitignore
new file mode 100644
index 00000000..0c740ded
--- /dev/null
+++ b/external-providers/java-external-provider/examples/gradle-multi-project-example/.gitignore
@@ -0,0 +1,105 @@
+### Intellij+iml ###
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff:
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/dictionaries
+
+# Sensitive or high-churn files:
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.xml
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+
+# Gradle:
+.idea/**/gradle.xml
+.idea/**/libraries
+
+## File-based project format:
+*.iws
+
+## Plugin-specific files:
+
+# IntelliJ
+/out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+### Intellij+iml Patch ###
+# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
+
+.idea/
+
+*.iml
+modules.xml
+.idea/misc.xml
+*.ipr
+
+### Java ###
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# Package Files #
+*.jar
+*.war
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+### macOS ###
+*.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+### Gradle ###
+.gradle
+**/build/
+
+# Ignore Gradle GUI config
+gradle-app.setting
+
+# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
+!gradle-wrapper.jar
+
+# Cache of project
+.gradletasknamecache
diff --git a/external-providers/java-external-provider/examples/gradle-multi-project-example/LICENSE b/external-providers/java-external-provider/examples/gradle-multi-project-example/LICENSE
new file mode 100644
index 00000000..25408ddc
--- /dev/null
+++ b/external-providers/java-external-provider/examples/gradle-multi-project-example/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) [year] [author]
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/external-providers/java-external-provider/examples/gradle-multi-project-example/Procfile b/external-providers/java-external-provider/examples/gradle-multi-project-example/Procfile
new file mode 100644
index 00000000..40dc36e6
--- /dev/null
+++ b/external-providers/java-external-provider/examples/gradle-multi-project-example/Procfile
@@ -0,0 +1,2 @@
+web: java -jar build/libs/template-server-all.jar
+worker: java -jar build/libs/template-core-all.jar
diff --git a/external-providers/java-external-provider/examples/gradle-multi-project-example/README.md b/external-providers/java-external-provider/examples/gradle-multi-project-example/README.md
new file mode 100644
index 00000000..64e41321
--- /dev/null
+++ b/external-providers/java-external-provider/examples/gradle-multi-project-example/README.md
@@ -0,0 +1,53 @@
+# gradle-multi-project-example
+
+Basic gradle template with subprojects, deployable to Heroku as separate dyno processes.
+
+## What's included?
+
+1. Gradle Plugins
+ - application plugin
+ - shadowjar plugin
+2. Code Style
+ - checkstyle
+ - findbugs
+ - pmd
+3. General Libraries
+ - guava
+ - junit
+ - mockito
+ - log4j2 via slf4j
+4. Multi-Project Gradle Setup
+ - see: [settings.gradle](settings.gradle)
+5. Heroku Deployment
+ - see: [Procfile](Procfile), [stage.gradle](gradle/heroku/stage.gradle)
+
+## Development
+
+### Building
+
+```
+$ ./gradlew clean build
+```
+
+### Testing
+
+```
+$ ./gradlew clean test
+```
+
+### Building Deployment Artifacts
+
+```
+$ ./gradlew clean stage
+```
+
+### Running
+
+Use the Gradle [application plugin](https://docs.gradle.org/current/userguide/application_plugin.html).
+However, `./gradlew run` will run applications in lexicographical order.
+Instead, explicitly specify which subproject to run:
+
+```
+$ ./gradlew template-core:run
+$ ./gradlew template-server:run
+```
diff --git a/external-providers/java-external-provider/examples/gradle-multi-project-example/build.gradle b/external-providers/java-external-provider/examples/gradle-multi-project-example/build.gradle
new file mode 100644
index 00000000..d81723d2
--- /dev/null
+++ b/external-providers/java-external-provider/examples/gradle-multi-project-example/build.gradle
@@ -0,0 +1,47 @@
+apply plugin: 'idea'
+
+ext {
+ log4jVersion = '2.9.1'
+}
+
+buildscript {
+ repositories {
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.1'
+ }
+}
+
+allprojects {
+ repositories {
+ mavenLocal()
+ mavenCentral() // maven { url: 'http://jcenter.bintray.com' }
+ }
+}
+
+apply from: file('gradle/check.gradle')
+apply from: file('gradle/heroku/clean.gradle')
+
+subprojects {
+ apply plugin: 'com.github.johnrengelman.shadow'
+ apply plugin: 'java'
+
+ group = "io.jeffchao.${rootProject.name}"
+
+ dependencies {
+ implementation 'com.google.guava:guava:23.0'
+
+ testImplementation 'junit:junit:4.12'
+
+ compile "org.apache.logging.log4j:log4j-api:$log4jVersion"
+ compile "org.apache.logging.log4j:log4j-core:$log4jVersion"
+ compile "org.apache.logging.log4j:log4j-slf4j-impl:$log4jVersion"
+
+ testCompile 'org.mockito:mockito-core:2.11.0'
+
+ }
+
+ apply from: file("$rootProject.projectDir/gradle/heroku/stage.gradle")
+
+}
\ No newline at end of file
diff --git a/external-providers/java-external-provider/examples/gradle-multi-project-example/codequality/checkstyle.xml b/external-providers/java-external-provider/examples/gradle-multi-project-example/codequality/checkstyle.xml
new file mode 100644
index 00000000..2d6336e9
--- /dev/null
+++ b/external-providers/java-external-provider/examples/gradle-multi-project-example/codequality/checkstyle.xml
@@ -0,0 +1,238 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/external-providers/java-external-provider/examples/gradle-multi-project-example/gradle/check.gradle b/external-providers/java-external-provider/examples/gradle-multi-project-example/gradle/check.gradle
new file mode 100644
index 00000000..19af4208
--- /dev/null
+++ b/external-providers/java-external-provider/examples/gradle-multi-project-example/gradle/check.gradle
@@ -0,0 +1,15 @@
+subprojects {
+ apply plugin: 'checkstyle'
+ checkstyle {
+ ignoreFailures = true
+ configFile = rootProject.file('codequality/checkstyle.xml')
+ toolVersion = '8.4'
+ }
+
+ apply plugin: 'findbugs'
+ findbugs {
+ ignoreFailures = true
+ }
+
+ apply plugin: 'pmd'
+}
diff --git a/external-providers/java-external-provider/examples/gradle-multi-project-example/gradle/heroku/clean.gradle b/external-providers/java-external-provider/examples/gradle-multi-project-example/gradle/heroku/clean.gradle
new file mode 100644
index 00000000..67329835
--- /dev/null
+++ b/external-providers/java-external-provider/examples/gradle-multi-project-example/gradle/heroku/clean.gradle
@@ -0,0 +1,5 @@
+apply plugin: 'base'
+
+clean.doLast {
+ delete rootProject.buildDir
+}
\ No newline at end of file
diff --git a/external-providers/java-external-provider/examples/gradle-multi-project-example/gradle/heroku/stage.gradle b/external-providers/java-external-provider/examples/gradle-multi-project-example/gradle/heroku/stage.gradle
new file mode 100644
index 00000000..819e4e83
--- /dev/null
+++ b/external-providers/java-external-provider/examples/gradle-multi-project-example/gradle/heroku/stage.gradle
@@ -0,0 +1,8 @@
+task stage(dependsOn: ['clean', 'shadowJar'])
+
+task copyToLib(type: Copy) {
+ from "$buildDir/libs"
+ into "$rootProject.buildDir/libs"
+}
+copyToLib.dependsOn(shadowJar)
+stage.dependsOn(copyToLib)
\ No newline at end of file
diff --git a/external-providers/java-external-provider/examples/gradle-multi-project-example/gradle/wrapper/gradle-wrapper.jar b/external-providers/java-external-provider/examples/gradle-multi-project-example/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..27768f1b
Binary files /dev/null and b/external-providers/java-external-provider/examples/gradle-multi-project-example/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/external-providers/java-external-provider/examples/gradle-multi-project-example/gradle/wrapper/gradle-wrapper.properties b/external-providers/java-external-provider/examples/gradle-multi-project-example/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..7e4921d3
--- /dev/null
+++ b/external-providers/java-external-provider/examples/gradle-multi-project-example/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Nov 01 15:30:19 PDT 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.3-all.zip
diff --git a/external-providers/java-external-provider/examples/gradle-multi-project-example/gradlew b/external-providers/java-external-provider/examples/gradle-multi-project-example/gradlew
new file mode 100755
index 00000000..cccdd3d5
--- /dev/null
+++ b/external-providers/java-external-provider/examples/gradle-multi-project-example/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/external-providers/java-external-provider/examples/gradle-multi-project-example/gradlew.bat b/external-providers/java-external-provider/examples/gradle-multi-project-example/gradlew.bat
new file mode 100644
index 00000000..e95643d6
--- /dev/null
+++ b/external-providers/java-external-provider/examples/gradle-multi-project-example/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/external-providers/java-external-provider/examples/gradle-multi-project-example/settings.gradle b/external-providers/java-external-provider/examples/gradle-multi-project-example/settings.gradle
new file mode 100644
index 00000000..ace373a1
--- /dev/null
+++ b/external-providers/java-external-provider/examples/gradle-multi-project-example/settings.gradle
@@ -0,0 +1,4 @@
+rootProject.name = 'basic-gradle-template'
+
+include 'template-core'
+include 'template-server'
diff --git a/external-providers/java-external-provider/examples/gradle-multi-project-example/template-core/build.gradle b/external-providers/java-external-provider/examples/gradle-multi-project-example/template-core/build.gradle
new file mode 100644
index 00000000..7fb7ee66
--- /dev/null
+++ b/external-providers/java-external-provider/examples/gradle-multi-project-example/template-core/build.gradle
@@ -0,0 +1,10 @@
+apply plugin: 'application'
+
+mainClassName = 'io.jeffchao.template.core.Core'
+
+dependencies {
+}
+
+run.doFirst {
+ // Environment variables go here.
+}
\ No newline at end of file
diff --git a/external-providers/java-external-provider/examples/gradle-multi-project-example/template-core/src/main/java/io/jeffchao/template/core/Core.java b/external-providers/java-external-provider/examples/gradle-multi-project-example/template-core/src/main/java/io/jeffchao/template/core/Core.java
new file mode 100644
index 00000000..b430f2b1
--- /dev/null
+++ b/external-providers/java-external-provider/examples/gradle-multi-project-example/template-core/src/main/java/io/jeffchao/template/core/Core.java
@@ -0,0 +1,8 @@
+package io.jeffchao.template.core;
+
+public class Core {
+
+ public static void main(String[] args) {
+ System.out.println("hello, template!");
+ }
+}
\ No newline at end of file
diff --git a/external-providers/java-external-provider/examples/gradle-multi-project-example/template-core/src/test/java/io/jeffchao/template/core/CoreTest.java b/external-providers/java-external-provider/examples/gradle-multi-project-example/template-core/src/test/java/io/jeffchao/template/core/CoreTest.java
new file mode 100644
index 00000000..d88ab5a1
--- /dev/null
+++ b/external-providers/java-external-provider/examples/gradle-multi-project-example/template-core/src/test/java/io/jeffchao/template/core/CoreTest.java
@@ -0,0 +1,16 @@
+package io.jeffchao.template.core;
+
+import org.junit.After;
+import org.junit.Before;
+
+
+public class CoreTest {
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+}
\ No newline at end of file
diff --git a/external-providers/java-external-provider/examples/gradle-multi-project-example/template-server/build.gradle b/external-providers/java-external-provider/examples/gradle-multi-project-example/template-server/build.gradle
new file mode 100644
index 00000000..47600b02
--- /dev/null
+++ b/external-providers/java-external-provider/examples/gradle-multi-project-example/template-server/build.gradle
@@ -0,0 +1,10 @@
+apply plugin: 'application'
+
+mainClassName = 'io.jeffchao.template.server.Server'
+
+dependencies {
+}
+
+run.doFirst {
+ // Environment variables go here.
+}
diff --git a/external-providers/java-external-provider/examples/gradle-multi-project-example/template-server/src/main/java/io/jeffchao/template/server/Server.java b/external-providers/java-external-provider/examples/gradle-multi-project-example/template-server/src/main/java/io/jeffchao/template/server/Server.java
new file mode 100644
index 00000000..cc6d373d
--- /dev/null
+++ b/external-providers/java-external-provider/examples/gradle-multi-project-example/template-server/src/main/java/io/jeffchao/template/server/Server.java
@@ -0,0 +1,32 @@
+package io.jeffchao.template.server;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
+
+public class Server {
+
+ public static void main(String[] args) throws IOException {
+ String portString = System.getenv("PORT");
+ int port = portString == null ? 8080 : Integer.valueOf(portString);
+ HttpServer server = HttpServer.create(new InetSocketAddress(port), 0);
+ server.createContext("/", new MyHandler());
+ server.setExecutor(null); // creates a default executor
+ server.start();
+ }
+
+ static class MyHandler implements HttpHandler {
+ @Override
+ public void handle(HttpExchange t) throws IOException {
+ String response = "Hello from Gradle!";
+ t.sendResponseHeaders(200, response.length());
+ OutputStream os = t.getResponseBody();
+ os.write(response.getBytes());
+ os.close();
+ }
+ }
+}
\ No newline at end of file
diff --git a/external-providers/java-external-provider/examples/gradle-multi-project-example/template-server/src/test/java/io/jeffchao/template/server/ServerTest.java b/external-providers/java-external-provider/examples/gradle-multi-project-example/template-server/src/test/java/io/jeffchao/template/server/ServerTest.java
new file mode 100644
index 00000000..6f63c10e
--- /dev/null
+++ b/external-providers/java-external-provider/examples/gradle-multi-project-example/template-server/src/test/java/io/jeffchao/template/server/ServerTest.java
@@ -0,0 +1,16 @@
+package io.jeffchao.template.server;
+
+import org.junit.After;
+import org.junit.Before;
+
+
+public class ServerTest {
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+}
\ No newline at end of file
diff --git a/external-providers/java-external-provider/go.mod b/external-providers/java-external-provider/go.mod
index aecc1677..0df571c0 100644
--- a/external-providers/java-external-provider/go.mod
+++ b/external-providers/java-external-provider/go.mod
@@ -6,14 +6,16 @@ require (
github.com/go-logr/logr v1.4.1
github.com/konveyor/analyzer-lsp v0.4.0-alpha.1
github.com/swaggest/openapi-go v0.2.50
- github.com/vifraa/gopom v1.0.0
go.lsp.dev/uri v0.3.0
go.opentelemetry.io/otel v1.11.2
google.golang.org/grpc v1.62.1 // indirect
gopkg.in/yaml.v2 v2.4.0
)
-require github.com/sirupsen/logrus v1.9.0
+require (
+ github.com/sirupsen/logrus v1.9.0
+ github.com/vifraa/gopom v1.0.0
+)
require google.golang.org/genproto/googleapis/rpc v0.0.0-20240123012728-ef4313101c80 // indirect
diff --git a/external-providers/java-external-provider/pkg/java_external_provider/dependency.go b/external-providers/java-external-provider/pkg/java_external_provider/dependency.go
index d980e85e..15b061c3 100644
--- a/external-providers/java-external-provider/pkg/java_external_provider/dependency.go
+++ b/external-providers/java-external-provider/pkg/java_external_provider/dependency.go
@@ -4,6 +4,7 @@ import (
"bufio"
"bytes"
"context"
+ "errors"
"fmt"
"io"
"io/fs"
@@ -36,6 +37,21 @@ const (
baseDepKey = "baseDep"
)
+const (
+ maven = "maven"
+ gradle = "gradle"
+)
+
+func (p *javaServiceClient) getBuildTool() string {
+ bf := ""
+ if bf = p.findPom(); bf != "" {
+ return maven
+ } else if bf = p.findGradleBuild(); bf != "" {
+ return gradle
+ }
+ return ""
+}
+
// TODO implement this for real
func (p *javaServiceClient) findPom() string {
var depPath string
@@ -51,10 +67,45 @@ func (p *javaServiceClient) findPom() string {
if err != nil {
return ""
}
+ if _, err := os.Stat(f); errors.Is(err, os.ErrNotExist) {
+ return ""
+ }
return f
}
+func (p *javaServiceClient) findGradleBuild() string {
+ if p.config.Location != "" {
+ path := filepath.Join(p.config.Location, "build.gradle")
+ _, err := os.Stat(path)
+ if err != nil {
+ return ""
+ }
+ f, err := filepath.Abs(path)
+ if err != nil {
+ return ""
+ }
+ return f
+ }
+ return ""
+}
+
func (p *javaServiceClient) GetDependencies(ctx context.Context) (map[uri.URI][]*provider.Dep, error) {
+ if p.getBuildTool() == gradle {
+ p.log.V(2).Info("gradle found - retrieving dependencies")
+ m := map[uri.URI][]*provider.Dep{}
+ deps, err := p.getDependenciesForGradle(ctx)
+ for f, ds := range deps {
+ deps := []*provider.Dep{}
+ for _, dep := range ds {
+ d := dep.Dep
+ deps = append(deps, &d)
+ deps = append(deps, provider.ConvertDagItemsToList(dep.AddedDeps)...)
+ }
+ m[f] = deps
+ }
+ return m, err
+ }
+
p.depsMutex.RLock()
val := p.depsCache
p.depsMutex.RUnlock()
@@ -226,6 +277,17 @@ func pomCoordinate(value *string) string {
}
func (p *javaServiceClient) GetDependenciesDAG(ctx context.Context) (map[uri.URI][]provider.DepDAGItem, error) {
+ switch p.getBuildTool() {
+ case maven:
+ return p.getDependenciesForMaven(ctx)
+ case gradle:
+ return p.getDependenciesForGradle(ctx)
+ default:
+ return nil, fmt.Errorf("no build tool found")
+ }
+}
+
+func (p *javaServiceClient) getDependenciesForMaven(ctx context.Context) (map[uri.URI][]provider.DepDAGItem, error) {
localRepoPath := getMavenLocalRepoPath(p.mvnSettingsFile)
path := p.findPom()
@@ -274,6 +336,170 @@ func (p *javaServiceClient) GetDependenciesDAG(ctx context.Context) (map[uri.URI
return m, nil
}
+// getDependenciesForGradle invokes the Gradle wrapper to get the dependency tree and returns all project dependencies
+func (p *javaServiceClient) getDependenciesForGradle(ctx context.Context) (map[uri.URI][]provider.DepDAGItem, error) {
+ subprojects, err := p.getGradleSubprojects()
+ if err != nil {
+ return nil, err
+ }
+
+ // command syntax: ./gradlew subproject1:dependencies subproject2:dependencies ...
+ args := []string{}
+ if len(subprojects) > 0 {
+ for _, sp := range subprojects {
+ args = append(args, fmt.Sprintf("%s:dependencies", sp))
+ }
+ } else {
+ args = append(args, "dependencies")
+ }
+
+ // get the graph output
+ exe, err := filepath.Abs(filepath.Join(p.config.Location, "gradlew"))
+ if err != nil {
+ return nil, fmt.Errorf("error calculating gradle wrapper path")
+ }
+ if _, err = os.Stat(exe); errors.Is(err, os.ErrNotExist) {
+ return nil, fmt.Errorf("a gradle wrapper must be present in the project")
+ }
+ cmd := exec.Command(exe, args...)
+ cmd.Dir = p.config.Location
+ output, err := cmd.CombinedOutput()
+ if err != nil {
+ return nil, err
+ }
+
+ lines := strings.Split(string(output), "\n")
+ deps := p.parseGradleDependencyOutput(lines)
+
+ // TODO: do we need to separate by submodule somehow?
+
+ path := p.findGradleBuild()
+ file := uri.File(path)
+ m := map[uri.URI][]provider.DepDAGItem{}
+ m[file] = deps
+
+ // TODO: need error?
+ return m, nil
+}
+
+func (p *javaServiceClient) getGradleSubprojects() ([]string, error) {
+ args := []string{
+ "projects",
+ }
+
+ // Ideally we'd want to set this in gradle.properties, or as a -Dorg.gradle.java.home arg,
+ // but it doesn't seem to work in older Gradle versions. This should only affect child processes in any case.
+ err := os.Setenv("JAVA_HOME", os.Getenv("JAVA8_HOME"))
+ if err != nil {
+ return nil, err
+ }
+
+ exe, err := filepath.Abs(filepath.Join(p.config.Location, "gradlew"))
+ if err != nil {
+ return nil, fmt.Errorf("error calculating gradle wrapper path")
+ }
+ if _, err = os.Stat(exe); errors.Is(err, os.ErrNotExist) {
+ return nil, fmt.Errorf("a gradle wrapper must be present in the project")
+ }
+ cmd := exec.Command(exe, args...)
+ cmd.Dir = p.config.Location
+ output, err := cmd.CombinedOutput()
+ if err != nil {
+ return nil, err
+ }
+
+ beginRegex := regexp.MustCompile(`Root project`)
+ endRegex := regexp.MustCompile(`To see a list of`)
+ npRegex := regexp.MustCompile(`No sub-projects`)
+ pRegex := regexp.MustCompile(`.*- Project '(.*)'`)
+
+ subprojects := []string{}
+
+ gather := false
+ lines := strings.Split(string(output), "\n")
+ for _, line := range lines {
+ if npRegex.Find([]byte(line)) != nil {
+ return []string{}, nil
+ }
+ if beginRegex.Find([]byte(line)) != nil {
+ gather = true
+ continue
+ }
+ if gather {
+ if endRegex.Find([]byte(line)) != nil {
+ return subprojects, nil
+ }
+
+ if p := pRegex.FindStringSubmatch(line); p != nil {
+ subprojects = append(subprojects, p[1])
+ }
+ }
+ }
+
+ return subprojects, fmt.Errorf("error parsing gradle dependency output")
+}
+
+// parseGradleDependencyOutput converts the relevant lines from the dependency output into actual dependencies
+// See https://regex101.com/r/9Gp7dW/1 for context
+func (p *javaServiceClient) parseGradleDependencyOutput(lines []string) []provider.DepDAGItem {
+ deps := []provider.DepDAGItem{}
+
+ treeDepRegex := regexp.MustCompile(`^([| ]+)?[+\\]--- (.*)`)
+
+ // map of to
+ // this is so that children can be added to their respective parents
+ lastFoundWithDepth := make(map[int]*provider.DepDAGItem)
+
+ for _, line := range lines {
+ match := treeDepRegex.FindStringSubmatch(line)
+ if match != nil {
+ dep := parseGradleDependencyString(match[2])
+ if reflect.DeepEqual(dep, provider.DepDAGItem{}) { // ignore empty dependency
+ continue
+ } else if match[1] != "" { // transitive dependency
+ dep.Dep.Indirect = true
+ depth := len(match[1]) / 5 // get the level of anidation of the dependency within the tree
+ parent := lastFoundWithDepth[depth-1] // find its parent
+ parent.AddedDeps = append(parent.AddedDeps, dep) // add child to parent
+ lastFoundWithDepth[depth] = &parent.AddedDeps[len(parent.AddedDeps)-1] // update last found with given depth
+ } else { // root level (direct) dependency
+ deps = append(deps, dep) // add root dependency to result list
+ lastFoundWithDepth[0] = &deps[len(deps)-1]
+ continue
+ }
+ }
+ }
+
+ return deps
+}
+
+// parseGradleDependencyString parses the lines of the gradle dependency output, for instance:
+// org.codehaus.groovy:groovy:3.0.21
+// org.codehaus.groovy:groovy:3.+ -> 3.0.21
+// com.codevineyard:hello-world:{strictly 1.0.1} -> 1.0.1
+// :simple-jar (n)
+func parseGradleDependencyString(s string) provider.DepDAGItem {
+ // (*) - dependencies omitted (listed previously)
+ // (n) - Not resolved (configuration is not meant to be resolved)
+ if strings.HasSuffix(s, "(n)") || strings.HasSuffix(s, "(*)") {
+ return provider.DepDAGItem{}
+ }
+
+ depRegex := regexp.MustCompile(`(.+):(.+):((.*) -> )?(.*)`)
+ libRegex := regexp.MustCompile(`:(.*)`)
+
+ dep := provider.Dep{}
+ match := depRegex.FindStringSubmatch(s)
+ if match != nil {
+ dep.Name = match[1] + "." + match[2]
+ dep.Version = match[5]
+ } else if match = libRegex.FindStringSubmatch(s); match != nil {
+ dep.Name = match[1]
+ }
+
+ return provider.DepDAGItem{Dep: dep, AddedDeps: []provider.DepDAGItem{}}
+}
+
// extractSubmoduleTrees creates an array of lines for each submodule tree found in the mvn dependency:tree output
func extractSubmoduleTrees(lines []string) [][]string {
submoduleTrees := [][]string{}
diff --git a/external-providers/java-external-provider/pkg/java_external_provider/dependency_test.go b/external-providers/java-external-provider/pkg/java_external_provider/dependency_test.go
index d605f319..33957093 100644
--- a/external-providers/java-external-provider/pkg/java_external_provider/dependency_test.go
+++ b/external-providers/java-external-provider/pkg/java_external_provider/dependency_test.go
@@ -560,3 +560,238 @@ func Test_parseMavenDepLines(t *testing.T) {
})
}
}
+
+func Test_parseGradleDependencyOutput(t *testing.T) {
+ gradleOutput := `
+Starting a Gradle Daemon, 1 incompatible Daemon could not be reused, use --status for details
+
+> Task :dependencies
+
+------------------------------------------------------------
+Root project
+------------------------------------------------------------
+
+annotationProcessor - Annotation processors and their dependencies for source set 'main'.
+No dependencies
+
+api - API dependencies for source set 'main'. (n)
+No dependencies
+
+apiElements - API elements for main. (n)
+No dependencies
+
+archives - Configuration for archive artifacts. (n)
+No dependencies
+
+compileClasspath - Compile classpath for source set 'main'.
++--- org.codehaus.groovy:groovy:3.+ -> 3.0.21
++--- org.codehaus.groovy:groovy-json:3.+ -> 3.0.21
+| \--- org.codehaus.groovy:groovy:3.0.21
++--- com.codevineyard:hello-world:{strictly 1.0.1} -> 1.0.1
+\--- :simple-jar
+
+testRuntimeOnly - Runtime only dependencies for source set 'test'. (n)
+No dependencies
+
+(*) - dependencies omitted (listed previously)
+
+(n) - Not resolved (configuration is not meant to be resolved)
+
+A web-based, searchable dependency report is available by adding the --scan option.
+
+BUILD SUCCESSFUL in 4s
+1 actionable task: 1 executed
+`
+
+ lines := strings.Split(gradleOutput, "\n")
+
+ p := javaServiceClient{
+ log: testr.New(t),
+ depToLabels: map[string]*depLabelItem{},
+ config: provider.InitConfig{
+ ProviderSpecificConfig: map[string]interface{}{
+ "excludePackages": []string{},
+ },
+ },
+ }
+
+ wantedDeps := []provider.DepDAGItem{
+ {
+ Dep: provider.Dep{
+ Name: "org.codehaus.groovy.groovy",
+ Version: "3.0.21",
+ Indirect: false,
+ },
+ },
+ {
+ Dep: provider.Dep{
+ Name: "org.codehaus.groovy.groovy-json",
+ Version: "3.0.21",
+ Indirect: false,
+ },
+ AddedDeps: []provider.DepDAGItem{
+ {
+ Dep: provider.Dep{
+ Name: "org.codehaus.groovy.groovy",
+ Version: "3.0.21",
+ Indirect: true,
+ },
+ },
+ },
+ },
+ {
+ Dep: provider.Dep{
+ Name: "com.codevineyard.hello-world",
+ Version: "1.0.1",
+ Indirect: false,
+ },
+ },
+ {
+ Dep: provider.Dep{
+ Name: "simple-jar",
+ Indirect: false,
+ },
+ },
+ }
+
+ deps := p.parseGradleDependencyOutput(lines)
+
+ if len(deps) != len(wantedDeps) {
+ t.Errorf("different number of dependencies found")
+ }
+
+ for i := 0; i < len(deps); i++ {
+ dep := deps[i]
+ wantedDep := wantedDeps[i]
+ if dep.Dep.Name != wantedDep.Dep.Name {
+ t.Errorf("wanted name: %s, found name: %s", wantedDep.Dep.Name, dep.Dep.Name)
+ }
+ if dep.Dep.Version != wantedDep.Dep.Version {
+ t.Errorf("wanted version: %s, found version: %s", wantedDep.Dep.Version, dep.Dep.Version)
+ }
+ if len(dep.AddedDeps) != len(wantedDep.AddedDeps) {
+ t.Errorf("wanted %d child deps, found %d for dep %s", len(wantedDep.AddedDeps), len(dep.AddedDeps), dep.Dep.Name)
+ }
+
+ }
+
+}
+
+func Test_parseGradleDependencyOutput_withTwoLevelsOfNesting(t *testing.T) {
+ gradleOutput := `
+Starting a Gradle Daemon, 1 incompatible Daemon could not be reused, use --status for details
+
+> Task :dependencies
+
+------------------------------------------------------------
+Root project
+------------------------------------------------------------
+
+annotationProcessor - Annotation processors and their dependencies for source set 'main'.
+No dependencies
+
+api - API dependencies for source set 'main'. (n)
+No dependencies
+
+apiElements - API elements for main. (n)
+No dependencies
+
+archives - Configuration for archive artifacts. (n)
+No dependencies
+
+compileClasspath - Compile classpath for source set 'main'.
++--- net.sourceforge.pmd:pmd-java:5.6.1
+ +--- net.sourceforge.pmd:pmd-core:5.6.1
+ | \--- com.google.code.gson:gson:2.5
+ \--- net.sourceforge.saxon:saxon:9.1.0.8
++--- org.apache.logging.log4j:log4j-api:2.9.1
+
+testRuntimeOnly - Runtime only dependencies for source set 'test'. (n)
+No dependencies
+
+(*) - dependencies omitted (listed previously)
+
+(n) - Not resolved (configuration is not meant to be resolved)
+
+A web-based, searchable dependency report is available by adding the --scan option.
+
+BUILD SUCCESSFUL in 4s
+1 actionable task: 1 executed
+`
+
+ lines := strings.Split(gradleOutput, "\n")
+
+ p := javaServiceClient{
+ log: testr.New(t),
+ depToLabels: map[string]*depLabelItem{},
+ config: provider.InitConfig{
+ ProviderSpecificConfig: map[string]interface{}{
+ "excludePackages": []string{},
+ },
+ },
+ }
+
+ wantedDeps := []provider.DepDAGItem{
+ {
+ Dep: provider.Dep{
+ Name: "net.sourceforge.pmd.pmd-java",
+ Version: "5.6.1",
+ Indirect: false,
+ },
+ AddedDeps: []provider.DepDAGItem{
+ {
+ Dep: provider.Dep{
+ Name: "net.sourceforge.pmd.pmd-core",
+ Version: "5.6.1",
+ Indirect: true,
+ },
+ AddedDeps: []provider.DepDAGItem{
+ {
+ Dep: provider.Dep{
+ Name: "com.google.code.gson.gson",
+ Version: "2.5",
+ Indirect: true,
+ },
+ },
+ },
+ },
+ {
+ Dep: provider.Dep{
+ Name: "net.sourceforge.saxon.saxon",
+ Version: "9.1.0.8",
+ Indirect: true,
+ },
+ },
+ },
+ },
+ {
+ Dep: provider.Dep{
+ Name: "org.apache.logging.log4j.log4j-api",
+ Version: "2.9.1",
+ Indirect: false,
+ },
+ },
+ }
+
+ deps := p.parseGradleDependencyOutput(lines)
+
+ if len(deps) != len(wantedDeps) {
+ t.Errorf("different number of dependencies found")
+ }
+
+ for i := 0; i < len(deps); i++ {
+ dep := deps[i]
+ wantedDep := wantedDeps[i]
+ if dep.Dep.Name != wantedDep.Dep.Name {
+ t.Errorf("wanted name: %s, found name: %s", wantedDep.Dep.Name, dep.Dep.Name)
+ }
+ if dep.Dep.Version != wantedDep.Dep.Version {
+ t.Errorf("wanted version: %s, found version: %s", wantedDep.Dep.Version, dep.Dep.Version)
+ }
+ if len(dep.AddedDeps) != len(wantedDep.AddedDeps) {
+ t.Errorf("wanted %d child deps, found %d for dep %s", len(wantedDep.AddedDeps), len(dep.AddedDeps), dep.Dep.Name)
+ }
+
+ }
+
+}
diff --git a/external-providers/java-external-provider/pkg/java_external_provider/service_client.go b/external-providers/java-external-provider/pkg/java_external_provider/service_client.go
index 1749b7cb..3f557e11 100644
--- a/external-providers/java-external-provider/pkg/java_external_provider/service_client.go
+++ b/external-providers/java-external-provider/pkg/java_external_provider/service_client.go
@@ -205,6 +205,8 @@ func (p *javaServiceClient) initialization(ctx context.Context) {
params.ExtendedClientCapilities = map[string]interface{}{
"classFileContentsSupport": true,
}
+ // See https://github.com/eclipse-jdtls/eclipse.jdt.ls/blob/1a3dd9323756113bf39cfab82746d57a2fd19474/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/Preferences.java
+ // TODO: what if no wrapper?
params.InitializationOptions = map[string]interface{}{
"bundles": absBundles,
"workspaceFolders": []string{fmt.Sprintf("file://%v", absLocation)},
@@ -221,6 +223,13 @@ func (p *javaServiceClient) initialization(ctx context.Context) {
"maven": map[string]interface{}{
"downloadSources": downloadSources,
},
+ "import": map[string]interface{}{
+ "gradle": map[string]interface{}{
+ "java": map[string]interface{}{
+ "home": "/usr/lib/jvm/java-1.8.0-openjdk",
+ },
+ },
+ },
},
},
}
diff --git a/external-providers/yq-external-provider/go.mod b/external-providers/yq-external-provider/go.mod
index 09b6daa0..4087fa85 100644
--- a/external-providers/yq-external-provider/go.mod
+++ b/external-providers/yq-external-provider/go.mod
@@ -23,7 +23,7 @@ require (
github.com/PaesslerAG/gval v1.2.2 // indirect
github.com/cbroglie/mustache v1.4.0 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
- github.com/golang/protobuf v1.5.2 // indirect
+ github.com/golang/protobuf v1.5.3 // indirect
github.com/hashicorp/go-version v1.6.0 // indirect
github.com/shopspring/decimal v1.3.1 // indirect
go.opentelemetry.io/otel v1.11.2 // indirect
@@ -31,9 +31,9 @@ require (
go.opentelemetry.io/otel/sdk v1.11.2 // indirect
go.opentelemetry.io/otel/trace v1.11.2 // indirect
golang.org/x/mod v0.8.0
- golang.org/x/net v0.17.0 // indirect
- golang.org/x/sys v0.13.0 // indirect
- golang.org/x/text v0.13.0 // indirect
- google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect
+ golang.org/x/net v0.20.0 // indirect
+ golang.org/x/sys v0.16.0 // indirect
+ golang.org/x/text v0.14.0 // indirect
+ google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 // indirect
google.golang.org/protobuf v1.33.0 // indirect
)
diff --git a/external-providers/yq-external-provider/go.sum b/external-providers/yq-external-provider/go.sum
index 7921a4de..e4ba260b 100644
--- a/external-providers/yq-external-provider/go.sum
+++ b/external-providers/yq-external-provider/go.sum
@@ -19,6 +19,7 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
@@ -65,16 +66,21 @@ golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
+golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w=
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
+google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80/go.mod h1:cc8bqMqtv9gMOr0zHg2Vzff5ULhhL2IXP4sbcn32Dro=
google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag=
google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
+google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=