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