diff --git a/Jenkinsfile b/Jenkinsfile
index 37a9ad6..46ca90b 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -16,7 +16,7 @@ node('rhel7'){
def isSnapshot = props['projectVersion'].contains('-SNAPSHOT')
def version = isSnapshot?props['projectVersion'].replace('-SNAPSHOT', ".${env.BUILD_NUMBER}"):props['projectVersion'] + ".${env.BUILD_NUMBER}"
- // github user and token are required for consuming the crda-java-api module from GHPR in build-time
+ // github user and token are required for consuming the exhort-java-api module from GHPR in build-time
withCredentials([[$class: 'StringBinding', credentialsId: 'rhdevelopersci-github-token', variable: 'GITHUB_TOKEN']]) {
stage('Build') {
sh "./gradlew assemble -PprojectVersion=${version} -Pgpr.username=rhdevelopers-ci -Pgpr.token=${GITHUB_TOKEN}"
@@ -44,7 +44,7 @@ node('rhel7'){
stage("Publish to Marketplace") {
unstash 'zip'
- // github user and token are required for consuming the crda-java-api module from GHPR in build-time
+ // github user and token are required for consuming the exhort-java-api module from GHPR in build-time
withCredentials([[$class: 'StringBinding', credentialsId: 'rhdevelopersci-github-token', variable: 'GITHUB_TOKEN']]) {
withCredentials([[$class: 'StringBinding', credentialsId: 'JetBrains marketplace token', variable: 'TOKEN']]) {
sh "./gradlew publishPlugin -PjetBrainsToken=${TOKEN} -PprojectVersion=${version} -PjetBrainsChannel=${channel} -Pgpr.username=rhdevelopers-ci -Pgpr.token=${GITHUB_TOKEN}"
diff --git a/build.gradle b/build.gradle
index a048c5d..d591d3e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -29,7 +29,7 @@ targetCompatibility = '11'
intellij {
version = ideaVersion //for a full list of IntelliJ IDEA releases please see https://www.jetbrains.com/intellij-repository/releases
pluginName = 'org.jboss.tools.intellij.analytics'
- plugins = ['com.redhat.devtools.intellij.telemetry:0.0.3.33']
+ plugins = ['com.redhat.devtools.intellij.telemetry:0.0.3.33', "org.jetbrains.idea.maven"]
updateSinceUntilBuild = false
}
@@ -48,19 +48,11 @@ dependencies {
resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
}
- // WATCH OUT - lsp4intellij version 0.95.1 breaks diagnostics for opened files
- implementation 'com.github.ballerina-platform:lsp4intellij:0.95.0'
- constraints {
- implementation('com.google.guava:guava:30.0-jre') {
- because 'version 27.1-jre introduced by lsp4intellij:0.95.0 reports vulnerabilities'
- }
- implementation('com.google.code.gson:gson:2.8.9') {
- because 'version 2.8.2 introduced by lsp4intellij:0.95.0 reports vulnerabilities'
- }
- }
implementation 'org.kohsuke:github-api:1.314'
implementation 'org.apache.commons:commons-compress:1.21'
- implementation 'com.redhat.exhort:exhort-java-api:0.0.1-SNAPSHOT'
+ implementation 'com.redhat.exhort:exhort-java-api:0.0.2-SNAPSHOT'
+ implementation 'com.github.ben-manes.caffeine:caffeine:3.1.8'
+
testImplementation('junit:junit:4.13.1')
}
diff --git a/src/main/java/org/jboss/tools/intellij/analytics/AnalyticsLanguageClient.java b/src/main/java/org/jboss/tools/intellij/analytics/AnalyticsLanguageClient.java
deleted file mode 100644
index 4582ffd..0000000
--- a/src/main/java/org/jboss/tools/intellij/analytics/AnalyticsLanguageClient.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package org.jboss.tools.intellij.analytics;
-
-import com.intellij.notification.Notification;
-import com.intellij.notification.NotificationType;
-import com.intellij.notification.Notifications;
-import com.redhat.devtools.intellij.telemetry.core.service.TelemetryMessageBuilder;
-import com.redhat.devtools.intellij.telemetry.core.service.TelemetryMessageBuilder.ActionMessage;
-import org.eclipse.lsp4j.jsonrpc.services.JsonNotification;
-import org.jetbrains.annotations.NotNull;
-import org.wso2.lsp4intellij.client.ClientContext;
-import org.wso2.lsp4intellij.client.DefaultLanguageClient;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.nio.file.Paths;
-import java.util.Map;
-
-public class AnalyticsLanguageClient extends DefaultLanguageClient {
- public AnalyticsLanguageClient(@NotNull ClientContext context) {
- super(context);
- }
-
- private static String getFilename(Map info) {
- String filename = null;
- String url = (String) info.get("uri");
- if (url != null) {
- try {
- filename = Paths.get(new URI(url)).getFileName().toString();
- } catch (URISyntaxException e) {}
- }
- return filename;
- }
-
- @JsonNotification("caNotification")
- public void caNotify(Object payload) {
- if (payload instanceof Map) {
- Map info = (Map) payload;
- if (info.containsKey("data") && info.containsKey("diagCount")) {
- ActionMessage telemetry = TelemetryService.instance().action("lsp:component_analysis_done");
- String filename = getFilename(info);
- if (filename != null) {
- telemetry.property("filename", filename);
- }
- telemetry.send();
- Notifications.Bus.notify(new Notification("Analytics", "Analytics", (String) info.get("data"), NotificationType.INFORMATION));
- }
- }
- }
-
-}
diff --git a/src/main/java/org/jboss/tools/intellij/analytics/AnalyticsLanguageServerDefinition.java b/src/main/java/org/jboss/tools/intellij/analytics/AnalyticsLanguageServerDefinition.java
deleted file mode 100644
index b6e5cea..0000000
--- a/src/main/java/org/jboss/tools/intellij/analytics/AnalyticsLanguageServerDefinition.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package org.jboss.tools.intellij.analytics;
-
-import com.intellij.openapi.editor.Editor;
-import com.intellij.openapi.editor.event.DocumentListener;
-import org.eclipse.lsp4j.ServerCapabilities;
-import org.eclipse.lsp4j.services.LanguageClient;
-import org.eclipse.lsp4j.services.LanguageServer;
-import org.wso2.lsp4intellij.client.ClientContext;
-import org.wso2.lsp4intellij.client.connection.StreamConnectionProvider;
-import org.wso2.lsp4intellij.client.languageserver.ServerOptions;
-import org.wso2.lsp4intellij.client.languageserver.requestmanager.DefaultRequestManager;
-import org.wso2.lsp4intellij.client.languageserver.requestmanager.RequestManager;
-import org.wso2.lsp4intellij.client.languageserver.serverdefinition.RawCommandServerDefinition;
-import org.wso2.lsp4intellij.client.languageserver.wrapper.LanguageServerWrapper;
-import org.wso2.lsp4intellij.editor.EditorEventManager;
-import org.wso2.lsp4intellij.extensions.LSPExtensionManager;
-import org.wso2.lsp4intellij.listeners.EditorMouseListenerImpl;
-import org.wso2.lsp4intellij.listeners.EditorMouseMotionListenerImpl;
-import org.wso2.lsp4intellij.listeners.LSPCaretListenerImpl;
-
-import java.util.Arrays;
-
-public class AnalyticsLanguageServerDefinition extends RawCommandServerDefinition implements LSPExtensionManager {
- public AnalyticsLanguageServerDefinition(String ext, String[] cmds) {
- super(ext, cmds);
- }
-
- @Override
- public StreamConnectionProvider createConnectionProvider(String workingDir) {
- return new AnalyticsProcessStreamConnectionProvider(Arrays.asList(command), workingDir);
- }
-
- @Override
- public T getExtendedRequestManagerFor(LanguageServerWrapper wrapper, LanguageServer server, LanguageClient client, ServerCapabilities serverCapabilities) {
- return (T) new DefaultRequestManager(wrapper, server, client, serverCapabilities);
- }
-
- @Override
- public T getExtendedEditorEventManagerFor(Editor editor, DocumentListener documentListener, EditorMouseListenerImpl mouseListener, EditorMouseMotionListenerImpl mouseMotionListener, LSPCaretListenerImpl caretListener, RequestManager requestManager, ServerOptions serverOptions, LanguageServerWrapper wrapper) {
- return (T) new EditorEventManager(editor, documentListener, mouseListener, mouseMotionListener, caretListener,
- requestManager, serverOptions, wrapper);
- }
-
- @Override
- public Class extends LanguageServer> getExtendedServerInterface() {
- return LanguageServer.class;
- }
-
- @Override
- public LanguageClient getExtendedClientFor(ClientContext context) {
- return new AnalyticsLanguageClient(context);
- }
-}
diff --git a/src/main/java/org/jboss/tools/intellij/analytics/AnalyticsProcessStreamConnectionProvider.java b/src/main/java/org/jboss/tools/intellij/analytics/AnalyticsProcessStreamConnectionProvider.java
deleted file mode 100644
index ab0c03b..0000000
--- a/src/main/java/org/jboss/tools/intellij/analytics/AnalyticsProcessStreamConnectionProvider.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package org.jboss.tools.intellij.analytics;
-
-import org.wso2.lsp4intellij.client.connection.ProcessStreamConnectionProvider;
-
-import java.io.File;
-import java.util.List;
-
-public class AnalyticsProcessStreamConnectionProvider extends ProcessStreamConnectionProvider {
- public AnalyticsProcessStreamConnectionProvider(List commands, String workingDir) {
- super(createProcessBuilder(commands, workingDir));
- }
-
- protected static ProcessBuilder createProcessBuilder(List commands, String workingDir) {
- ProcessBuilder builder = new ProcessBuilder(commands);
- builder.directory(new File(workingDir));
- builder.redirectError(ProcessBuilder.Redirect.INHERIT);
- builder.environment().put("RECOMMENDER_API_URL", "https://f8a-analytics-2445582058137.production.gw.apicast.io:443/api/v2");
- builder.environment().put("THREE_SCALE_USER_TOKEN", "9e7da76708fe374d8c10fa752e72989f");
- //builder.environment().put("PROVIDE_FULLSTACK_ACTION", "true");
- return builder;
- }
-}
diff --git a/src/main/java/org/jboss/tools/intellij/analytics/GitHubRelease.java b/src/main/java/org/jboss/tools/intellij/analytics/GitHubRelease.java
deleted file mode 100644
index 0f6ff4d..0000000
--- a/src/main/java/org/jboss/tools/intellij/analytics/GitHubRelease.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package org.jboss.tools.intellij.analytics;
-
-import org.kohsuke.github.GitHub;
-import org.kohsuke.github.GHAsset;
-import org.kohsuke.github.GHRepository;
-import org.kohsuke.github.GHRelease;
-import java.io.IOException;
-
-public class GitHubRelease {
- private final GHRepository repo;
-
- public GitHubRelease(final String repository) throws IOException {
- final GitHub github = GitHub.connectAnonymously();
- this.repo = github.getRepository(repository);
- }
-
- public String getLatestRelease() throws IOException {
- return this.repo.getLatestRelease().getTagName();
- }
-
- public String getDownloadUri(final String releaseLabel, final String fileLabel) throws IOException {
- final GHRelease release = this.repo.getReleaseByTagName(releaseLabel);
- final GHAsset asset = release.listAssets()
- .toList()
- .stream()
- .filter(a -> a.getName().equals(fileLabel))
- .findFirst()
- .orElseThrow(() -> new IOException(fileLabel + ": unable to download"));
- return asset.getBrowserDownloadUrl();
- }
-}
diff --git a/src/main/java/org/jboss/tools/intellij/analytics/GitHubReleaseDownloader.java b/src/main/java/org/jboss/tools/intellij/analytics/GitHubReleaseDownloader.java
deleted file mode 100644
index f176049..0000000
--- a/src/main/java/org/jboss/tools/intellij/analytics/GitHubReleaseDownloader.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package org.jboss.tools.intellij.analytics;
-
-import java.io.File;
-import java.io.IOException;
-
-import com.intellij.openapi.progress.ProgressManager;
-import com.intellij.util.io.HttpRequests;
-import com.redhat.devtools.intellij.telemetry.core.service.TelemetryMessageBuilder.ActionMessage;
-import com.intellij.openapi.diagnostic.Logger;
-import org.jboss.tools.intellij.stackanalysis.Cli;
-
-
-public class GitHubReleaseDownloader {
- private static final Logger logger = Logger.getInstance(GitHubReleaseDownloader.class);
- private final String fileName;
- private final ICookie cookies;
- private final GitHubRelease release;
- private final boolean forCli;
- private ICookie.Name cookieName; // Set name according to LSP/CLI calls
-
- public GitHubReleaseDownloader(final String fileName, final ICookie cookies, final String repoName, final boolean forCli) throws IOException {
- this.fileName = fileName;
- this.cookies = cookies;
- this.release = new GitHubRelease(repoName);
- this.forCli=forCli; // False for LSP download, True for CLI
- }
-
- private boolean isNewRelease(final String releaseLabel) {
- if (forCli) {
- this.cookieName = ICookie.Name.CLIVersion;
- } else {
- this.cookieName = ICookie.Name.LSPVersion;
- }
- final String currentVersion = cookies.getValue(cookieName);
- return !releaseLabel.equals(currentVersion);
- }
-
-
- public File download() throws IOException {
- final ActionMessage telemetry;
- final String latestReleaseTag;
- final File dest = new File(Platform.pluginDirectory, fileName);
- String telemetryAction;
- String telemetryProperty;
-
- if (forCli){
- // CLI Release version is pinned to a latest stable version
- // to avoid issues due to ongoing development of CLI
- latestReleaseTag = Cli.current.cliReleaseTag;
-
- // Set telemetry action and property for CLI.
- telemetryAction = "cli:download";
- telemetryProperty = "cliVersion";
- } else {
- // Get latest LSP release version from repo
- latestReleaseTag = this.release.getLatestRelease();
-
- // Set telemetry action and property for LSP.
- telemetryAction = "lsp:download";
- telemetryProperty = "lspVersion";
- }
-
- if (!isNewRelease(latestReleaseTag) && dest.exists()) {
- return dest;
- }
-
- telemetry = TelemetryService.instance().action(telemetryAction)
- .property(telemetryProperty, latestReleaseTag);
-
- try {
- final String url = this.release.getDownloadUri(latestReleaseTag, this.fileName);
- HttpRequests
- .request(url)
- .productNameAsUserAgent()
- .saveToFile(dest, ProgressManager.getGlobalProgressIndicator());
-
- dest.setExecutable(true);
- cookies.setValue(cookieName, latestReleaseTag);
- telemetry.send();
- return dest;
- } catch (IOException e) {
- telemetry.error(e).send();
- logger.warn(e.getLocalizedMessage(), e);
- throw e;
- }
- }
-}
diff --git a/src/main/java/org/jboss/tools/intellij/analytics/ICookie.java b/src/main/java/org/jboss/tools/intellij/analytics/ICookie.java
deleted file mode 100644
index a6fdce8..0000000
--- a/src/main/java/org/jboss/tools/intellij/analytics/ICookie.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package org.jboss.tools.intellij.analytics;
-
-public interface ICookie {
- enum Name {
- LSPVersion,
- CLIVersion
- }
-
- void setValue(Name name, String value);
- String getValue(Name name);
-}
diff --git a/src/main/java/org/jboss/tools/intellij/analytics/Platform.java b/src/main/java/org/jboss/tools/intellij/analytics/Platform.java
deleted file mode 100644
index f5285ee..0000000
--- a/src/main/java/org/jboss/tools/intellij/analytics/Platform.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package org.jboss.tools.intellij.analytics;
-
-import com.intellij.ide.plugins.PluginManagerCore;
-import com.intellij.openapi.extensions.PluginId;
-import com.intellij.openapi.util.SystemInfo;
-
-import java.util.Arrays;
-import java.util.List;
-
-public class Platform {
- //Set Plugin location in host machine. Location will be used as download location.
- public static final String pluginDirectory = PluginManagerCore.getPlugin(
- PluginId.getId("org.jboss.tools.intellij.analytics")).getPluginPath().toAbsolutePath().toString();
-
- // Set LSP and CLI tarballs to be downloaded, CLI version is pinned to last stable version instead of latest.
- private static final Platform WINDOWS = new Platform("analytics-lsp-win.exe", "crda_0.2.5_Windows_64bit.tar.gz");
- private static final Platform LINUX = new Platform("analytics-lsp-linux", "crda_0.2.5_Linux_64bit.tar.gz");
- private static final Platform MACOS = new Platform("analytics-lsp-macos", "crda_0.2.5_macOS_64bit.tar.gz");
-
- public String lspBundleName;
- public String cliTarBallName;
- private Platform(String lspBundleName, String cliTarBallName) {
- this.lspBundleName = lspBundleName;
- this.cliTarBallName = cliTarBallName;
- }
-
- private static Platform detect() {
- if (SystemInfo.isLinux)
- return LINUX;
- if (SystemInfo.isWindows)
- return WINDOWS;
- if (SystemInfo.isMac)
- return MACOS;
- throw new PlatformDetectionException(SystemInfo.OS_NAME + " is not supported");
- }
-
- public static final Platform current = detect();
-
- // Set supported file names
- public static final List supportedManifestFiles = Arrays.asList("pom.xml",
- "package.json", "go.mod", "requirements.txt", "requirements-dev.txt");
-}
diff --git a/src/main/java/org/jboss/tools/intellij/analytics/PlatformDetectionException.java b/src/main/java/org/jboss/tools/intellij/analytics/PlatformDetectionException.java
deleted file mode 100644
index f184f50..0000000
--- a/src/main/java/org/jboss/tools/intellij/analytics/PlatformDetectionException.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package org.jboss.tools.intellij.analytics;
-
-public class PlatformDetectionException extends RuntimeException {
- public PlatformDetectionException(String ex) {
- super(ex);
- }
-}
diff --git a/src/main/java/org/jboss/tools/intellij/analytics/PreloadLanguageServer.java b/src/main/java/org/jboss/tools/intellij/analytics/PreloadLanguageServer.java
deleted file mode 100644
index a72a92d..0000000
--- a/src/main/java/org/jboss/tools/intellij/analytics/PreloadLanguageServer.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package org.jboss.tools.intellij.analytics;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.List;
-
-import com.intellij.ide.AppLifecycleListener;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.components.ServiceManager;
-import org.jetbrains.annotations.NotNull;
-import org.wso2.lsp4intellij.IntellijLanguageClient;
-
-public final class PreloadLanguageServer implements AppLifecycleListener {
- private static final Logger log = Logger.getInstance(PreloadLanguageServer.class);
- private final ICookie cookies = ServiceManager.getService(Settings.class);
-
- private void attachLanguageClient(final File cliFile) {
- final String[] cmds = {cliFile.toString(), "--stdio"};
- ApplicationManager.getApplication().invokeAndWait(() -> {
- Platform.supportedManifestFiles.stream().map(s -> s.substring(s.lastIndexOf('.') + 1)).distinct().forEach(ext -> {
- AnalyticsLanguageServerDefinition serverDefinition = new AnalyticsLanguageServerDefinition(ext, cmds);
- IntellijLanguageClient.addServerDefinition(serverDefinition);
- IntellijLanguageClient.addExtensionManager(ext, serverDefinition);}
- );
- });
- log.warn(String.format("lsp registration done %s", cliFile));
- }
-
- @Override
- public void appFrameCreated(@NotNull List commandLineArgs) {
- log.info("lsp preload called");
- ApplicationManager.getApplication().executeOnPooledThread(() -> {
- try {
- final String devUrl = System.getenv("ANALYTICS_LSP_FILE_PATH");
- File lspBundle;
- if (devUrl != null) {
- lspBundle = new File(devUrl);
- } else {
- final GitHubReleaseDownloader bundle = new GitHubReleaseDownloader(
- Platform.current.lspBundleName,
- cookies,
- "fabric8-analytics/fabric8-analytics-lsp-server",
- false);
- lspBundle = bundle.download();
-
- log.info("lsp binary is ready for use.");
- }
- attachLanguageClient(lspBundle);
- } catch(IOException ex) {
- log.warn("lsp download fail", ex);
- }
- });
- }
-}
diff --git a/src/main/java/org/jboss/tools/intellij/analytics/Settings.java b/src/main/java/org/jboss/tools/intellij/analytics/Settings.java
deleted file mode 100644
index 0e83625..0000000
--- a/src/main/java/org/jboss/tools/intellij/analytics/Settings.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package org.jboss.tools.intellij.analytics;
-
-import com.intellij.openapi.components.PersistentStateComponent;
-import com.intellij.openapi.components.RoamingType;
-import com.intellij.openapi.components.State;
-import com.intellij.openapi.components.Service;
-import com.intellij.openapi.components.Storage;
-import com.intellij.util.xmlb.XmlSerializerUtil;
-import com.intellij.util.xmlb.annotations.MapAnnotation;
-
-import java.util.Map;
-import java.util.HashMap;
-
-@Service
-@State(
- name = "Settings",
- storages = {
- @Storage(value = "analytics.settings.xml", roamingType = RoamingType.DISABLED)
-})
-public final class Settings implements ICookie, PersistentStateComponent {
-
- // str representation of ICookie.Name values are key.
- private Map settings = new HashMap();
-
- @Override
- public Settings getState() {
- return this;
- }
-
- @Override
- public void loadState(Settings state) {
- XmlSerializerUtil.copyBean(state, this);
- }
-
- @Override
- public void setValue(ICookie.Name name, String value) {
- this.settings.put(name.name(), value);
- }
-
- @Override
- public String getValue(ICookie.Name name) {
- return this.settings.getOrDefault(name.name(), "");
- }
-
- @MapAnnotation
- public Map getSettings() {
- return settings;
- }
-
- public void setSettings(Map settings) {
- this.settings = settings;
- }
-}
diff --git a/src/main/java/org/jboss/tools/intellij/componentanalysis/CAAnnotator.java b/src/main/java/org/jboss/tools/intellij/componentanalysis/CAAnnotator.java
new file mode 100644
index 0000000..e6ffff2
--- /dev/null
+++ b/src/main/java/org/jboss/tools/intellij/componentanalysis/CAAnnotator.java
@@ -0,0 +1,226 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Red Hat, Inc.
+ * Distributed under license by Red Hat, Inc. All rights reserved.
+ * This program is made available under the terms of the
+ * Eclipse Public License v2.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v20.html
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ ******************************************************************************/
+
+package org.jboss.tools.intellij.componentanalysis;
+
+import com.github.packageurl.PackageURL;
+import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
+import com.intellij.codeInsight.daemon.HighlightDisplayKey;
+import com.intellij.codeInspection.InspectionProfile;
+import com.intellij.codeInspection.InspectionProfileEntry;
+import com.intellij.lang.annotation.AnnotationBuilder;
+import com.intellij.lang.annotation.AnnotationHolder;
+import com.intellij.lang.annotation.ExternalAnnotator;
+import com.intellij.lang.annotation.HighlightSeverity;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.project.Project;
+import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.serviceContainer.AlreadyDisposedException;
+import com.redhat.exhort.api.DependencyReport;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public abstract class CAAnnotator extends ExternalAnnotator> {
+
+ private static final Logger LOG = Logger.getInstance(CAAnnotator.class);
+
+ @Override
+ public @Nullable Info collectInformation(@NotNull PsiFile file) {
+ final InspectionProfileEntry inspection = this.getInspection(file, this.getInspectionShortName());
+ if (inspection == null) {
+ return null;
+ }
+ return new Info(file, this.getDependencies(file));
+ }
+
+ @Override
+ public @Nullable Map doAnnotate(Info info) {
+ if (info != null && info.getFile() != null
+ && info.getDependencies() != null && !info.getDependencies().isEmpty()) {
+ String path = info.getFile().getVirtualFile().getPath();
+ Set dependencies = info.getDependencies().keySet();
+
+ if (CAService.dependenciesModified(path, dependencies)) {
+ Project project = info.getFile().getProject();
+ ApplicationManager.getApplication().executeOnPooledThread(() -> {
+ boolean updated = CAService.performAnalysis(
+ getPackageManager(info.getFile().getName()),
+ info.getFile().getVirtualFile().getName(),
+ info.getFile().getVirtualFile().getPath(),
+ dependencies);
+
+ ApplicationManager.getApplication().runReadAction(() -> {
+ if (updated) {
+ try {
+ DaemonCodeAnalyzer.getInstance(project).restart();
+ } catch (AlreadyDisposedException ex) {
+ LOG.warn("DaemonCodeAnalyzer disposed, invalidate cache: " + path, ex);
+ CAService.deleteReports(path);
+ }
+ }
+ });
+ });
+ }
+
+ Map reports = CAService.getReports(path);
+ return this.matchDependencies(info.getDependencies(), reports);
+ }
+
+ return null;
+ }
+
+ @Override
+ public void apply(@NotNull PsiFile file, Map annotationResult, @NotNull AnnotationHolder holder) {
+ annotationResult.forEach((key, value) -> {
+ if (value != null) {
+ DependencyReport report = value.getReport();
+ List elements = value.getElements();
+ if (report.getIssues() != null && !report.getIssues().isEmpty()
+ && elements != null && !elements.isEmpty()) {
+ if (report.getRef() != null) {
+ String d = getDependencyString(report.getRef().purl());
+ int num = report.getIssues().size();
+ String m = d + ", " + "Known security vulnerabilities: " + num + ", ";
+ String t = "" +
+ "" + d + "
" +
+ "Known security vulnerabilities: " + num + "
";
+
+ if (report.getHighestVulnerability() != null && report.getHighestVulnerability().getSeverity() != null) {
+ String severity = report.getHighestVulnerability().getSeverity().getValue();
+ m += "Highest severity: " + severity + ", ";
+ t += "Highest severity: " + severity + "
";
+ }
+
+ m += "Dependency Analytics Plugin [Powered by Snyk]";
+ t += "Dependency Analytics Plugin [Powered by Snyk]
" +
+ "";
+
+ String message = m;
+ String tooltip = t;
+
+ elements.forEach(e -> {
+ if (e != null) {
+ AnnotationBuilder builder = holder
+ .newAnnotation(HighlightSeverity.ERROR, message)
+ .tooltip(tooltip)
+ .range(e)
+ .withFix(new CAIntentionAction());
+ builder.create();
+ }
+ });
+ }
+ }
+ }
+ });
+ }
+
+ abstract protected String getInspectionShortName();
+
+ abstract protected Map> getDependencies(PsiFile file);
+
+ private Map matchDependencies(Map> dependencies,
+ Map reports) {
+ if (dependencies != null && !dependencies.isEmpty()
+ && reports != null && !reports.isEmpty()) {
+ return dependencies.entrySet()
+ .parallelStream()
+ .filter(e -> reports.containsKey(e.getKey()))
+ .collect(Collectors.toMap(
+ Map.Entry::getKey,
+ e -> new Result(dependencies.get(e.getKey()), reports.get(e.getKey())),
+ (o1, o2) -> o1));
+ }
+ return null;
+ }
+
+ private String getDependencyString(PackageURL purl) {
+ String namespace = purl.getNamespace();
+ String s;
+ if (namespace != null) {
+ s = namespace + ":" + purl.getName();
+ } else {
+ s = purl.getName();
+ }
+ String version = purl.getVersion();
+ if (version != null) {
+ s += "@" + version;
+ }
+ return s;
+ }
+
+ private InspectionProfileEntry getInspection(@NotNull PsiElement context, @NotNull String inspectionShortName) {
+ final HighlightDisplayKey key = HighlightDisplayKey.find(inspectionShortName);
+ if (key == null) {
+ return null;
+ }
+
+ final InspectionProfile profile = InspectionProjectProfileManager.getInstance(context.getProject()).getCurrentProfile();
+ if (!profile.isToolEnabled(key, context)) {
+ return null;
+ }
+ return profile.getUnwrappedTool(inspectionShortName, context);
+ }
+
+ private String getPackageManager(String file) {
+ switch (file) {
+ case "pom.xml":
+ return "maven";
+ case "package.json":
+ return "npm";
+ default:
+ return null;
+ }
+ }
+
+ public static class Info {
+ PsiFile file;
+ Map> dependencies;
+
+ public Info(PsiFile file, Map> dependencies) {
+ this.file = file;
+ this.dependencies = dependencies;
+ }
+
+ public PsiFile getFile() {
+ return file;
+ }
+
+ public Map> getDependencies() {
+ return dependencies;
+ }
+ }
+
+ public static class Result {
+ List elements;
+ DependencyReport report;
+
+ public Result(List elements, DependencyReport report) {
+ this.elements = elements;
+ this.report = report;
+ }
+
+ public List getElements() {
+ return elements;
+ }
+
+ public DependencyReport getReport() {
+ return report;
+ }
+ }
+}
diff --git a/src/main/java/org/jboss/tools/intellij/componentanalysis/CAIntentionAction.java b/src/main/java/org/jboss/tools/intellij/componentanalysis/CAIntentionAction.java
new file mode 100644
index 0000000..87cab55
--- /dev/null
+++ b/src/main/java/org/jboss/tools/intellij/componentanalysis/CAIntentionAction.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Red Hat, Inc.
+ * Distributed under license by Red Hat, Inc. All rights reserved.
+ * This program is made available under the terms of the
+ * Eclipse Public License v2.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v20.html
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ ******************************************************************************/
+
+package org.jboss.tools.intellij.componentanalysis;
+
+import com.google.gson.JsonObject;
+import com.intellij.codeInsight.intention.IntentionAction;
+import com.intellij.codeInspection.util.IntentionFamilyName;
+import com.intellij.codeInspection.util.IntentionName;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.PsiFile;
+import com.intellij.util.IncorrectOperationException;
+import org.jboss.tools.intellij.stackanalysis.SaUtils;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.IOException;
+
+public class CAIntentionAction implements IntentionAction {
+ @Override
+ public @IntentionName @NotNull String getText() {
+ return "Detailed Vulnerability Report";
+ }
+
+ @Override
+ public @NotNull @IntentionFamilyName String getFamilyName() {
+ return "Maven";
+ }
+
+ @Override
+ public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
+ if (file == null) {
+ return false;
+ }
+ return "pom.xml".equals(file.getName()) || "package.json".equals(file.getName());
+ }
+
+ @Override
+ public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
+ SaUtils saUtils = new SaUtils();
+ VirtualFile vf = file.getVirtualFile();
+
+ if (vf != null) {
+ JsonObject manifestDetails = saUtils.performSA(vf);
+ if (manifestDetails != null) {
+ try {
+ saUtils.openCustomEditor(FileEditorManager.getInstance(project), manifestDetails);
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean startInWriteAction() {
+ return false;
+ }
+}
diff --git a/src/main/java/org/jboss/tools/intellij/componentanalysis/CAService.java b/src/main/java/org/jboss/tools/intellij/componentanalysis/CAService.java
new file mode 100644
index 0000000..8ffc7c2
--- /dev/null
+++ b/src/main/java/org/jboss/tools/intellij/componentanalysis/CAService.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Red Hat, Inc.
+ * Distributed under license by Red Hat, Inc. All rights reserved.
+ * This program is made available under the terms of the
+ * Eclipse Public License v2.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v20.html
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ ******************************************************************************/
+
+package org.jboss.tools.intellij.componentanalysis;
+
+import com.github.benmanes.caffeine.cache.Cache;
+import com.github.benmanes.caffeine.cache.Caffeine;
+import com.intellij.openapi.components.Service;
+import com.intellij.openapi.components.ServiceManager;
+import com.redhat.exhort.api.AnalysisReport;
+import com.redhat.exhort.api.DependencyReport;
+import org.jboss.tools.intellij.exhort.ApiService;
+
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+@Service(Service.Level.PROJECT)
+public final class CAService {
+
+ public static CAService getInstance() {
+ return ServiceManager.getService(CAService.class);
+ }
+
+ private final Cache> vulnerabilityCache = Caffeine.newBuilder()
+ .maximumSize(100)
+ .build();
+
+ private final Cache> dependencyCache = Caffeine.newBuilder()
+ .expireAfterWrite(25, TimeUnit.SECONDS)
+ .maximumSize(100)
+ .build();
+
+ public static Map getReports(String filePath) {
+ return Collections.unmodifiableMap(getInstance().vulnerabilityCache.get(filePath, p -> Collections.emptyMap()));
+ }
+
+ public static void deleteReports(String filePath) {
+ getInstance().vulnerabilityCache.invalidate(filePath);
+ }
+
+ public static boolean dependenciesModified(String filePath, Set dependencies) {
+ return !dependencies.equals(getInstance().dependencyCache.get(filePath, p -> Collections.emptySet()));
+ }
+
+ public static boolean performAnalysis(String packageManager,
+ String fileName,
+ String filePath,
+ Set dependencies) {
+ if (dependenciesModified(filePath, dependencies)) {
+ ApiService apiService = ServiceManager.getService(ApiService.class);
+ AnalysisReport report = apiService.getComponentAnalysis(packageManager, fileName, filePath);
+ if (report == null) {
+ throw new RuntimeException("Failed to perform component analysis, result is invalid.");
+ }
+ if (report.getDependencies() != null) {
+ // Avoid comparing the version of dependency
+ Map dependencyMap = Collections.unmodifiableMap(
+ dependencies
+ .parallelStream()
+ .collect(Collectors.toMap(
+ Function.identity(),
+ d -> new Dependency(d, false),
+ (o1, o2) -> o1
+ ))
+ );
+
+ Map reportMap = Collections.unmodifiableMap(
+ report.getDependencies()
+ .parallelStream()
+ .filter(r -> Objects.nonNull(r.getRef()))
+ .collect(Collectors.toMap(
+ r -> new Dependency(r.getRef().purl(), false),
+ Function.identity(),
+ (o1, o2) -> o1
+ ))
+ );
+
+ Map resultMap = Collections.unmodifiableMap(
+ dependencyMap.entrySet()
+ .parallelStream()
+ .filter(e -> reportMap.containsKey(e.getValue()))
+ .map(e -> {
+ DependencyReport dp = reportMap.get(e.getValue());
+ return new AbstractMap.SimpleEntry<>(e.getKey(), dp);
+ })
+ .collect(Collectors.toMap(
+ AbstractMap.SimpleEntry::getKey,
+ AbstractMap.SimpleEntry::getValue,
+ (o1, o2) -> o1
+ ))
+ );
+
+ getInstance().vulnerabilityCache.put(filePath, resultMap);
+ } else {
+ getInstance().vulnerabilityCache.invalidate(filePath);
+ }
+
+ getInstance().dependencyCache.put(filePath, dependencies);
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/org/jboss/tools/intellij/componentanalysis/Dependency.java b/src/main/java/org/jboss/tools/intellij/componentanalysis/Dependency.java
new file mode 100644
index 0000000..21bd615
--- /dev/null
+++ b/src/main/java/org/jboss/tools/intellij/componentanalysis/Dependency.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Red Hat, Inc.
+ * Distributed under license by Red Hat, Inc. All rights reserved.
+ * This program is made available under the terms of the
+ * Eclipse Public License v2.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v20.html
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ ******************************************************************************/
+
+package org.jboss.tools.intellij.componentanalysis;
+
+import com.github.packageurl.PackageURL;
+
+import java.util.Objects;
+
+public class Dependency {
+
+ String type;
+ String namespace;
+ String name;
+ String version;
+
+ public Dependency(String type, String namespace, String name, String version) {
+ this.type = type;
+ this.namespace = namespace;
+ this.name = name;
+ this.version = version;
+ }
+
+ public Dependency(Dependency d, boolean version) {
+ this.type = d.type;
+ this.namespace = d.namespace;
+ this.name = d.name;
+ if (version) {
+ this.version = d.version;
+ }
+ }
+
+ public Dependency(PackageURL purl) {
+ this(purl, true);
+ }
+
+ public Dependency(PackageURL purl, boolean version) {
+ this.type = purl.getType();
+ this.namespace = purl.getNamespace();
+ this.name = purl.getName();
+ if (version) {
+ this.version = purl.getVersion();
+ }
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getNamespace() {
+ return namespace;
+ }
+
+ public void setNamespace(String namespace) {
+ this.namespace = namespace;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Dependency that = (Dependency) o;
+ return Objects.equals(type, that.type) && Objects.equals(namespace, that.namespace)
+ && Objects.equals(name, that.name) && Objects.equals(version, that.version);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(type, namespace, name, version);
+ }
+
+ @Override
+ public String toString() {
+ return "Dependency{" +
+ "type='" + type + '\'' +
+ ", namespace='" + namespace + '\'' +
+ ", name='" + name + '\'' +
+ ", version='" + version + '\'' +
+ '}';
+ }
+}
diff --git a/src/main/java/org/jboss/tools/intellij/componentanalysis/maven/MavenCAAnnotator.java b/src/main/java/org/jboss/tools/intellij/componentanalysis/maven/MavenCAAnnotator.java
new file mode 100644
index 0000000..fa112f9
--- /dev/null
+++ b/src/main/java/org/jboss/tools/intellij/componentanalysis/maven/MavenCAAnnotator.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Red Hat, Inc.
+ * Distributed under license by Red Hat, Inc. All rights reserved.
+ * This program is made available under the terms of the
+ * Eclipse Public License v2.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v20.html
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ ******************************************************************************/
+
+package org.jboss.tools.intellij.componentanalysis.maven;
+
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.xml.XmlComment;
+import com.intellij.psi.xml.XmlElement;
+import org.jboss.tools.intellij.componentanalysis.CAAnnotator;
+import org.jboss.tools.intellij.componentanalysis.Dependency;
+import org.jetbrains.idea.maven.dom.MavenDomUtil;
+import org.jetbrains.idea.maven.dom.model.MavenDomDependency;
+import org.jetbrains.idea.maven.dom.model.MavenDomProjectModel;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+public class MavenCAAnnotator extends CAAnnotator {
+
+ @Override
+ protected String getInspectionShortName() {
+ return MavenCAInspection.SHORT_NAME;
+ }
+
+ @Override
+ protected Map> getDependencies(PsiFile file) {
+ MavenDomProjectModel projectModel = MavenDomUtil.getMavenDomModel(file, MavenDomProjectModel.class);
+ if (projectModel != null) {
+ List dependencies = projectModel.getDependencies().getDependencies();
+ dependencies = dependencies.stream()
+ .filter(d -> {
+ if ("test".equals(d.getScope().getStringValue())) {
+ return false;
+ }
+ XmlElement element = d.getXmlElement();
+ if (element != null) {
+ return Arrays.stream(element.getChildren())
+ .noneMatch(c -> c instanceof XmlComment
+ && "exhortignore".equals(((XmlComment) c).getCommentText().trim()));
+ }
+ return false;
+ }).collect(Collectors.toList());
+
+ Map> resultMap = new HashMap<>();
+ dependencies.forEach(d -> {
+ Dependency dp = new Dependency(
+ "maven",
+ d.getGroupId().getStringValue(),
+ d.getArtifactId().getStringValue(),
+ d.getVersion().getStringValue());
+ resultMap.computeIfAbsent(dp, k -> new LinkedList<>()).add(d.getXmlElement());
+ });
+ return resultMap;
+ }
+ return Collections.emptyMap();
+ }
+}
diff --git a/src/main/java/org/jboss/tools/intellij/componentanalysis/maven/MavenCAInspection.java b/src/main/java/org/jboss/tools/intellij/componentanalysis/maven/MavenCAInspection.java
new file mode 100644
index 0000000..8032f53
--- /dev/null
+++ b/src/main/java/org/jboss/tools/intellij/componentanalysis/maven/MavenCAInspection.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Red Hat, Inc.
+ * Distributed under license by Red Hat, Inc. All rights reserved.
+ * This program is made available under the terms of the
+ * Eclipse Public License v2.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v20.html
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ ******************************************************************************/
+
+package org.jboss.tools.intellij.componentanalysis.maven;
+
+import com.intellij.codeHighlighting.HighlightDisplayLevel;
+import com.intellij.codeInspection.LocalInspectionTool;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.idea.maven.dom.MavenDomBundle;
+
+public class MavenCAInspection extends LocalInspectionTool {
+
+ @NonNls
+ public static final String SHORT_NAME = "MavenCAInspection";
+
+ @Override
+ @NotNull
+ public String getGroupDisplayName() {
+ return MavenDomBundle.message("inspection.group");
+ }
+
+ @Override
+ @NotNull
+ public String getShortName() {
+ return SHORT_NAME;
+ }
+
+ @Override
+ @NotNull
+ public HighlightDisplayLevel getDefaultLevel() {
+ return HighlightDisplayLevel.ERROR;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/jboss/tools/intellij/componentanalysis/maven/POMFileType.java b/src/main/java/org/jboss/tools/intellij/componentanalysis/maven/POMFileType.java
new file mode 100644
index 0000000..b4a64fe
--- /dev/null
+++ b/src/main/java/org/jboss/tools/intellij/componentanalysis/maven/POMFileType.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Red Hat, Inc.
+ * Distributed under license by Red Hat, Inc. All rights reserved.
+ * This program is made available under the terms of the
+ * Eclipse Public License v2.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v20.html
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ ******************************************************************************/
+
+package org.jboss.tools.intellij.componentanalysis.maven;
+
+import com.intellij.lang.xml.XMLLanguage;
+import com.intellij.openapi.fileTypes.LanguageFileType;
+import com.intellij.openapi.util.NlsContexts;
+import com.intellij.openapi.util.NlsSafe;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.Icon;
+
+public class POMFileType extends LanguageFileType {
+
+ POMFileType() {
+ super(XMLLanguage.INSTANCE, true);
+ }
+
+ @Override
+ public @NonNls @NotNull String getName() {
+ return "pom";
+ }
+
+ @Override
+ public @NlsContexts.Label @NotNull String getDescription() {
+ return "Maven project object model";
+ }
+
+ @Override
+ public @NlsSafe @NotNull String getDefaultExtension() {
+ return "xml";
+ }
+
+ @Override
+ public @Nullable Icon getIcon() {
+ return null;
+ }
+}
+
diff --git a/src/main/java/org/jboss/tools/intellij/componentanalysis/npm/NpmCAAnnotator.java b/src/main/java/org/jboss/tools/intellij/componentanalysis/npm/NpmCAAnnotator.java
new file mode 100644
index 0000000..7f403e6
--- /dev/null
+++ b/src/main/java/org/jboss/tools/intellij/componentanalysis/npm/NpmCAAnnotator.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Red Hat, Inc.
+ * Distributed under license by Red Hat, Inc. All rights reserved.
+ * This program is made available under the terms of the
+ * Eclipse Public License v2.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v20.html
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ ******************************************************************************/
+
+package org.jboss.tools.intellij.componentanalysis.npm;
+
+import com.intellij.json.psi.*;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.util.PsiTreeUtil;
+import org.jboss.tools.intellij.componentanalysis.CAAnnotator;
+import org.jboss.tools.intellij.componentanalysis.Dependency;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+public class NpmCAAnnotator extends CAAnnotator {
+
+ @Override
+ protected String getInspectionShortName() {
+ return NpmCAInspection.SHORT_NAME;
+ }
+
+ @Override
+ protected Map> getDependencies(PsiFile file) {
+ if ("package.json".equals(file.getName())) {
+ Set ignored = PsiTreeUtil.findChildrenOfType(file, JsonArray.class)
+ .stream()
+ .filter(c -> {
+ PsiElement p = c.getParent();
+ if (p != null) {
+ return p instanceof JsonProperty && "exhortignore".equals(((JsonProperty) p).getName());
+ }
+ return false;
+ })
+ .flatMap(c -> Arrays.stream(c.getChildren()))
+ .filter(c -> c instanceof JsonStringLiteral)
+ .map(c -> ((JsonStringLiteral) c).getValue())
+ .collect(Collectors.toSet());
+
+ Map> resultMap = new HashMap<>();
+ PsiTreeUtil.findChildrenOfType(file, JsonObject.class)
+ .stream()
+ .filter(c -> {
+ PsiElement p = c.getParent();
+ if (p != null) {
+ return p instanceof JsonProperty && "dependencies".equals(((JsonProperty) p).getName());
+ }
+ return false;
+ })
+ .flatMap(c -> Arrays.stream(c.getChildren()))
+ .filter(c -> c instanceof JsonProperty && !ignored.contains(((JsonProperty) c).getName()))
+ .forEach(c -> {
+ String name = ((JsonProperty) c).getName();
+ String[] parts = name.split("/", 2);
+ String namespace = null;
+ if (parts.length == 2) {
+ namespace = parts[0];
+ name = parts[1];
+ }
+ JsonValue value = ((JsonProperty) c).getValue();
+ String version = value instanceof JsonStringLiteral
+ ? ((JsonStringLiteral) value).getValue()
+ : null;
+ Dependency dp = new Dependency("npm", namespace, name, version);
+ resultMap.computeIfAbsent(dp, k -> new LinkedList<>()).add(c);
+ });
+ return resultMap;
+ }
+ return Collections.emptyMap();
+ }
+}
diff --git a/src/main/java/org/jboss/tools/intellij/componentanalysis/npm/NpmCAInspection.java b/src/main/java/org/jboss/tools/intellij/componentanalysis/npm/NpmCAInspection.java
new file mode 100644
index 0000000..488a307
--- /dev/null
+++ b/src/main/java/org/jboss/tools/intellij/componentanalysis/npm/NpmCAInspection.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Red Hat, Inc.
+ * Distributed under license by Red Hat, Inc. All rights reserved.
+ * This program is made available under the terms of the
+ * Eclipse Public License v2.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v20.html
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ ******************************************************************************/
+
+package org.jboss.tools.intellij.componentanalysis.npm;
+
+import com.intellij.codeHighlighting.HighlightDisplayLevel;
+import com.intellij.codeInspection.LocalInspectionTool;
+import org.jetbrains.annotations.Nls;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+
+public class NpmCAInspection extends LocalInspectionTool {
+
+ @NonNls
+ public static final String SHORT_NAME = "NpmCAInspection";
+
+ @Override
+ @NotNull
+ public String getGroupDisplayName() {
+ return "npm";
+ }
+
+ @Override
+ public @Nls(capitalization = Nls.Capitalization.Sentence) String @NotNull [] getGroupPath() {
+ return new String[]{"Javascript and Typescript"};
+ }
+
+ @Override
+ @NotNull
+ public String getShortName() {
+ return SHORT_NAME;
+ }
+
+ @Override
+ @NotNull
+ public HighlightDisplayLevel getDefaultLevel() {
+ return HighlightDisplayLevel.ERROR;
+ }
+}
diff --git a/src/main/java/org/jboss/tools/intellij/componentanalysis/npm/PackageFileType.java b/src/main/java/org/jboss/tools/intellij/componentanalysis/npm/PackageFileType.java
new file mode 100644
index 0000000..da6731e
--- /dev/null
+++ b/src/main/java/org/jboss/tools/intellij/componentanalysis/npm/PackageFileType.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Red Hat, Inc.
+ * Distributed under license by Red Hat, Inc. All rights reserved.
+ * This program is made available under the terms of the
+ * Eclipse Public License v2.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v20.html
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ ******************************************************************************/
+
+package org.jboss.tools.intellij.componentanalysis.npm;
+
+import com.intellij.json.JsonLanguage;
+import com.intellij.openapi.fileTypes.LanguageFileType;
+import com.intellij.openapi.util.NlsContexts;
+import com.intellij.openapi.util.NlsSafe;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+
+public class PackageFileType extends LanguageFileType {
+ protected PackageFileType() {
+ super(JsonLanguage.INSTANCE, true);
+ }
+
+ @Override
+ public @NonNls @NotNull String getName() {
+ return "package";
+ }
+
+ @Override
+ public @NlsContexts.Label @NotNull String getDescription() {
+ return "Project manifest";
+ }
+
+ @Override
+ public @NlsSafe @NotNull String getDefaultExtension() {
+ return "json";
+ }
+
+ @Override
+ public @Nullable Icon getIcon() {
+ return null;
+ }
+}
diff --git a/src/main/java/org/jboss/tools/intellij/exhort/ApiService.java b/src/main/java/org/jboss/tools/intellij/exhort/ApiService.java
index da79243..54ea9ed 100644
--- a/src/main/java/org/jboss/tools/intellij/exhort/ApiService.java
+++ b/src/main/java/org/jboss/tools/intellij/exhort/ApiService.java
@@ -1,60 +1,101 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Red Hat, Inc.
+ * Distributed under license by Red Hat, Inc. All rights reserved.
+ * This program is made available under the terms of the
+ * Eclipse Public License v2.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v20.html
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ ******************************************************************************/
+
package org.jboss.tools.intellij.exhort;
import com.intellij.openapi.components.Service;
+import com.intellij.openapi.diagnostic.Logger;
import com.redhat.exhort.Api;
+import com.redhat.exhort.api.AnalysisReport;
import com.redhat.exhort.impl.ExhortApi;
-import com.redhat.exhort.tools.Ecosystem;
-import org.jboss.tools.intellij.analytics.TelemetryService;
+import org.jboss.tools.intellij.settings.ApiSettingsState;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
import java.util.concurrent.ExecutionException;
@Service(Service.Level.PROJECT)
public final class ApiService {
- enum TelemetryKeys {
- MANIFEST, ECOSYSTEM, PLATFORM;
- @Override
- public String toString() {
- return this.name().toLowerCase();
+ private static final Logger LOG = Logger.getInstance(ApiService.class);
+
+ enum TelemetryKeys {
+ MANIFEST, ECOSYSTEM, PLATFORM;
+
+ @Override
+ public String toString() {
+ return this.name().toLowerCase();
+ }
}
- }
- private final Api exhortApi;
+ private final Api exhortApi;
- public ApiService() {
- this(new ExhortApi());
- }
+ public ApiService() {
+ this(new ExhortApi());
+ }
- ApiService(Api exhortApi) {
- this.exhortApi = exhortApi;
- }
+ ApiService(Api exhortApi) {
+ this.exhortApi = exhortApi;
+ }
+
+ public Path getStackAnalysis(final String packageManager, final String manifestName, final String manifestPath) {
+ var telemetryMsg = TelemetryService.instance().action("stack-analysis");
+ telemetryMsg.property(TelemetryKeys.ECOSYSTEM.toString(), packageManager);
+ telemetryMsg.property(TelemetryKeys.PLATFORM.toString(), System.getProperty("os.name"));
+ telemetryMsg.property(TelemetryKeys.MANIFEST.toString(), manifestName);
- public Path getStackAnalysis(
- final String packageManager,
- final String manifestName,
- final String manifestPath
- ) throws RuntimeException {
+ try {
+ ApiSettingsState.getInstance().setApiOptions();
+ var htmlContent = exhortApi.stackAnalysisHtml(manifestPath);
+ var tmpFile = Files.createTempFile("exhort_", ".html");
+ Files.write(tmpFile, htmlContent.get());
- var telemetryMsg = TelemetryService.instance().action("stack-analysis");
- telemetryMsg.property(TelemetryKeys.ECOSYSTEM.toString(), packageManager);
- telemetryMsg.property(TelemetryKeys.PLATFORM.toString(), System.getProperty("os.name"));
- telemetryMsg.property(TelemetryKeys.MANIFEST.toString(), manifestName);
+ telemetryMsg.send();
+ return tmpFile;
- try {
- var htmlContent = exhortApi.stackAnalysisHtml(manifestPath);
- var tmpFile = Files.createTempFile("exhort_", ".html");
- Files.write(tmpFile, htmlContent.get());
+ } catch (IOException | InterruptedException | ExecutionException exc) {
+ telemetryMsg.error(exc);
+ telemetryMsg.send();
+ throw new RuntimeException(exc);
+ }
+ }
- telemetryMsg.send();
- return tmpFile;
+ public AnalysisReport getComponentAnalysis(final String packageManager, final String manifestName, final String manifestPath) {
+ var telemetryMsg = TelemetryService.instance().action("component-analysis");
+ telemetryMsg.property(TelemetryKeys.ECOSYSTEM.toString(), packageManager);
+ telemetryMsg.property(TelemetryKeys.PLATFORM.toString(), System.getProperty("os.name"));
+ telemetryMsg.property(TelemetryKeys.MANIFEST.toString(), manifestName);
- } catch (IOException | InterruptedException | ExecutionException exc) {
- telemetryMsg.error(exc);
- telemetryMsg.send();
- throw new RuntimeException(exc);
+ try {
+ ApiSettingsState.getInstance().setApiOptions();
+ CompletableFuture componentReport = exhortApi.componentAnalysis(manifestPath);
+ AnalysisReport report = componentReport.get();
+ telemetryMsg.send();
+ return report;
+ } catch (IOException | InterruptedException | ExecutionException ex) {
+ telemetryMsg.error(ex);
+ telemetryMsg.send();
+ throw new RuntimeException(ex);
+ } catch (IllegalArgumentException ex) {
+ telemetryMsg.error(ex);
+ telemetryMsg.send();
+ LOG.warn("Invalid manifest file submitted.", ex);
+ } catch (CompletionException ex) {
+ telemetryMsg.error(ex);
+ telemetryMsg.send();
+ LOG.warn("Invalid vulnerability report returned.", ex);
+ }
+ return null;
}
- }
}
diff --git a/src/main/java/org/jboss/tools/intellij/analytics/TelemetryService.java b/src/main/java/org/jboss/tools/intellij/exhort/TelemetryService.java
similarity index 95%
rename from src/main/java/org/jboss/tools/intellij/analytics/TelemetryService.java
rename to src/main/java/org/jboss/tools/intellij/exhort/TelemetryService.java
index 079c782..ae635be 100644
--- a/src/main/java/org/jboss/tools/intellij/analytics/TelemetryService.java
+++ b/src/main/java/org/jboss/tools/intellij/exhort/TelemetryService.java
@@ -8,7 +8,7 @@
* Contributors:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
-package org.jboss.tools.intellij.analytics;
+package org.jboss.tools.intellij.exhort;
import com.redhat.devtools.intellij.telemetry.core.service.TelemetryMessageBuilder;
import com.redhat.devtools.intellij.telemetry.core.util.Lazy;
diff --git a/src/main/java/org/jboss/tools/intellij/settings/ApiSettingsComponent.java b/src/main/java/org/jboss/tools/intellij/settings/ApiSettingsComponent.java
new file mode 100644
index 0000000..5727bd5
--- /dev/null
+++ b/src/main/java/org/jboss/tools/intellij/settings/ApiSettingsComponent.java
@@ -0,0 +1,152 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Red Hat, Inc.
+ * Distributed under license by Red Hat, Inc. All rights reserved.
+ * This program is made available under the terms of the
+ * Eclipse Public License v2.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v20.html
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ ******************************************************************************/
+
+package org.jboss.tools.intellij.settings;
+
+import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
+import com.intellij.openapi.ui.TextComponentAccessor;
+import com.intellij.openapi.ui.TextFieldWithBrowseButton;
+import com.intellij.ui.components.JBLabel;
+import com.intellij.ui.components.JBTextField;
+import com.intellij.util.ui.FormBuilder;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+
+public class ApiSettingsComponent {
+
+ private final static String mvnPathLabel = "Maven > Executable: Path"
+ + "
Specifies absolute path of mvn executable.";
+ private final static String javaPathLabel = "Maven > JAVA_HOME: Path"
+ + "
Specifies absolute path of Java installation directory.";
+ private final static String npmPathLabel = "Npm > Executable: Path"
+ + "
Specifies absolute path of npm executable.";
+ private final static String nodePathLabel = "Node > Directory: Path"
+ + "
Specifies absolute path of the directory containing node executable.";
+ private final static String snykTokenLabel = "Red Hat Dependency Analytics: Exhort Snyk Token"
+ + "
Red Hat Dependency Analytics sever authentication token for Snky.";
+
+ private final JPanel mainPanel;
+
+ private final TextFieldWithBrowseButton mvnPathText;
+ private final TextFieldWithBrowseButton javaPathText;
+ private final TextFieldWithBrowseButton npmPathText;
+ private final TextFieldWithBrowseButton nodePathText;
+ private final JBTextField snykTokenText;
+
+ public ApiSettingsComponent() {
+ mvnPathText = new TextFieldWithBrowseButton();
+ mvnPathText.addBrowseFolderListener(
+ null,
+ null,
+ null,
+ FileChooserDescriptorFactory.createSingleFileDescriptor(),
+ TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT
+ );
+
+ javaPathText= new TextFieldWithBrowseButton();
+ javaPathText.addBrowseFolderListener(
+ null,
+ null,
+ null,
+ FileChooserDescriptorFactory.createSingleFolderDescriptor(),
+ TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT
+ );
+
+ npmPathText = new TextFieldWithBrowseButton();
+ npmPathText.addBrowseFolderListener(
+ null,
+ null,
+ null,
+ FileChooserDescriptorFactory.createSingleFileDescriptor(),
+ TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT
+ );
+
+ nodePathText = new TextFieldWithBrowseButton();
+ nodePathText.addBrowseFolderListener(
+ null,
+ null,
+ null,
+ FileChooserDescriptorFactory.createSingleFolderDescriptor(),
+ TextComponentAccessor.TEXT_FIELD_WHOLE_TEXT
+ );
+
+ snykTokenText = new JBTextField();
+
+ mainPanel = FormBuilder.createFormBuilder()
+ .addLabeledComponent(new JBLabel(mvnPathLabel), mvnPathText, 1, true)
+ .addVerticalGap(10)
+ .addLabeledComponent(new JBLabel(javaPathLabel), javaPathText, 1, true)
+ .addSeparator(10)
+ .addVerticalGap(10)
+ .addLabeledComponent(new JBLabel(npmPathLabel), npmPathText, 1, true)
+ .addVerticalGap(10)
+ .addLabeledComponent(new JBLabel(nodePathLabel), nodePathText, 1, true)
+ .addSeparator(10)
+ .addVerticalGap(10)
+ .addLabeledComponent(new JBLabel(snykTokenLabel), snykTokenText, 1, true)
+ .addComponentFillVertically(new JPanel(), 0)
+ .getPanel();
+ }
+
+ public JPanel getPanel() {
+ return mainPanel;
+ }
+
+ public JComponent getPreferredFocusedComponent() {
+ return mvnPathText;
+ }
+
+ @NotNull
+ public String getMvnPathText() {
+ return mvnPathText.getText();
+ }
+
+ public void setMvnPathText(@NotNull String text) {
+ mvnPathText.setText(text);
+ }
+
+ @NotNull
+ public String getJavaPathText() {
+ return javaPathText.getText();
+ }
+
+ public void setJavaPathText(@NotNull String text) {
+ javaPathText.setText(text);
+ }
+
+ @NotNull
+ public String getNpmPathText() {
+ return npmPathText.getText();
+ }
+
+ public void setNpmPathText(@NotNull String text) {
+ npmPathText.setText(text);
+ }
+
+ @NotNull
+ public String getNodePathText() {
+ return nodePathText.getText();
+ }
+
+ public void setNodePathText(@NotNull String text) {
+ nodePathText.setText(text);
+ }
+
+ @NotNull
+ public String getSnykTokenText() {
+ return snykTokenText.getText();
+ }
+
+ public void setSnykTokenText(@NotNull String text) {
+ snykTokenText.setText(text);
+ }
+}
diff --git a/src/main/java/org/jboss/tools/intellij/settings/ApiSettingsConfigurable.java b/src/main/java/org/jboss/tools/intellij/settings/ApiSettingsConfigurable.java
new file mode 100644
index 0000000..a9fdadd
--- /dev/null
+++ b/src/main/java/org/jboss/tools/intellij/settings/ApiSettingsConfigurable.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Red Hat, Inc.
+ * Distributed under license by Red Hat, Inc. All rights reserved.
+ * This program is made available under the terms of the
+ * Eclipse Public License v2.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v20.html
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ ******************************************************************************/
+
+package org.jboss.tools.intellij.settings;
+
+import com.intellij.openapi.util.NlsContexts;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+
+public class ApiSettingsConfigurable implements com.intellij.openapi.options.Configurable {
+
+ private ApiSettingsComponent settingsComponent;
+
+ @Override
+ public @NlsContexts.ConfigurableName String getDisplayName() {
+ return "Red Hat Dependency Analytics";
+ }
+
+ @Override
+ public @Nullable JComponent createComponent() {
+ settingsComponent = new ApiSettingsComponent();
+ return settingsComponent.getPanel();
+ }
+
+ @Override
+ public JComponent getPreferredFocusedComponent() {
+ return settingsComponent.getPreferredFocusedComponent();
+ }
+
+ @Override
+ public boolean isModified() {
+ ApiSettingsState settings = ApiSettingsState.getInstance();
+ boolean modified = !settingsComponent.getMvnPathText().equals(settings.mvnPath);
+ modified |= !settingsComponent.getJavaPathText().equals(settings.javaPath);
+ modified |= !settingsComponent.getNpmPathText().equals(settings.npmPath);
+ modified |= !settingsComponent.getNodePathText().equals(settings.nodePath);
+ modified |= !settingsComponent.getSnykTokenText().equals(settings.snykToken);
+ return modified;
+ }
+
+ @Override
+ public void apply() {
+ ApiSettingsState settings = ApiSettingsState.getInstance();
+ settings.mvnPath = settingsComponent.getMvnPathText();
+ settings.javaPath = settingsComponent.getJavaPathText();
+ settings.npmPath = settingsComponent.getNpmPathText();
+ settings.nodePath = settingsComponent.getNodePathText();
+ settings.snykToken = settingsComponent.getSnykTokenText();
+ }
+
+ @Override
+ public void reset() {
+ ApiSettingsState settings = ApiSettingsState.getInstance();
+ settingsComponent.setMvnPathText(settings.mvnPath);
+ settingsComponent.setJavaPathText(settings.javaPath);
+ settingsComponent.setNpmPathText(settings.npmPath);
+ settingsComponent.setNodePathText(settings.nodePath);
+ settingsComponent.setSnykTokenText(settings.snykToken);
+ }
+
+ @Override
+ public void disposeUIResources() {
+ settingsComponent = null;
+ }
+}
diff --git a/src/main/java/org/jboss/tools/intellij/settings/ApiSettingsState.java b/src/main/java/org/jboss/tools/intellij/settings/ApiSettingsState.java
new file mode 100644
index 0000000..5b84e8c
--- /dev/null
+++ b/src/main/java/org/jboss/tools/intellij/settings/ApiSettingsState.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2023 Red Hat, Inc.
+ * Distributed under license by Red Hat, Inc. All rights reserved.
+ * This program is made available under the terms of the
+ * Eclipse Public License v2.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v20.html
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ ******************************************************************************/
+
+package org.jboss.tools.intellij.settings;
+
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.components.*;
+import com.intellij.util.xmlb.XmlSerializerUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+@State(
+ name = "org.jboss.tools.intellij.settings.ApiSettingsState",
+ storages = @Storage(
+ value = "rhda.exhort.xml",
+ roamingType = RoamingType.DISABLED
+ )
+)
+@Service(Service.Level.APP)
+public final class ApiSettingsState implements PersistentStateComponent {
+
+ public static ApiSettingsState getInstance() {
+ return ApplicationManager.getApplication().getService(ApiSettingsState.class);
+ }
+
+ public String mvnPath;
+ public String javaPath;
+ public String npmPath;
+ public String nodePath;
+ public String snykToken;
+
+ @Override
+ public @Nullable ApiSettingsState getState() {
+ return this;
+ }
+
+ @Override
+ public void loadState(@NotNull ApiSettingsState state) {
+ XmlSerializerUtil.copyBean(state, this);
+ }
+
+ public void setApiOptions() {
+ if (mvnPath != null && !mvnPath.isBlank()) {
+ System.setProperty("EXHORT_MVN_PATH", mvnPath);
+ } else {
+ System.clearProperty("EXHORT_MVN_PATH");
+ }
+ if (javaPath != null && !javaPath.isBlank()) {
+ System.setProperty("JAVA_HOME", javaPath);
+ } else {
+ System.clearProperty("JAVA_HOME");
+ }
+ if (npmPath != null && !npmPath.isBlank()) {
+ System.setProperty("EXHORT_NPM_PATH", npmPath);
+ } else {
+ System.clearProperty("EXHORT_NPM_PATH");
+ }
+ if (nodePath != null && !nodePath.isBlank()) {
+ System.setProperty("NODE_HOME", nodePath);
+ } else {
+ System.clearProperty("NODE_HOME");
+ }
+ if (snykToken != null && !snykToken.isBlank()) {
+ System.setProperty("EXHORT_SNYK_TOKEN", snykToken);
+ } else {
+ System.clearProperty("EXHORT_SNYK_TOKEN");
+ }
+ }
+}
diff --git a/src/main/java/org/jboss/tools/intellij/stackanalysis/Cli.java b/src/main/java/org/jboss/tools/intellij/stackanalysis/Cli.java
deleted file mode 100644
index bf83a05..0000000
--- a/src/main/java/org/jboss/tools/intellij/stackanalysis/Cli.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2021 Red Hat, Inc.
- * Distributed under license by Red Hat, Inc. All rights reserved.
- * This program is made available under the terms of the
- * Eclipse Public License v2.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v20.html
- *
- * Contributors:
- * Red Hat, Inc. - initial API and implementation
- ******************************************************************************/
-package org.jboss.tools.intellij.stackanalysis;
-
-import com.intellij.openapi.util.SystemInfo;
-import org.jboss.tools.intellij.analytics.PlatformDetectionException;
-
-public class Cli {
- public String cliBinaryName;
- public String cliReleaseTag;
-
- // Set name of CLI binary and release tag
- private static final Cli WINDOWS = new Cli("crda.exe", "v0.2.5");
- private static final Cli LINUX = new Cli("crda", "v0.2.5");
- private static final Cli MACOS = new Cli("crda", "v0.2.5");
-
- private Cli(String cliBinaryName, String cliReleaseTag) {
- this.cliBinaryName = cliBinaryName;
- this.cliReleaseTag = cliReleaseTag;
- }
-
- private static Cli detect() {
- if (SystemInfo.isLinux)
- return LINUX;
- if (SystemInfo.isWindows)
- return WINDOWS;
- if (SystemInfo.isMac)
- return MACOS;
- throw new PlatformDetectionException(SystemInfo.OS_NAME + " is not supported");
- }
-
- public static final Cli current = detect();
-}
diff --git a/src/main/java/org/jboss/tools/intellij/stackanalysis/PlatformDetectionException.java b/src/main/java/org/jboss/tools/intellij/stackanalysis/PlatformDetectionException.java
new file mode 100644
index 0000000..bdbd732
--- /dev/null
+++ b/src/main/java/org/jboss/tools/intellij/stackanalysis/PlatformDetectionException.java
@@ -0,0 +1,18 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Red Hat, Inc.
+ * Distributed under license by Red Hat, Inc. All rights reserved.
+ * This program is made available under the terms of the
+ * Eclipse Public License v2.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v20.html
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ ******************************************************************************/
+
+package org.jboss.tools.intellij.stackanalysis;
+
+public class PlatformDetectionException extends RuntimeException {
+ public PlatformDetectionException(String ex) {
+ super(ex);
+ }
+}
diff --git a/src/main/java/org/jboss/tools/intellij/stackanalysis/PreloadCli.java b/src/main/java/org/jboss/tools/intellij/stackanalysis/PreloadCli.java
deleted file mode 100644
index 175c154..0000000
--- a/src/main/java/org/jboss/tools/intellij/stackanalysis/PreloadCli.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2021 Red Hat, Inc.
- * Distributed under license by Red Hat, Inc. All rights reserved.
- * This program is made available under the terms of the
- * Eclipse Public License v2.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v20.html
- *
- * Contributors:
- * Red Hat, Inc. - initial API and implementation
- ******************************************************************************/
-package org.jboss.tools.intellij.stackanalysis;
-
-import com.intellij.ide.AppLifecycleListener;
-import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.components.ServiceManager;
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.progress.ProcessCanceledException;
-import org.jboss.tools.intellij.analytics.GitHubReleaseDownloader;
-import org.jboss.tools.intellij.analytics.ICookie;
-import org.jboss.tools.intellij.analytics.Platform;
-import org.jboss.tools.intellij.analytics.Settings;
-import org.jetbrains.annotations.NotNull;
-
-import java.io.IOException;
-import java.util.List;
-
-public final class PreloadCli implements AppLifecycleListener {
- private static final Logger logger = Logger.getInstance(PreloadCli.class);
- private final ICookie cookies = ServiceManager.getService(Settings.class);
-
- @Override
- public void appFrameCreated(@NotNull List commandLineArgs) {
- logger.info("CLI preload is called");
- ApplicationManager.getApplication().executeOnPooledThread(() -> {
- try {
- // If Env variable is set then use binary file from value given
- final String cliPath = System.getenv("CLI_FILE_PATH");
-
- // If Env variable is not set download binary from GitHub Repo
- if (cliPath == null) {
- final GitHubReleaseDownloader bundle = new GitHubReleaseDownloader(
- Platform.current.cliTarBallName,
- cookies,
- "fabric8-analytics/cli-tools",
- true);
-
- // Download the CLI tarball
- bundle.download();
-
- // Extract tar file to get CLI Binary
- new SaUtils().unTarBundle(Platform.current.cliTarBallName, Cli.current.cliBinaryName);
- logger.info("CLI binary is ready for use.");
- }
-
- // Authenticate user
- new SaProcessExecutor().authenticateUser();
- } catch(IOException | InterruptedException e) {
- logger.warn(e);
- throw new ProcessCanceledException(e);
- }
- });
- }
-}
diff --git a/src/main/java/org/jboss/tools/intellij/stackanalysis/SaAction.java b/src/main/java/org/jboss/tools/intellij/stackanalysis/SaAction.java
index 255644d..fbdd3dd 100644
--- a/src/main/java/org/jboss/tools/intellij/stackanalysis/SaAction.java
+++ b/src/main/java/org/jboss/tools/intellij/stackanalysis/SaAction.java
@@ -12,33 +12,37 @@
import com.google.gson.JsonObject;
-import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.AnAction;
-import com.intellij.openapi.actionSystem.PlatformDataKeys;
+import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
-import com.intellij.openapi.components.ServiceManager;
+import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
-
-import org.jboss.tools.intellij.exhort.ApiService;
-import org.jboss.tools.intellij.analytics.Platform;
import org.jetbrains.annotations.NotNull;
+import java.util.Arrays;
+import java.util.List;
+
public class SaAction extends AnAction {
private static final Logger logger = Logger.getInstance(SaAction.class);
- private final ApiService apiService;
+ private static final List supportedManifestFiles = Arrays.asList(
+ "pom.xml",
+ "package.json"
+// Disable support for go and python
+// , "go.mod", "requirements.txt", "requirements-dev.txt"
+ );
public SaAction() {
- apiService = ServiceManager.getService(ApiService.class);
+
}
/**
* Intellij Plugin Action implementation for triggering SA.
- *
+ *
* Analysis will be performed on the file for which Action is triggered and Report will be shown in editor workspace.
*
* @param event An instance of AnActionEvent.
@@ -49,29 +53,13 @@ public void actionPerformed(@NotNull AnActionEvent event) {
SaUtils saUtils = new SaUtils();
VirtualFile manifestFile = event.getData(PlatformDataKeys.VIRTUAL_FILE);
- // Get SA report for given manifest file.
- String reportLink;
- if ("pom.xml".equals(manifestFile.getName()) || "package.json".equals(manifestFile.getName()) ) {
- reportLink = apiService.getStackAnalysis(
- determinePackageManagerName(manifestFile.getName()),
- manifestFile.getName(),
- manifestFile.getPath()
- ).toUri().toString();
- } else {
- reportLink = saUtils.getReport(manifestFile.getPath()).get("report_link").getAsString();
+ if (manifestFile != null) {
+ JsonObject manifestDetails = saUtils.performSA(manifestFile);
+ if (manifestDetails != null) {
+ // Open custom editor window which will load SA Report in browser attached to it.
+ saUtils.openCustomEditor(FileEditorManager.getInstance(event.getProject()), manifestDetails);
+ }
}
-
- // Manifest file details to be saved in temp file which will be used while opening Report tab
- JsonObject manifestDetails = new JsonObject();
- manifestDetails.addProperty("showParent", false);
- manifestDetails.addProperty("manifestName", manifestFile.getName());
- manifestDetails.addProperty("manifestPath", manifestFile.getPath());
- manifestDetails.addProperty("manifestFileParent", manifestFile.getParent().getName());
- manifestDetails.addProperty("report_link", reportLink);
- manifestDetails.addProperty("manifestNameWithoutExtension", manifestFile.getNameWithoutExtension());
-
- // Open custom editor window which will load SA Report in browser attached to it.
- saUtils.openCustomEditor(FileEditorManager.getInstance(event.getProject()), manifestDetails);
} catch (Exception e) {
logger.warn(e);
Messages.showErrorDialog(event.getProject(),
@@ -80,23 +68,6 @@ public void actionPerformed(@NotNull AnActionEvent event) {
}
}
- private String determinePackageManagerName(String name) {
- String packageManager;
- switch(name)
- {
- case "pom.xml":
- packageManager = "maven";
- break;
- case "package.json":
- packageManager = "npm";
- break;
- default:
- throw new IllegalArgumentException("package manager not implemented");
- }
- return packageManager;
- }
-
-
/**
*
Updates the state of the action, Action is show if this method returns true.
*
@@ -109,7 +80,7 @@ public void update(AnActionEvent event) {
// Check if file where context menu is opened is type of supported extension.
// If yes then show the action for SA in menu
if (psiFile != null) {
- event.getPresentation().setEnabledAndVisible(Platform.supportedManifestFiles
+ event.getPresentation().setEnabledAndVisible(supportedManifestFiles
.contains(psiFile.getName()));
} else {
event.getPresentation().setEnabledAndVisible(false);
diff --git a/src/main/java/org/jboss/tools/intellij/stackanalysis/SaEditorTabTitleProvider.java b/src/main/java/org/jboss/tools/intellij/stackanalysis/SaEditorTabTitleProvider.java
index 3c18997..606214f 100644
--- a/src/main/java/org/jboss/tools/intellij/stackanalysis/SaEditorTabTitleProvider.java
+++ b/src/main/java/org/jboss/tools/intellij/stackanalysis/SaEditorTabTitleProvider.java
@@ -21,7 +21,7 @@
import java.io.IOException;
-public class SaEditorTabTitleProvider implements EditorTabTitleProvider{
+public class SaEditorTabTitleProvider implements EditorTabTitleProvider {
@Override
public @NotNull String getEditorTabTitle(@NotNull Project project, @NotNull VirtualFile file) {
// Check if file opened in Editor is SA report, if Yes then change the title of Custom Editor Tab
@@ -32,9 +32,9 @@ public class SaEditorTabTitleProvider implements EditorTabTitleProvider{
JsonObject manifestDetails = new Gson().fromJson(VfsUtilCore.loadText(file), JsonObject.class);
// If a tab is already opened for same manifest type then add parent directory to distinguish between tabs
if (manifestDetails.get("showParent").getAsBoolean()) {
- tabName = "Dependency Analytics Report for "+manifestDetails.get("manifestFileParent").getAsString()+"/"+manifestDetails.get("manifestName").getAsString();
+ tabName = "Dependency Analytics Report for " + manifestDetails.get("manifestFileParent").getAsString() + "/" + manifestDetails.get("manifestName").getAsString();
} else {
- tabName = "Dependency Analytics Report for "+manifestDetails.get("manifestName").getAsString();
+ tabName = "Dependency Analytics Report for " + manifestDetails.get("manifestName").getAsString();
}
} catch (IOException e) {
tabName = "Dependency Analytics Report";
diff --git a/src/main/java/org/jboss/tools/intellij/stackanalysis/SaProcessExecutor.java b/src/main/java/org/jboss/tools/intellij/stackanalysis/SaProcessExecutor.java
deleted file mode 100644
index f639220..0000000
--- a/src/main/java/org/jboss/tools/intellij/stackanalysis/SaProcessExecutor.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2021 Red Hat, Inc.
- * Distributed under license by Red Hat, Inc. All rights reserved.
- * This program is made available under the terms of the
- * Eclipse Public License v2.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v20.html
- *
- * Contributors:
- * Red Hat, Inc. - initial API and implementation
- ******************************************************************************/
-package org.jboss.tools.intellij.stackanalysis;
-
-import com.intellij.openapi.diagnostic.Logger;
-import com.intellij.openapi.util.SystemInfo;
-import org.jboss.tools.intellij.analytics.Platform;
-import org.jboss.tools.intellij.analytics.PlatformDetectionException;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.util.UUID;
-
-
-public class SaProcessExecutor {
- private static final Logger logger = Logger.getInstance(SaProcessExecutor.class);
- private static final String CLI_CONFIG_FILE_PATH = Paths.get(System.getProperty("user.home"),
- ".crda", "config.yaml").toString();
- private static final String CLI_COMMAND = Platform.pluginDirectory + File.separator + "crda";
-
-
- /**
- * Authenticate a CRDA CLI user.
- *
- * If CLI config file is not present in host machine then user is considered to be new
- * and needs to be authenticated in CRDA Platform.
- *
- * @throws IOException In case of process failure
- * @throws InterruptedException In case of process failure
- */
- public void authenticateUser() throws IOException, InterruptedException {
- // Check if crda config file is already present in system. if not create CLI config file.
- if(!Files.exists(Paths.get(CLI_CONFIG_FILE_PATH))) {
- logger.info("Authenticating user.");
-
- // Run CLI command to set user consent to False for CLI telemetry data collection.
- execute(new String[]{CLI_COMMAND, "config", "set", "consent_telemetry", "false"});
-
- // Run command to authenticate user in CRDA Platform.
- execute(new String[]{CLI_COMMAND, "config", "set", "crda_key", UUID.randomUUID().toString()});
- }
- }
-
-
- /**
- * Perform Stack Analysis on given file.
- *
- * @param filePath Path to target manifest file.
- *
- * @return String object having analysis report.
- *
- * @throws IOException In case of process failure
- * @throws InterruptedException In case of process failure
- */
- public String performStackAnalysis(String filePath) throws IOException, InterruptedException {
- logger.info("Starting Stack Analysis.");
- // Authenticate user, in case file has been deleted after loading the plugin
- authenticateUser();
-
- // Execute CLI command for analysis
- return execute(new String[]{CLI_COMMAND, "analyse", filePath, "-j", "-m", "intellij"});
- }
-
-
- /**
- * Execute CLI commands.
- *
- * @param arguments Arguments for command to be executed.
- *
- * @return String object having result of command.
- *
- * @throws IOException In case of process failure
- * @throws InterruptedException In case of process failure
- */
- public String execute(String[] arguments) throws IOException, InterruptedException {
- // Logic to execute given CLI command and get the result.
- ProcessBuilder processBuilder = new ProcessBuilder(arguments);
-
- // Set CLI binary location as working directory for process.
- processBuilder.directory(new File(Platform.pluginDirectory));
- processBuilder.redirectErrorStream(true);
-
- Process process = processBuilder.start();
- StringBuilder output = new StringBuilder();
-
- try (InputStreamReader inputStreamReader = new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8);
- BufferedReader bufferedReader = new BufferedReader(inputStreamReader)){
-
- String line;
- while ((line = bufferedReader.readLine()) != null) {
- output.append(line).append("\n");
- }
-
- int exitVal = process.waitFor();
-
- // Return data according to exit code of command.
- if (exitVal == 0 || exitVal == 2) {
- return output.toString();
- } else {
- logger.info("Process execution failed for = "+processBuilder.command());
- throw new PlatformDetectionException(output.toString());
- }
- }
- }
-}
diff --git a/src/main/java/org/jboss/tools/intellij/stackanalysis/SaReport.java b/src/main/java/org/jboss/tools/intellij/stackanalysis/SaReport.java
index a0ad6c2..34e3b64 100644
--- a/src/main/java/org/jboss/tools/intellij/stackanalysis/SaReport.java
+++ b/src/main/java/org/jboss/tools/intellij/stackanalysis/SaReport.java
@@ -11,6 +11,7 @@
package org.jboss.tools.intellij.stackanalysis;
import com.intellij.ui.jcef.JBCefBrowser;
+
import javax.swing.JComponent;
diff --git a/src/main/java/org/jboss/tools/intellij/stackanalysis/SaReportEditor.java b/src/main/java/org/jboss/tools/intellij/stackanalysis/SaReportEditor.java
index 7c27f68..3184044 100644
--- a/src/main/java/org/jboss/tools/intellij/stackanalysis/SaReportEditor.java
+++ b/src/main/java/org/jboss/tools/intellij/stackanalysis/SaReportEditor.java
@@ -54,10 +54,13 @@ public SaReportEditor(VirtualFile virtualFile) throws IOException {
}
@Override
- public @NotNull String getName() { return ""; }
+ public @NotNull String getName() {
+ return "";
+ }
@Override
- public void setState(@NotNull FileEditorState state) { }
+ public void setState(@NotNull FileEditorState state) {
+ }
@Override
public boolean isModified() {
@@ -70,16 +73,20 @@ public boolean isValid() {
}
@Override
- public void selectNotify() {}
+ public void selectNotify() {
+ }
@Override
- public void deselectNotify() {}
+ public void deselectNotify() {
+ }
@Override
- public void addPropertyChangeListener(@NotNull PropertyChangeListener listener) {}
+ public void addPropertyChangeListener(@NotNull PropertyChangeListener listener) {
+ }
@Override
- public void removePropertyChangeListener(@NotNull PropertyChangeListener listener) {}
+ public void removePropertyChangeListener(@NotNull PropertyChangeListener listener) {
+ }
@Nullable
@Override
@@ -101,5 +108,7 @@ public void dispose() {
@NotNull
@Override
- public VirtualFile getFile() { return this.virtualFile; }
+ public VirtualFile getFile() {
+ return this.virtualFile;
+ }
}
diff --git a/src/main/java/org/jboss/tools/intellij/stackanalysis/SaReportEditorProvider.java b/src/main/java/org/jboss/tools/intellij/stackanalysis/SaReportEditorProvider.java
index 1702ea1..49a46df 100644
--- a/src/main/java/org/jboss/tools/intellij/stackanalysis/SaReportEditorProvider.java
+++ b/src/main/java/org/jboss/tools/intellij/stackanalysis/SaReportEditorProvider.java
@@ -17,7 +17,6 @@
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
-import org.jboss.tools.intellij.analytics.PlatformDetectionException;
import org.jetbrains.annotations.NotNull;
diff --git a/src/main/java/org/jboss/tools/intellij/stackanalysis/SaUtils.java b/src/main/java/org/jboss/tools/intellij/stackanalysis/SaUtils.java
index 2798849..21d56aa 100644
--- a/src/main/java/org/jboss/tools/intellij/stackanalysis/SaUtils.java
+++ b/src/main/java/org/jboss/tools/intellij/stackanalysis/SaUtils.java
@@ -12,15 +12,12 @@
import com.google.gson.Gson;
import com.google.gson.JsonObject;
+import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
-import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
-import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
-import org.apache.commons.compress.utils.IOUtils;
-import org.jboss.tools.intellij.analytics.Platform;
-import org.jboss.tools.intellij.analytics.PlatformDetectionException;
+import org.jboss.tools.intellij.exhort.ApiService;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
@@ -28,36 +25,16 @@
import java.io.OutputStreamWriter;
import java.io.File;
import java.io.Writer;
-import java.io.FileInputStream;
-import java.io.BufferedInputStream;
-import java.util.zip.GZIPInputStream;
public class SaUtils {
- /**
- * Get Stack Analysis Report for given manifest file using CLI.
- *
- * @param filePath Path to target manifest file
- *
- * @return A JSONObject having SA Report.
- *
- * @throws IOException In case of process failure
- * @throws InterruptedException In case of process failure
- */
- public JsonObject getReport(String filePath) throws IOException, InterruptedException {
- // Get the SA report using CLI and return JSON data
- return new Gson().fromJson(new SaProcessExecutor().performStackAnalysis(filePath), JsonObject.class);
- }
-
-
/**
* Open a custom editor window.
*
* The custom editor window will open a file which will have browser attached to it.
*
- * @param instance An instance of FileEditorManager.
+ * @param instance An instance of FileEditorManager.
* @param manifestDetails Manifest file details.
- *
* @throws IOException In case of process failure
*/
public void openCustomEditor(FileEditorManager instance, JsonObject manifestDetails) throws IOException {
@@ -67,7 +44,7 @@ public void openCustomEditor(FileEditorManager instance, JsonObject manifestDeta
manifestDetails = closeCustomEditor(instance, manifestDetails);
// Create a temp file in which is registered with SaReportEditorProvider.
- File reportFile = File.createTempFile("CRDA-", "_"+manifestDetails.get("manifestName").getAsString()+".sa");
+ File reportFile = File.createTempFile("exhort-", "_" + manifestDetails.get("manifestName").getAsString() + ".sa");
//Save the SA Report URL in file, which will be loaded in browser
try (Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(reportFile)))) {
@@ -80,7 +57,7 @@ public void openCustomEditor(FileEditorManager instance, JsonObject manifestDeta
// Refresh the cached file from the physical file system.
// if Virtual file is already opened in editor window from previous run then refresh file from physical file
// else old web page will be shown in editor window.
- if (virtualFile == null){
+ if (virtualFile == null) {
throw new PlatformDetectionException("Dependency Analytics Report file is not created.");
}
virtualFile.refresh(false, true);
@@ -102,20 +79,20 @@ private JsonObject closeCustomEditor(FileEditorManager instance, JsonObject mani
VirtualFile[] openFiles = instance.getOpenFiles();
// iterate through all files and if Report file is open then close it
- for (VirtualFile openFile : openFiles){
+ for (VirtualFile openFile : openFiles) {
// Check if opened file extension is sa, and existing tab manifest file type is same as new (pom.xml, go.mod)
// if not then no need to close any existing tab, just create new tab.
if (openFile.getExtension().equals("sa")
&& openFile.getNameWithoutExtension()
.replaceAll("^.*?_", "")
- .equals(manifestDetails.get("manifestName").getAsString())){
+ .equals(manifestDetails.get("manifestName").getAsString())) {
// If existing tab manifest type is same as new (pom.xml == pom.xml), then check if existing tab ss for same file by comparing the paths
String existingFilePath = new Gson().fromJson(VfsUtilCore.loadText(openFile), JsonObject.class).get("manifestPath").getAsString();
String currentFilePath = manifestDetails.get("manifestPath").getAsString();
// If file path is same then close existing tab
- if (currentFilePath.equals(existingFilePath)){
+ if (currentFilePath.equals(existingFilePath)) {
// Close the Report file in workspace,
// dispose method of SaReportEditor will delete file from filesystem as well.
instance.closeFile(openFile);
@@ -135,37 +112,43 @@ private JsonObject closeCustomEditor(FileEditorManager instance, JsonObject mani
return manifestDetails;
}
+ public JsonObject performSA(VirtualFile manifestFile) {
+ // Get SA report for given manifest file.
+ String reportLink;
+ if ("pom.xml".equals(manifestFile.getName()) || "package.json".equals(manifestFile.getName())) {
+ ApiService apiService = ServiceManager.getService(ApiService.class);
+ reportLink = apiService.getStackAnalysis(
+ determinePackageManagerName(manifestFile.getName()),
+ manifestFile.getName(),
+ manifestFile.getPath()
+ ).toUri().toString();
+
+ // Manifest file details to be saved in temp file which will be used while opening Report tab
+ JsonObject manifestDetails = new JsonObject();
+ manifestDetails.addProperty("showParent", false);
+ manifestDetails.addProperty("manifestName", manifestFile.getName());
+ manifestDetails.addProperty("manifestPath", manifestFile.getPath());
+ manifestDetails.addProperty("manifestFileParent", manifestFile.getParent().getName());
+ manifestDetails.addProperty("report_link", reportLink);
+ manifestDetails.addProperty("manifestNameWithoutExtension", manifestFile.getNameWithoutExtension());
+
+ return manifestDetails;
+ }
+ return null;
+ }
- /**
- * Extract given tar.gz file.
- *
- * @param cliTarBallName Tar file to be extracted.
- * @param cliBinaryName File which need to be extracted from tar
- *
- * @throws IOException In case of process failure
- */
- public void unTarBundle(final String cliTarBallName, final String cliBinaryName) throws IOException {
- // Logic to extract downloaded file into a directory
-
- // Get plugin directory to store extracted data
- String sandBox = Platform.pluginDirectory;
-
- // CLI Binary file
- final File cliBinaryDest = new File(sandBox, cliBinaryName);
-
- try (FileInputStream fileInputStream = new FileInputStream(sandBox + File.separator + cliTarBallName);
- GZIPInputStream gzipInputStream = new GZIPInputStream(new BufferedInputStream(fileInputStream));
- TarArchiveInputStream tarArchiveInputStream = new TarArchiveInputStream(gzipInputStream)) {
-
- TarArchiveEntry tarEntry;
- while ((tarEntry = tarArchiveInputStream.getNextTarEntry()) != null) {
- File outputFile = new File(sandBox + File.separator + tarEntry.getName());
- outputFile.getParentFile().mkdirs();
- try (FileOutputStream fileOutputStream = new FileOutputStream(outputFile)) {
- IOUtils.copy(tarArchiveInputStream, fileOutputStream);
- }
- }
- cliBinaryDest.setExecutable(true);
+ private String determinePackageManagerName(String name) {
+ String packageManager;
+ switch (name) {
+ case "pom.xml":
+ packageManager = "maven";
+ break;
+ case "package.json":
+ packageManager = "npm";
+ break;
+ default:
+ throw new IllegalArgumentException("package manager not implemented");
}
+ return packageManager;
}
}
diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml
index 229d43a..9a15b7d 100644
--- a/src/main/resources/META-INF/plugin.xml
+++ b/src/main/resources/META-INF/plugin.xml
@@ -1,10 +1,10 @@
- org.jboss.tools.intellij.analytics
- Dependency Analytics
- 1.0
- Red-Hat
+ org.jboss.tools.intellij.analytics
+ Dependency Analytics
+ 1.0
+ Red-Hat
-
Overview
@@ -86,7 +86,7 @@
]]>
- 0.6.0
Various dependency bumps.
Various maintenance resolutions.
@@ -117,65 +117,58 @@
0.0.1
Initial release
]]>
-
-
-
-
-
-
- com.intellij.modules.lang
- com.redhat.devtools.intellij.telemetry
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+ com.intellij.modules.lang
+ com.redhat.devtools.intellij.telemetry
+ org.jetbrains.idea.maven
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/inspectionDescriptions/MavenCAInspection.html b/src/main/resources/inspectionDescriptions/MavenCAInspection.html
new file mode 100644
index 0000000..83e9645
--- /dev/null
+++ b/src/main/resources/inspectionDescriptions/MavenCAInspection.html
@@ -0,0 +1,8 @@
+
+
+Reports dependencies vulnerabilities in pom.xml files.
+
+ Powered by Snyk.
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/inspectionDescriptions/NpmCAInspection.html b/src/main/resources/inspectionDescriptions/NpmCAInspection.html
new file mode 100644
index 0000000..80ed0ae
--- /dev/null
+++ b/src/main/resources/inspectionDescriptions/NpmCAInspection.html
@@ -0,0 +1,8 @@
+
+
+Reports dependencies vulnerabilities in package.json files.
+
+ Powered by Snyk.
+
+
+
\ No newline at end of file
diff --git a/src/test/java/org/jboss/tools/intellij/analytics/GitHubCLIReleaseTest.java b/src/test/java/org/jboss/tools/intellij/analytics/GitHubCLIReleaseTest.java
deleted file mode 100644
index adb44e8..0000000
--- a/src/test/java/org/jboss/tools/intellij/analytics/GitHubCLIReleaseTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.jboss.tools.intellij.analytics;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.io.IOException;
-
-import static org.junit.Assert.assertNotNull;
-
-
-public class GitHubCLIReleaseTest {
-
- private GitHubRelease release;
-
- @Before
- public void setupCli() throws IOException {
- final GitHubRelease release = new GitHubRelease("fabric8-analytics/cli-tools");
- assertNotNull(release);
- this.release = release;
- }
-
- @After
- public void tearDown() {
- this.release = null;
- }
-
- @Test
- public void testCliDownloadUri() throws IOException {
- final String uri = this.release.getDownloadUri("v0.2.4", "crda_0.2.4_Windows_64bit.tar.gz");
- assertNotNull(uri);
- }
-
- @Test(expected = IOException.class)
- public void testCliDownloadUriException() throws IOException {
- final String uri = this.release.getDownloadUri("v0.2.4", "bad file name");
- assertNotNull(uri);
- }
-}
diff --git a/src/test/java/org/jboss/tools/intellij/analytics/GitHubReleaseTest.java b/src/test/java/org/jboss/tools/intellij/analytics/GitHubReleaseTest.java
deleted file mode 100644
index a50b969..0000000
--- a/src/test/java/org/jboss/tools/intellij/analytics/GitHubReleaseTest.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package org.jboss.tools.intellij.analytics;
-
-import java.io.IOException;
-
-import org.junit.Test;
-import org.junit.Before;
-import org.junit.After;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-
-public class GitHubReleaseTest {
-
- private GitHubRelease release;
-
- @Before
- public void setup() throws IOException {
- final GitHubRelease release = new GitHubRelease("fabric8-analytics/fabric8-analytics-lsp-server");
- assertNotNull(release);
- this.release = release;
- }
-
- @After
- public void tearDown() {
- this.release = null;
- }
-
- @Test
- public void testLatestDownloadUri() throws IOException {
- final String latestReleaseTag = this.release.getLatestRelease();
- assertNotNull(latestReleaseTag);
-
- final String uri = this.release.getDownloadUri(latestReleaseTag, "analytics-lsp-win.exe");
- assertNotNull(uri);
- }
-
- @Test(expected = IOException.class)
- public void testLatestDownloadUriException() throws IOException {
- final String latestReleaseTag = this.release.getLatestRelease();
- assertNotNull(latestReleaseTag);
-
- final String uri = this.release.getDownloadUri(latestReleaseTag, "bad tag name");
- assertNotNull(uri);
- }
-}