Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Abort Scan button #429

Merged
merged 6 commits into from
Oct 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@ public void update(@NotNull AnActionEvent e) {
return;
}
boolean isScanInProgress = ScanManager.getInstance(project).isScanInProgress();
e.getPresentation().setEnabled(!isScanInProgress);
e.getPresentation().setVisible(!isScanInProgress);
}
}
37 changes: 37 additions & 0 deletions src/main/java/com/jfrog/ide/idea/actions/StopLocalScanAction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.jfrog.ide.idea.actions;

import com.intellij.openapi.actionSystem.ActionUpdateThread;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.project.Project;
import com.jfrog.ide.idea.scan.ScanManager;
import org.jetbrains.annotations.NotNull;

/**
* Created by tala on 10/10/23.
*/
public class StopLocalScanAction extends AnAction {
@Override
public @NotNull ActionUpdateThread getActionUpdateThread() {
return ActionUpdateThread.BGT;
}

@Override
public void actionPerformed(AnActionEvent e) {
Project project = e.getProject();
if (project == null) {
return;
}
ScanManager.getInstance(project).stopScan();
}

@Override
public void update(@NotNull AnActionEvent e) {
Project project = e.getProject();
if (project == null) {
return;
}
boolean isScanInProgress = ScanManager.getInstance(project).isScanInProgress();
e.getPresentation().setVisible(isScanInProgress);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
public interface ApplicationEvents {
// Scan started
Topic<ApplicationEvents> ON_SCAN_LOCAL_STARTED = Topic.create("Local scan started", ApplicationEvents.class);
Topic<ApplicationEvents> ON_SCAN_LOCAL_CANCELED = Topic.create("Local scan canceled", ApplicationEvents.class);
Topic<ApplicationEvents> ON_SCAN_CI_STARTED = Topic.create("CI scan started", ApplicationEvents.class);

// Configuration changed
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/jfrog/ide/idea/scan/ScanBinaryExecutor.java
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ protected List<JFrogSecurityWarning> execute(ScanConfig.Builder inputFileBuilder
CommandResults commandResults = commandExecutor.exeCommand(binaryTargetPath.toFile().getParentFile(), args,
null, new NullLog(), MAX_EXECUTION_MINUTES, TimeUnit.MINUTES);

checkCanceled.run();

if (commandResults.isOk()) {
log.debug(commandResults.getRes());
return parseOutputSarif(outputFilePath);
Expand Down
28 changes: 17 additions & 11 deletions src/main/java/com/jfrog/ide/idea/scan/ScanManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import static com.jfrog.ide.common.log.Utils.logError;
import static com.jfrog.ide.common.utils.XrayConnectionUtils.createXrayClientBuilder;
Expand All @@ -37,6 +36,8 @@ public class ScanManager {
private final ScannerFactory factory;
private final SourceCodeScannerManager sourceCodeScannerManager;
private Map<Integer, ScannerBase> scanners = Maps.newHashMap();
private ExecutorService executor;


private ScanManager(@NotNull Project project) {
this.project = project;
Expand Down Expand Up @@ -83,9 +84,8 @@ public void startScan() {
project.getMessageBus().syncPublisher(ApplicationEvents.ON_SCAN_LOCAL_STARTED).update();
LocalComponentsTree componentsTree = LocalComponentsTree.getInstance(project);
componentsTree.setScanningEmptyText();
AtomicBoolean isScanCompleted = new AtomicBoolean(false);
Thread currScanThread = new Thread(() -> {
ExecutorService executor = Executors.newFixedThreadPool(3);
executor = Executors.newFixedThreadPool(3);
try {
// Source code scanners
sourceCodeScannerManager.asyncScanAndUpdateResults(executor, Logger.getInstance());
Expand All @@ -101,28 +101,34 @@ public void startScan() {
logError(Logger.getInstance(), "Scan timeout of " + SCAN_TIMEOUT_MINUTES + " minutes elapsed. The scan is being canceled.", true);
}
// Cache tree only if no errors occurred during scan.
if (scanners.values().stream().anyMatch(ScannerBase::isScanInterrupted)) {
if (scanners.values().stream().anyMatch(ScannerBase::isScanErrorOccurred)) {
componentsTree.deleteCachedTree();
componentsTree.setScanErrorEmptyText();
} else if (scanners.values().stream().anyMatch(ScannerBase::isScanCanceled)) {
project.getMessageBus().syncPublisher(ApplicationEvents.ON_SCAN_LOCAL_CANCELED).update();
} else {
isScanCompleted.set(true);
componentsTree.cacheTree();
componentsTree.setNoIssuesEmptyText();
}
} catch (JFrogInactiveEnvironmentException e) {
handleJfrogInactiveEnvironment(e.getRedirectUrl());
componentsTree.setScanErrorEmptyText();
} catch (IOException | RuntimeException | InterruptedException e) {
logError(Logger.getInstance(), ExceptionUtils.getRootCauseMessage(e), e, true);
componentsTree.setScanErrorEmptyText();
} finally {
executor.shutdownNow();
if (isScanCompleted.get()) {
componentsTree.setNoIssuesEmptyText();
} else {
componentsTree.setScanErrorEmptyText();
}
}
});
currScanThread.start();
}

public void stopScan() {
executor.shutdown();
scanners.values().forEach(ScannerBase::stopScan);
sourceCodeScannerManager.stopScan();
}

/**
* Handle inactive JFrog platform (free-tier) by displaying a clear warning message and a reactivation link.
*
Expand All @@ -141,7 +147,7 @@ public void refreshScanners(ScanLogic scanLogic, @Nullable ExecutorService execu
}

public boolean isScanInProgress() {
return scanners.values().stream().anyMatch(ScannerBase::isScanInProgress);
return scanners.values().stream().anyMatch(ScannerBase::isScanInProgress) || sourceCodeScannerManager.isScanInProgress();
}

/**
Expand Down
33 changes: 25 additions & 8 deletions src/main/java/com/jfrog/ide/idea/scan/ScannerBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import static com.jfrog.ide.common.log.Utils.logError;
Expand All @@ -70,7 +69,9 @@ public abstract class ScannerBase {
private final Log log;
// Lock to prevent multiple simultaneous scans
private final AtomicBoolean scanInProgress = new AtomicBoolean(false);
private final AtomicBoolean scanInterrupted = new AtomicBoolean(false);
private final AtomicBoolean scanError = new AtomicBoolean(false);
private final AtomicBoolean scanCanceled = new AtomicBoolean(false);

private ScanLogic scanLogic;
protected Project project;
protected SourceCodeScannerManager sourceCodeScannerManager;
Expand Down Expand Up @@ -124,7 +125,8 @@ void setScanLogic(ScanLogic logic) {
*
* @return the Inspection tool corresponding to the scan-manager type.
*/
protected @Nullable abstract AbstractInspection getInspectionTool();
@Nullable
protected abstract AbstractInspection getInspectionTool();

protected void sendUsageReport() {
ApplicationManager.getApplication().invokeLater(() -> Utils.sendUsageReport(getPackageManagerType().getName() + "-deps"));
Expand All @@ -144,11 +146,13 @@ private void scanAndUpdate(ProgressIndicator indicator) {
// Building dependency tree
indicator.setText("1/3: Building dependency tree");
DepTree depTree = buildTree();
checkCanceled();

// Sending the dependency tree to Xray for scanning
indicator.setText("2/3: Xray scanning project dependencies");
log.debug("Start scan for '" + basePath + "'.");
Map<String, DependencyNode> results = scanLogic.scanArtifacts(depTree, serverConfig, indicator, prefix, this::checkCanceled);
checkCanceled();

indicator.setText("3/3: Finalizing");
if (results == null || results.isEmpty()) {
Expand All @@ -168,9 +172,9 @@ private void scanAndUpdate(ProgressIndicator indicator) {

} catch (ProcessCanceledException e) {
log.info("Xray scan was canceled");
scanInterrupted.set(true);
scanCanceled.set(true);
} catch (Exception e) {
scanInterrupted.set(true);
scanError.set(true);
logError(log, "Xray scan failed", e, true);
}
}
Expand Down Expand Up @@ -310,13 +314,22 @@ public void onFinished() {
@Override
public void onThrowable(@NotNull Throwable error) {
log.error(ExceptionUtils.getRootCauseMessage(error));
scanInterrupted.set(true);
scanError.set(true);
}

};
executor.submit(createRunnable(scanAndUpdateTask, latch, progressIndicator, log));
}

/**
* Stop the current scan.
*/
void stopScan() {
if (progressIndicator != null) {
progressIndicator.cancel();
}
}

/**
* Get text to display in the task progress.
*
Expand Down Expand Up @@ -421,8 +434,12 @@ boolean isScanInProgress() {
return this.scanInProgress.get();
}

boolean isScanInterrupted() {
return this.scanInterrupted.get();
boolean isScanErrorOccurred() {
return this.scanError.get();
}

boolean isScanCanceled() {
return this.scanCanceled.get();
}

public String getProjectPath() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,9 @@ public List<FileTreeNode> applicabilityScan(ProgressIndicator indicator, Collect
scanResults.addAll(applicabilityResults);
}
}
} catch (IOException | InterruptedException | NullPointerException e) {
} catch (InterruptedException e) {
logError(Logger.getInstance(), "Scan canceled due to a user request or timeout.", false);
} catch (IOException | NullPointerException e) {
logError(Logger.getInstance(), "Failed to scan source code", e, true);
} finally {
scanInProgress.set(false);
Expand Down Expand Up @@ -151,6 +153,12 @@ public void onThrowable(@NotNull Throwable error) {
executor.submit(createRunnable(sourceCodeScanTask, latch, progressIndicator, log));
}

public void stopScan() {
if (progressIndicator != null) {
progressIndicator.cancel();
}
}

private void sourceCodeScanAndUpdate(ProgressIndicator indicator, Runnable checkCanceled, Logger log) throws IOException {
indicator.setText("Running advanced source code scanning");
JFrogApplicationsConfig projectConfig = parseJFrogApplicationsConfig();
Expand Down Expand Up @@ -313,4 +321,8 @@ private Map<SourceCodeScanType, ScanBinaryExecutor> initScannersCollection() {
scanners.put(SourceCodeScanType.SAST, new SastScannerExecutor(Logger.getInstance(), GlobalSettings.getInstance().getServerConfig()));
return scanners;
}

public boolean isScanInProgress() {
return this.scanInProgress.get();
}
}
11 changes: 10 additions & 1 deletion src/main/java/com/jfrog/ide/idea/ui/JFrogLocalToolWindow.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ public JPanel createActionToolbar() {
DefaultActionGroup actionGroup = new DefaultActionGroup(new CollapseAllAction(componentsTree), new ExpandAllAction(componentsTree),
new GoToSettingsAction(), new Separator(), new ScanTimeLabelAction());
actionGroup.addAction(ActionManager.getInstance().getAction("JFrog.StartLocalScan"), Constraints.FIRST);
actionGroup.addAction(ActionManager.getInstance().getAction("JFrog.StopLocalScan"), Constraints.FIRST);

return createJFrogToolbar(actionGroup);
}

Expand Down Expand Up @@ -124,6 +126,9 @@ public void registerListeners(JComponent browserComponent) {
setLeftPanelContent(compTreeView);
ApplicationManager.getApplication().invokeLater(this::resetViews);
});
projectBusConnection.subscribe(ApplicationEvents.ON_SCAN_LOCAL_CANCELED, (ApplicationEvents) () -> {
ApplicationManager.getApplication().invokeLater(this::initialView);
});
componentsTree.addRightClickListener();
}

Expand All @@ -143,7 +148,7 @@ private void refreshView(boolean reloadCredentials) {
return;
}
if (componentsTree.isCacheEmpty() && !ScanManager.getInstance(project).isScanInProgress()) {
setLeftPanelContent(createReadyEnvView());
initialView();
return;
}
setLeftPanelContent(compTreeView);
Expand Down Expand Up @@ -294,4 +299,8 @@ public void updateUI() {
refreshView(true);
}
}

public void initialView() {
talarian1 marked this conversation as resolved.
Show resolved Hide resolved
setLeftPanelContent(createReadyEnvView());
}
}
9 changes: 7 additions & 2 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,19 @@
<action id="JFrog.FloatingStartLocalScan"
class="com.jfrog.ide.idea.actions.StartLocalScanAction"
text="Trigger Scan"
description="Trigger JFrog Scan"
description="Trigger JFrog scan"
icon="/icons/jfrog_icon.svg"/>
</group>
<action id="JFrog.StartLocalScan"
class="com.jfrog.ide.idea.actions.StartLocalScanAction"
text="Trigger Scan"
description="Trigger JFrog Scan"
description="Trigger JFrog scan"
icon="AllIcons.Actions.Execute"/>
<action id="JFrog.StopLocalScan"
class="com.jfrog.ide.idea.actions.StopLocalScanAction"
text="Stop Scan"
description="Cancel all JFrog scan tasks"
icon="AllIcons.Actions.Suspend"/>
<action id="JFrog.RefreshBuilds"
class="com.jfrog.ide.idea.actions.RefreshBuildsAction"
text="Refresh Builds"
Expand Down
Loading