diff --git a/.github/scripts/BinariesListUpdates.java b/.github/scripts/BinariesListUpdates.java
new file mode 100644
index 000000000000..462bc7ce1099
--- /dev/null
+++ b/.github/scripts/BinariesListUpdates.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.concurrent.Semaphore;
+import java.util.stream.Stream;
+import org.apache.maven.search.api.Record;
+import org.apache.maven.search.api.SearchRequest;
+import org.apache.maven.search.backend.smo.SmoSearchBackend;
+import org.apache.maven.search.backend.smo.SmoSearchBackendFactory;
+
+import static java.util.FormatProcessor.FMT;
+import static org.apache.maven.search.api.MAVEN.ARTIFACT_ID;
+import static org.apache.maven.search.api.MAVEN.CLASSIFIER;
+import static org.apache.maven.search.api.MAVEN.GROUP_ID;
+import static org.apache.maven.search.api.MAVEN.VERSION;
+import static org.apache.maven.search.api.request.BooleanQuery.and;
+import static org.apache.maven.search.api.request.FieldQuery.fieldQuery;
+
+/**
+ * Scans for binaries-list files and checks if newer versions of the declared dependencies exist.
+ *
+ *
org.apache.maven.indexer:search-backend-smo
must be in classpath.
+ *
+ * @author mbien
+ */
+public class BinariesListUpdates {
+
+ // java --enable-preview --source 22 --class-path "lib/*" BinariesListUpdates.java /path/to/netbeans/project
+ public static void main(String[] args) throws IOException, InterruptedException {
+
+ if (args.length != 1 || Files.notExists(Path.of(args[0]).resolve("README.md"))) {
+ throw new IllegalArgumentException("path to netbeans folder expected");
+ }
+
+ Path path = Path.of(args[0]);
+ try (Stream dependencyFiles = Files.find(path, 10, (p, a) -> p.getFileName().toString().equals("binaries-list"));
+ SmoSearchBackend backend = SmoSearchBackendFactory.createDefault()) {
+ dependencyFiles.sorted().forEach(p -> {
+ try {
+ checkDependencies(p, backend);
+ } catch (IOException | InterruptedException ex) {
+ throw new RuntimeException(ex);
+ }
+ });
+ }
+ }
+
+ private static void checkDependencies(Path path, SmoSearchBackend backend) throws IOException, InterruptedException {
+ System.out.println(path);
+ try (Stream lines = Files.lines(path).parallel()) {
+ // 321C614F85F1DEA6BB08C1817C60D53B7F3552FD org.fusesource.jansi:jansi:2.4.0
+ lines.filter(l -> !l.startsWith("#"))
+ .filter(l -> l.length() > 40 && l.charAt(40) == ' ')
+ .map(l -> l.substring(40+1))
+ .forEach(l -> {
+ String[] comp = l.split("\\:");
+ if (comp.length == 3 || comp.length == 4) {
+ String gid = comp[0].strip();
+ String aid = comp[1].strip();
+ String version = comp[2].strip();
+ String classifier = comp.length == 4 ? comp[3].strip() : null;
+ try {
+ String latest = classifier == null ? queryLatestVersion(backend, gid, aid)
+ : queryLatestVersion(backend, gid, aid, classifier.split("@")[0]);
+ if (!version.equals(latest)) {
+ String gac = STR."\{gid}:\{aid}" + (classifier != null ? ":" + classifier : "");
+ System.out.println(FMT." %-50s\{gac} \{version} -> \{latest}");
+ }
+ } catch (IOException | InterruptedException ex) {
+ throw new RuntimeException(ex);
+ }
+ } else {
+ System.out.println(" skip: '"+l+"'");
+ }
+ });
+ }
+ System.out.println();
+ }
+
+ private static String queryLatestVersion(SmoSearchBackend backend, String gid, String aid) throws IOException, InterruptedException {
+ return queryLatestVersion(backend, new SearchRequest(and(fieldQuery(GROUP_ID, gid), fieldQuery(ARTIFACT_ID, aid))));
+ }
+
+ private static String queryLatestVersion(SmoSearchBackend backend, String gid, String aid, String classifier) throws IOException, InterruptedException {
+ return queryLatestVersion(backend, new SearchRequest(and(fieldQuery(GROUP_ID, gid), fieldQuery(ARTIFACT_ID, aid), fieldQuery(CLASSIFIER, classifier))));
+ }
+
+ // reduce concurrency level if needed
+ private final static Semaphore requests = new Semaphore(4);
+
+ private static String queryLatestVersion(SmoSearchBackend backend, SearchRequest request) throws IOException, InterruptedException {
+ requests.acquire();
+ try {
+ List result = backend.search(request).getPage();
+ return !result.isEmpty() ? result.getFirst().getValue(VERSION) : null;
+ } finally {
+ requests.release();
+ }
+ }
+
+}
diff --git a/.github/workflows/dependency-checks.yml b/.github/workflows/dependency-checks.yml
new file mode 100644
index 000000000000..83bd802f000f
--- /dev/null
+++ b/.github/workflows/dependency-checks.yml
@@ -0,0 +1,64 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+name: NetBeans Dependency Checks
+
+on:
+# pull_request:
+ # Allows you to run this workflow manually from the Actions tab in GitHub UI
+ workflow_dispatch:
+
+# cancel other workflow run in the same head-base group if it exists
+concurrency:
+ group: dep-checker-${{ github.head_ref || github.run_id }}-${{ github.base_ref }}
+ cancel-in-progress: true
+
+defaults:
+ run:
+ shell: bash
+
+jobs:
+
+ base-build:
+ name: Check Dependencies
+ runs-on: ubuntu-latest
+ timeout-minutes: 20
+ steps:
+
+ - name: Set up JDK
+ uses: actions/setup-java@v3
+ with:
+ java-version: '22-ea'
+ distribution: 'zulu'
+
+ - name: Checkout ${{ github.ref }} ( ${{ github.sha }} )
+ uses: actions/checkout@v4
+ with:
+ persist-credentials: false
+ submodules: false
+ show-progress: false
+
+ - name: Check Dependencies
+ run: |
+ mvn -q dependency:get -DgroupId=org.apache.maven.indexer -DartifactId=search-backend-smo -Dversion=7.1.1
+ mvn -q dependency:copy -Dartifact=org.apache.maven.indexer:search-api:7.1.1 -DoutputDirectory=./lib
+ mvn -q dependency:copy -Dartifact=org.apache.maven.indexer:search-backend-smo:7.1.1 -DoutputDirectory=./lib
+ mvn -q dependency:copy -Dartifact=com.google.code.gson:gson:2.10.1 -DoutputDirectory=./lib
+ echo "" >> $GITHUB_STEP_SUMMARY
+ java --enable-preview --source 22 --class-path "lib/*" .github/scripts/BinariesListUpdates.java $GITHUB_WORKSPACE | tee -a $GITHUB_STEP_SUMMARY
+ echo "
" >> $GITHUB_STEP_SUMMARY
+ rm -Rf lib