Skip to content

Commit ef5bde3

Browse files
committed
feat: wip, add support for Delta scans,folderconfig and branch selector
1 parent 05b5e4c commit ef5bde3

7 files changed

Lines changed: 274 additions & 2 deletions

File tree

plugin/src/main/java/io/snyk/eclipse/plugin/views/snyktoolview/ISnykToolView.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import org.eclipse.jface.viewers.TreeViewer;
44

5-
65
/**
76
* This interface captures the externally used methods with the tool window.
87
* Having it, should allow for easier testing of the business logic apart from
@@ -96,5 +95,17 @@ static String getPlural(long count) {
9695

9796
abstract TreeViewer getTreeViewer();
9897

98+
/**
99+
* Hides or shows the Ignore buttons.
100+
*
101+
* @return
102+
*/
99103
abstract void toggleIgnoresButtons();
104+
105+
/**
106+
* Enables the net new issues scans.
107+
*
108+
* @return
109+
*/
110+
abstract void enableDelta();
100111
}

plugin/src/main/java/io/snyk/eclipse/plugin/views/snyktoolview/SnykToolView.java

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
package io.snyk.eclipse.plugin.views.snyktoolview;
22

3+
import java.nio.file.Path;
34
import java.nio.file.Paths;
5+
import java.util.HashMap;
6+
import java.util.List;
7+
import java.util.Map;
48

9+
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
10+
import org.eclipse.core.runtime.preferences.InstanceScope;
511
import org.eclipse.jface.action.IMenuManager;
612
import org.eclipse.jface.action.MenuManager;
713
import org.eclipse.jface.viewers.ISelectionChangedListener;
@@ -13,22 +19,33 @@
1319
import org.eclipse.swt.SWT;
1420
import org.eclipse.swt.browser.Browser;
1521
import org.eclipse.swt.custom.SashForm;
22+
import org.eclipse.swt.events.SelectionAdapter;
23+
import org.eclipse.swt.events.SelectionEvent;
1624
import org.eclipse.swt.layout.FillLayout;
1725
import org.eclipse.swt.layout.GridData;
1826
import org.eclipse.swt.layout.GridLayout;
27+
import org.eclipse.swt.widgets.Button;
28+
import org.eclipse.swt.widgets.Combo;
1929
import org.eclipse.swt.widgets.Composite;
2030
import org.eclipse.swt.widgets.Display;
31+
import org.eclipse.swt.widgets.Event;
32+
import org.eclipse.swt.widgets.Label;
33+
import org.eclipse.swt.widgets.Listener;
2134
import org.eclipse.swt.widgets.Menu;
2235
import org.eclipse.swt.widgets.Tree;
36+
import org.eclipse.swt.widgets.TreeItem;
2337
import org.eclipse.ui.PlatformUI;
2438
import org.eclipse.ui.menus.CommandContributionItem;
2539
import org.eclipse.ui.menus.CommandContributionItemParameter;
2640
import org.eclipse.ui.part.ViewPart;
2741

42+
import com.google.gson.Gson;
43+
2844
import io.snyk.eclipse.plugin.properties.preferences.Preferences;
2945
import io.snyk.eclipse.plugin.utils.ResourceUtils;
3046
import io.snyk.eclipse.plugin.views.snyktoolview.providers.TreeContentProvider;
3147
import io.snyk.eclipse.plugin.views.snyktoolview.providers.TreeLabelProvider;
48+
import io.snyk.languageserver.protocolextension.messageObjects.FolderConfig;
3249

3350
/**
3451
* TODO This view will replace the old SnykView. Move the snyktoolview classes
@@ -47,6 +64,10 @@ public class SnykToolView extends ViewPart implements ISnykToolView {
4764
private TreeViewer treeViewer;
4865
private Browser browser;
4966
private BrowserHandler browserHandler;
67+
private Map<TreeItem, Listener> itemListeners = new HashMap<>();
68+
private final Gson gson = new Gson();
69+
70+
private final static Shell SHELL = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
5071

5172
@Override
5273
public void createPartControl(Composite parent) {
@@ -255,6 +276,123 @@ public void toggleIgnoresButtons() {
255276

256277
}
257278

279+
public void enableDelta() {
280+
TreeItem[] rootItems = getTreeViewer().getTree().getItems();
281+
for (TreeItem item : rootItems) {
282+
ContentRootNode node = (ContentRootNode) item.getData();
283+
String project = node.getText().toString();
284+
String projectPath = node.getPath().toString();
285+
String baseBranch = getBaseBranch(projectPath.toString());
286+
287+
item.setText(String.format("Click to choose base branch for: %s [ current: %s ]", project, baseBranch));
288+
289+
Listener selectionListener = new Listener() {
290+
@Override
291+
public void handleEvent(Event event) {
292+
if (event.item == item) {
293+
showPopup(event.display, item);
294+
}
295+
}
296+
};
297+
298+
// Store the listener in the map
299+
itemListeners.put(item, selectionListener);
300+
301+
// Add the listener to the item's parent
302+
item.getParent().addListener(SWT.Selection, selectionListener);
303+
}
304+
}
305+
306+
private void showPopup(Display display, TreeItem item) {
307+
Shell shell = new Shell(display, SWT.APPLICATION_MODAL | SWT.DIALOG_TRIM);
308+
shell.setText("Choose base branch for net-new issues scanning");
309+
shell.setLayout(new GridLayout(1, false));
310+
311+
if (!(item.getData() instanceof ContentRootNode))
312+
return;
313+
314+
ContentRootNode node = (ContentRootNode) item.getData();
315+
Path project = node.getPath();
316+
317+
Label label = new Label(shell, SWT.NONE);
318+
label.setText("Base Branch for: " + project);
319+
label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
320+
321+
List<String> dropdownItems = getLocalBranches(project.toString());
322+
323+
Combo dropdown = new Combo(shell, SWT.DROP_DOWN);
324+
dropdown.setItems(dropdownItems.toArray(new String[0]));
325+
dropdown.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
326+
327+
Button okButton = new Button(shell, SWT.PUSH);
328+
okButton.setText("OK");
329+
okButton.setLayoutData(new GridData(SWT.END, SWT.CENTER, false, false));
330+
okButton.addSelectionListener(new SelectionAdapter() {
331+
@Override
332+
public void widgetSelected(SelectionEvent e) {
333+
// Handle OK button press
334+
shell.close();
335+
}
336+
});
337+
338+
shell.pack();
339+
shell.open();
340+
341+
while (!shell.isDisposed()) {
342+
if (!display.readAndDispatch()) {
343+
display.sleep();
344+
}
345+
}
346+
}
347+
348+
public List<String> getLocalBranches(String folderPath) {
349+
350+
IEclipsePreferences state = InstanceScope.INSTANCE.getNode("io.snyk.eclipse.plugin");
351+
// Retrieve the JSON string from the preferences state
352+
String json = state.get(folderPath, null);
353+
354+
if (json != null) {
355+
// Deserialize the JSON string back to a FolderConfig object
356+
FolderConfig folderConfig = gson.fromJson(json, FolderConfig.class);
357+
// Return the list of local branches
358+
return folderConfig.getLocalBranches();
359+
}
360+
361+
return List.of(); // Return an empty list if no data is found
362+
}
363+
364+
public String getBaseBranch(String folderPath) {
365+
366+
IEclipsePreferences state = InstanceScope.INSTANCE.getNode("io.snyk.eclipse.plugin");
367+
// Retrieve the JSON string from the preferences state
368+
String json = state.get(folderPath, null);
369+
370+
if (json == null)
371+
return null;
372+
373+
// Deserialize the JSON string back to a FolderConfig object
374+
FolderConfig folderConfig = gson.fromJson(json, FolderConfig.class);
375+
// Return the list of local branches
376+
return folderConfig.getBaseBranch();
377+
378+
}
379+
380+
public void disableDelta() {
381+
for (Map.Entry<TreeItem, Listener> entry : itemListeners.entrySet()) {
382+
TreeItem item = entry.getKey();
383+
Listener listener = entry.getValue();
384+
385+
// Revert text to original
386+
item.setText("Project name");
387+
388+
// Remove listener from the item's parent
389+
item.getParent().removeListener(SWT.Selection, listener);
390+
}
391+
392+
// Clear the map after removing all listeners
393+
itemListeners.clear();
394+
}
395+
258396
// Helper method to add a command if it's not already present
259397
private void addCommandIfNotPresent(IMenuManager menu, String commandId) {
260398
if (menu.find(commandId) == null) {

plugin/src/main/java/io/snyk/eclipse/plugin/views/snyktoolview/handlers/FilterDeltaNewIssuesHandler.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package io.snyk.eclipse.plugin.views.snyktoolview.handlers;
22

3+
import org.eclipse.core.commands.ExecutionEvent;
4+
import org.eclipse.core.commands.ExecutionException;
35
import org.eclipse.ui.commands.IElementUpdater;
46

7+
import io.snyk.eclipse.plugin.SnykStartup;
58
import io.snyk.eclipse.plugin.properties.preferences.Preferences;
69
import io.snyk.eclipse.plugin.utils.SnykIcons;
710

@@ -14,7 +17,15 @@ public FilterDeltaNewIssuesHandler() {
1417
iconDisabled = SnykIcons.DISABLED;
1518
preferenceKey = Preferences.FILTER_DELTA_NEW_ISSUES;
1619

17-
// TODO filter to only show the issues on local branch
20+
}
21+
22+
@Override
23+
public Object execute(ExecutionEvent event) throws ExecutionException {
24+
super.execute(event);
25+
26+
SnykStartup.getView().enableDelta();
27+
28+
return null;
1829
}
1930

2031
}

plugin/src/main/java/io/snyk/languageserver/LsNotificationID.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ public interface LsNotificationID {
66
public static final String SNYK_ADD_TRUSTED_FOLDERS = "$/snyk.addTrustedFolders";
77
public static final String SNYK_SCAN = "$/snyk.scan";
88
public static final String SNYK_PUBLISH_DIAGNOSTICS_316 = "$/snyk.publishDiagnostics316";
9+
public static final String SNYK_FOLDER_CONFIG = "$/snyk.folderConfigs";
910
}

plugin/src/main/java/io/snyk/languageserver/protocolextension/SnykExtendedLanguageClient.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666

6767
import com.fasterxml.jackson.databind.DeserializationFeature;
6868
import com.fasterxml.jackson.databind.ObjectMapper;
69+
import com.google.gson.Gson;
6970

7071
import io.snyk.eclipse.plugin.SnykStartup;
7172
import io.snyk.eclipse.plugin.analytics.AbstractTask;
@@ -92,6 +93,8 @@
9293
import io.snyk.languageserver.SnykLanguageServer;
9394
import io.snyk.languageserver.protocolextension.messageObjects.Diagnostic316;
9495
import io.snyk.languageserver.protocolextension.messageObjects.FeatureFlagStatus;
96+
import io.snyk.languageserver.protocolextension.messageObjects.FolderConfig;
97+
import io.snyk.languageserver.protocolextension.messageObjects.FolderConfigsParam;
9598
import io.snyk.languageserver.protocolextension.messageObjects.HasAuthenticatedParam;
9699
import io.snyk.languageserver.protocolextension.messageObjects.LsSdk;
97100
import io.snyk.languageserver.protocolextension.messageObjects.PublishDiagnostics316Param;
@@ -109,6 +112,9 @@ public class SnykExtendedLanguageClient extends LanguageClientImpl {
109112
// this field is for testing only
110113
private LanguageServer ls;
111114
private LsConfigurationUpdater configurationUpdater = new LsConfigurationUpdater();
115+
private final Gson gson = new Gson();
116+
117+
private final IEclipsePreferences state = InstanceScope.INSTANCE.getNode("io.snyk.eclipse.plugin");
112118
private static SnykExtendedLanguageClient instance = null;
113119

114120
public SnykExtendedLanguageClient() {
@@ -378,6 +384,30 @@ public void snykScan(SnykScanParam param) {
378384
setNodeState(param.getStatus(), affectedProductTreeNodes, issueCache);
379385
}
380386

387+
@JsonNotification(value = LsNotificationID.SNYK_FOLDER_CONFIG)
388+
public void folderConfig(FolderConfigsParam folderConfigParam) {
389+
390+
List<FolderConfig> folderConfigs = folderConfigParam != null ? folderConfigParam.getFolderConfigs() : List.of();
391+
392+
CompletableFuture.runAsync(() -> addAll(folderConfigs));
393+
394+
}
395+
396+
public void addAll(List<FolderConfig> folderConfigs) {
397+
for (FolderConfig folderConfig : folderConfigs) {
398+
addFolderConfig(folderConfig);
399+
}
400+
}
401+
402+
public void addFolderConfig(FolderConfig folderConfig) {
403+
state.put(folderConfig.getFolderPath(), gson.toJson(folderConfig));
404+
try {
405+
state.flush();
406+
} catch (Exception e) {
407+
SnykLogger.logError(e);
408+
}
409+
}
410+
381411
private void openToolView() {
382412
// we don't want to use the UI in tests usually
383413
if (this.toolView != null || Preferences.getInstance().isTest()) {
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package io.snyk.languageserver.protocolextension.messageObjects;
2+
3+
import java.util.List;
4+
5+
import com.google.gson.annotations.SerializedName;
6+
7+
public class FolderConfig {
8+
9+
@SerializedName("folderPath")
10+
private String folderPath;
11+
12+
@SerializedName("baseBranch")
13+
private String baseBranch;
14+
15+
@SerializedName("localBranches")
16+
private List<String> localBranches;
17+
18+
@SerializedName("additionalParameters")
19+
private List<String> additionalParameters;
20+
21+
public FolderConfig(String folderPath, String baseBranch, List<String> localBranches, List<String> additionalParameters) {
22+
this.folderPath = folderPath;
23+
this.baseBranch = baseBranch;
24+
this.localBranches = localBranches != null ? localBranches : List.of();
25+
this.additionalParameters = additionalParameters != null ? additionalParameters : List.of();
26+
}
27+
28+
public String getFolderPath() {
29+
return folderPath;
30+
}
31+
32+
public void setFolderPath(String folderPath) {
33+
this.folderPath = folderPath;
34+
}
35+
36+
public String getBaseBranch() {
37+
return baseBranch;
38+
}
39+
40+
public void setBaseBranch(String baseBranch) {
41+
this.baseBranch = baseBranch;
42+
}
43+
44+
public List<String> getLocalBranches() {
45+
return localBranches;
46+
}
47+
48+
public void setLocalBranches(List<String> localBranches) {
49+
this.localBranches = localBranches != null ? localBranches : List.of();
50+
}
51+
52+
public List<String> getAdditionalParameters() {
53+
return additionalParameters;
54+
}
55+
56+
public void setAdditionalParameters(List<String> additionalParameters) {
57+
this.additionalParameters = additionalParameters != null ? additionalParameters : List.of();
58+
}
59+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package io.snyk.languageserver.protocolextension.messageObjects;
2+
3+
import com.google.gson.annotations.SerializedName;
4+
import java.util.List;
5+
6+
public class FolderConfigsParam {
7+
8+
@SerializedName("folderConfigs")
9+
private List<FolderConfig> folderConfigs;
10+
11+
public FolderConfigsParam(List<FolderConfig> folderConfigs) {
12+
this.folderConfigs = folderConfigs;
13+
}
14+
15+
public List<FolderConfig> getFolderConfigs() {
16+
return folderConfigs;
17+
}
18+
19+
public void setFolderConfigs(List<FolderConfig> folderConfigs) {
20+
this.folderConfigs = folderConfigs;
21+
}
22+
}

0 commit comments

Comments
 (0)