Skip to content

Commit 592c56b

Browse files
authored
Merge pull request #5 from DeepCodeAI/dev
Dev
2 parents 10eeddc + 2c86d45 commit 592c56b

20 files changed

+289
-38
lines changed

DeveloperGuide.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,14 @@
66
- Check if java is correctly installed (and your java version) with `java -version` command;
77
- Place `java-client-{X.X.X}-all.jar` into `..\libs` dir (see [java-client](https://github.com/DeepCodeAI/java-client) repository for instruction how to build it);
88
- At `build.gradle` file inside `intellij` block: uncomment `version` line and comment `localPath` line (or change `localPath` to pointing your locally installed Intellij Idea `2019.2` version instance);
9+
**Important note: For backward compatibility build MUST be run against Intellij Idea 2019.2 instance!**
910
- Run `source gradlew buildPlugin`
1011
- Look for resulting ZIP file at `..\build\distributions`
1112

13+
### Run tests
14+
15+
- Run gradle test task: `source gradlew test --stacktrace --scan`
16+
1217
### Useful links
1318
- IntelliJ Platform SDK [documentation](https://www.jetbrains.org/intellij/sdk/docs/intro/welcome.html)
1419
- JetBrains Marketplace [documentation](https://plugins.jetbrains.com/docs/marketplace/about-marketplace.html)

build.gradle

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ plugins {
77

88
//group 'org.example'
99

10-
version '1.0.1'
10+
version '1.0.2'
1111
sourceCompatibility = 1.8
1212

1313
repositories {
@@ -27,8 +27,7 @@ intellij {
2727
// localPath '/Users/arvid/Library/Application Support/JetBrains/Toolbox/apps/IDEA-C/ch-0/201.7223.91/IntelliJ IDEA CE.app/Contents'
2828
// localPath 'C:\\Users\\artem\\AppData\\Local\\JetBrains\\Toolbox\\apps\\PyCharm-C\\ch-0\\193.5233.109'
2929
// plugins += 'java'
30-
// plugins += 'PsiViewer:201-SNAPSHOT'
31-
plugins += 'PsiViewer:192-SNAPSHOT'
30+
// plugins += 'PsiViewer:192-SNAPSHOT'
3231

3332
}
3433
patchPluginXml {
@@ -91,7 +90,14 @@ task run_PC_193(type: RunIdeTask){
9190

9291
task run_AS_40(type: RunIdeTask){
9392
jvmArgs '-Xmx2G'
93+
jbrVersion '8u202b1483.24'
9494
ideDirectory 'C:\\Users\\artem\\AppData\\Local\\JetBrains\\Toolbox\\apps\\AndroidStudio\\ch-0\\193.6453388'
9595
}
9696

97+
task run_AS_36(type: RunIdeTask){
98+
jvmArgs '-Xmx2G'
99+
jbrVersion '8u202b1483.24'
100+
ideDirectory 'C:\\Users\\artem\\AppData\\Local\\JetBrains\\Toolbox\\apps\\AndroidStudio\\ch-1\\192.6392135'
101+
}
102+
97103
tasks.withType(RunIdeTask).forEach {task -> task.dependsOn(prepareSandbox)}

src/main/java/ai/deepcode/jbplugin/DeepCodeNotifications.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public static void showLoginLink(@Nullable Project project, @NotNull String mess
4747
new Notification(groupNeedAction, title, message, NotificationType.WARNING)
4848
.addAction(
4949
new ShowClickableLinkAction(
50-
"Login", () -> LoginUtils.requestNewLogin(prj), true));
50+
"Login", () -> LoginUtils.requestNewLogin(prj, true), true));
5151
lastNotifications.add(notification);
5252
notification.notify(prj);
5353
}
@@ -58,10 +58,8 @@ public static void showLoginLink(@Nullable Project project, @NotNull String mess
5858
public static void showConsentRequest(@NotNull Project project, boolean userActionNeeded) {
5959
if (!userActionNeeded && consentRequestShown) return;
6060
lastNotificationRunnable = () -> showConsentRequest(project, userActionNeeded);
61-
final String message =
62-
"Confirm remote analysis of "
63-
+ project.getBasePath();
64-
// + " (<a href=\"https://www.deepcode.ai/tc\">Terms & Conditions</a>)";
61+
final String message = "Confirm remote analysis of " + project.getBasePath();
62+
// + " (<a href=\"https://www.deepcode.ai/tc\">Terms & Conditions</a>)";
6563
final Notification notification =
6664
new ConsentNotification(
6765
groupNeedAction,
@@ -109,7 +107,7 @@ public void actionPerformed(@NotNull AnActionEvent e) {
109107
}
110108
}
111109

112-
private static void expireNotification(@NotNull Notification notification){
110+
private static void expireNotification(@NotNull Notification notification) {
113111
if (notification instanceof ConsentNotification) {
114112
((ConsentNotification) notification).consentExpired();
115113
} else {

src/main/java/ai/deepcode/jbplugin/actions/SeeResultsInBrowserAction.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,24 @@
44
import com.intellij.ide.BrowserUtil;
55
import com.intellij.openapi.actionSystem.AnAction;
66
import com.intellij.openapi.actionSystem.AnActionEvent;
7+
import com.intellij.openapi.project.Project;
78
import org.jetbrains.annotations.NotNull;
89

910
public class SeeResultsInBrowserAction extends AnAction {
1011

1112
@Override
1213
public void update(@NotNull AnActionEvent e) {
13-
e.getPresentation().setEnabled(!AnalysisData.getAnalysisUrl().isEmpty());
14+
final Project project = e.getProject();
15+
if (project==null) return;
16+
final boolean urlExist = !AnalysisData.getAnalysisUrl(project).isEmpty();
17+
e.getPresentation().setEnabled(urlExist);
1418
}
1519

1620
@Override
1721
public void actionPerformed(@NotNull AnActionEvent e) {
18-
final String analysisUrl = AnalysisData.getAnalysisUrl();
22+
final Project project = e.getProject();
23+
if (project==null) return;
24+
final String analysisUrl = AnalysisData.getAnalysisUrl(project);
1925
if (!analysisUrl.isEmpty()) BrowserUtil.open(analysisUrl);
2026
}
2127
}

src/main/java/ai/deepcode/jbplugin/core/AnalysisData.java

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ private AnalysisData() {}
4242

4343
private static final Logger LOG = LoggerFactory.getLogger("DeepCode.AnalysisData");
4444
private static final Map<PsiFile, List<SuggestionForFile>> EMPTY_MAP = Collections.emptyMap();
45-
private static String analysisUrl = "";
45+
private static Map<Project, String> mapProject2analysisUrl = new ConcurrentHashMap<>();
4646

4747
// todo: keep few latest file versions (Guava com.google.common.cache.CacheBuilder ?)
4848
private static final Map<PsiFile, List<SuggestionForFile>> mapFile2Suggestions =
@@ -94,8 +94,8 @@ public static Map<PsiFile, List<SuggestionForFile>> getAnalysis(
9494
return result;
9595
}
9696

97-
public static String getAnalysisUrl() {
98-
return analysisUrl;
97+
public static String getAnalysisUrl(@NotNull Project project) {
98+
return mapProject2analysisUrl.computeIfAbsent(project, p -> "");
9999
}
100100

101101
static boolean addProjectToCache(@NotNull Project project) {
@@ -184,11 +184,17 @@ public static void updateCachedResultsForFiles(
184184
.filter(file -> !mapFile2Suggestions.containsKey(file))
185185
.collect(Collectors.toSet());
186186
if (!filesToProceed.isEmpty()) {
187-
info("Files to proceed (not found in cache): " + filesToProceed.size());
188-
// fixme debug only
189187
// deepcode ignore checkIsPresent~Optional: collection already checked to be not empty
190188
final PsiFile firstFile = filesToProceed.stream().findFirst().get();
191-
info("Hash for first file " + firstFile.getName() + " [" + getHash(firstFile) + "]");
189+
info(
190+
"Files to proceed (not found in cache): "
191+
+ filesToProceed.size()
192+
// fixme debug only
193+
+ "\nHash for first file "
194+
+ firstFile.getName()
195+
+ " ["
196+
+ getHash(firstFile)
197+
+ "]");
192198

193199
mapFile2Suggestions.putAll(retrieveSuggestions(project, filesToProceed, filesToRemove));
194200

@@ -251,10 +257,6 @@ private static Map<PsiFile, List<SuggestionForFile>> retrieveSuggestions(
251257
info(PREPARE_FILES_TEXT);
252258
ProgressManager.checkCanceled();
253259
mapPsiFile2Content.clear();
254-
List<String> removedFiles =
255-
filesToRemove.stream()
256-
.map(DeepCodeUtils::getDeepCodedFilePath)
257-
.collect(Collectors.toList());
258260
Map<String, String> mapPath2Hash = new HashMap<>();
259261
long sizePath2Hash = 0;
260262
int fileCounter = 0;
@@ -280,7 +282,7 @@ private static Map<PsiFile, List<SuggestionForFile>> retrieveSuggestions(
280282
}
281283
}
282284
// todo break removeFiles in chunks less then MAX_BANDLE_SIZE
283-
CreateBundleResponse createBundleResponse = makeNewBundle(project, mapPath2Hash, removedFiles);
285+
CreateBundleResponse createBundleResponse = makeNewBundle(project, mapPath2Hash, filesToRemove);
284286
if (isNotSucceed(project, createBundleResponse, "Bad Create/Extend Bundle request: "))
285287
return EMPTY_MAP;
286288
info(
@@ -353,7 +355,7 @@ private static Map<PsiFile, List<SuggestionForFile>> retrieveSuggestions(
353355
progress.setText(WAITING_FOR_ANALYSIS_TEXT);
354356
ProgressManager.checkCanceled();
355357
GetAnalysisResponse getAnalysisResponse = doRetrieveSuggestions(project, bundleId, progress);
356-
result = parseGetAnalysisResponse(psiFiles, getAnalysisResponse, progress);
358+
result = parseGetAnalysisResponse(project, psiFiles, getAnalysisResponse, progress);
357359
info("--- Get Analysis took: " + (System.currentTimeMillis() - startTime) + " milliseconds");
358360
// progress.stop();
359361
return result;
@@ -362,9 +364,21 @@ private static Map<PsiFile, List<SuggestionForFile>> retrieveSuggestions(
362364
private static CreateBundleResponse makeNewBundle(
363365
@NotNull Project project,
364366
@NotNull Map<String, String> mapPath2Hash,
365-
@NotNull List<String> removedFiles) {
367+
@NotNull Collection<PsiFile> filesToRemove) {
366368
final FileHashRequest fileHashRequest = new FileHashRequest(mapPath2Hash);
367369
final String parentBundleId = mapProject2BundleId.getOrDefault(project, "");
370+
if (!parentBundleId.isEmpty()
371+
&& !filesToRemove.isEmpty()
372+
&& mapPath2Hash.isEmpty()
373+
&& filesToRemove.containsAll(cachedFilesOfProject(project))) {
374+
warn(
375+
"Attempt to Extending a bundle by removing all the parent bundle's files: "
376+
+ filesToRemove);
377+
}
378+
List<String> removedFiles =
379+
filesToRemove.stream()
380+
.map(DeepCodeUtils::getDeepCodedFilePath)
381+
.collect(Collectors.toList());
368382
String message =
369383
(parentBundleId.isEmpty()
370384
? "Creating new Bundle with "
@@ -385,10 +399,19 @@ private static CreateBundleResponse makeNewBundle(
385399
parentBundleId,
386400
new ExtendBundleRequest(fileHashRequest.getFiles(), removedFiles));
387401
}
388-
mapProject2BundleId.put(project, bundleResponse.getBundleId());
402+
String newBundleId = bundleResponse.getBundleId();
403+
// By man: "Extending a bundle by removing all the parent bundle's files is not allowed."
404+
// In reality new bundle returned with next bundleID:
405+
// gh/ArtsiomCh/DEEPCODE_PRIVATE_BUNDLE/0000000000000000000000000000000000000000000000000000000000000000
406+
if (newBundleId.equals(
407+
"gh/ArtsiomCh/DEEPCODE_PRIVATE_BUNDLE/0000000000000000000000000000000000000000000000000000000000000000")) {
408+
newBundleId = "";
409+
}
410+
mapProject2BundleId.put(project, newBundleId);
389411
return bundleResponse;
390412
}
391413

414+
// ?? com.intellij.openapi.util.text.StringUtil.toHexString
392415
// https://www.baeldung.com/sha-256-hashing-java#message-digest
393416
private static String bytesToHex(byte[] hash) {
394417
StringBuilder hexString = new StringBuilder();
@@ -512,13 +535,14 @@ private static GetAnalysisResponse doRetrieveSuggestions(
512535

513536
@NotNull
514537
private static Map<PsiFile, List<SuggestionForFile>> parseGetAnalysisResponse(
538+
@NotNull Project project,
515539
@NotNull Collection<PsiFile> psiFiles,
516540
GetAnalysisResponse response,
517541
@NotNull ProgressIndicator progressIndicator) {
518542
Map<PsiFile, List<SuggestionForFile>> result = new HashMap<>();
519543
if (!response.getStatus().equals("DONE")) return EMPTY_MAP;
520544
AnalysisResults analysisResults = response.getAnalysisResults();
521-
analysisUrl = response.getAnalysisURL();
545+
mapProject2analysisUrl.put(project, response.getAnalysisURL());
522546
if (analysisResults == null) {
523547
LOG.error("AnalysisResults is null for: {}", response);
524548
return EMPTY_MAP;
@@ -603,7 +627,7 @@ public static void clearCache(@Nullable final Project project) {
603627
for (Project prj : projects) {
604628
removeProjectFromCache(prj);
605629
ServiceManager.getService(prj, myTodoView.class).refresh();
630+
mapProject2analysisUrl.put(prj, "");
606631
}
607-
analysisUrl = "";
608632
}
609633
}

src/main/java/ai/deepcode/jbplugin/core/LoginUtils.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public class LoginUtils {
1818
private LoginUtils() {}
1919

2020
private static final String userAgent =
21-
"JetBrains-plugin-"
21+
"JetBrains-"
2222
+ ApplicationNamesInfo.getInstance().getProductName()
2323
+ "-"
2424
+ ApplicationInfo.getInstance().getFullVersion();
@@ -54,15 +54,17 @@ public static boolean isLogged(@Nullable Project project, boolean userActionNeed
5454
}
5555

5656
/** network request! */
57-
public static void requestNewLogin(@NotNull Project project) {
57+
public static void requestNewLogin(@NotNull Project project, boolean openBrowser) {
5858
DCLogger.info("New Login requested.");
5959
DeepCodeParams.clearLoginParams();
6060
LoginResponse response = DeepCodeRestApi.newLogin(userAgent);
6161
if (response.getStatusCode() == 200) {
62-
DCLogger.info("New Login request succeed. New Token: " + response.getSessionToken());
62+
DCLogger.info("New Login request succeed. New Token: " + response.getSessionToken());
6363
DeepCodeParams.setSessionToken(response.getSessionToken());
6464
DeepCodeParams.setLoginUrl(response.getLoginURL());
65-
BrowserUtil.open(DeepCodeParams.getLoginUrl());
65+
if (openBrowser) {
66+
BrowserUtil.open(DeepCodeParams.getLoginUrl());
67+
}
6668
if (!isLoginCheckLoopStarted) {
6769
ReadAction.nonBlocking(() -> startLoginCheckLoop(project))
6870
.submit(NonUrgentExecutor.getInstance());

src/main/java/ai/deepcode/jbplugin/core/MyBulkFileListener.java

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public class MyBulkFileListener implements BulkFileListener {
2626
@Override
2727
public void after(@NotNull List<? extends VFileEvent> events) {
2828
// fixme debug only
29-
DCLogger.info("MyBulkFileListener.after begins");
29+
DCLogger.info("MyBulkFileListener.after begins for: " + events);
3030
for (Project project : AnalysisData.getAllCachedProject()) {
3131
RunUtils.runInBackground(
3232
project,
@@ -48,11 +48,16 @@ public void after(@NotNull List<? extends VFileEvent> events) {
4848
// fixme doen't work for copy-past file ( VFileMoveEvent ?)
4949
VFileCreateEvent.class));
5050
if (!filesChangedOrCreated.isEmpty()) {
51-
// fixme debug only
5251
DCLogger.info(
5352
filesChangedOrCreated.size() + " files changed: " + filesChangedOrCreated);
54-
AnalysisData.removeFilesFromCache(filesChangedOrCreated);
55-
RunUtils.asyncAnalyseAndUpdatePanel(project, filesChangedOrCreated);
53+
for (PsiFile psiFile : filesChangedOrCreated) {
54+
RunUtils.runInBackgroundCancellable(
55+
psiFile,
56+
() -> {
57+
AnalysisData.removeFilesFromCache(Collections.singleton(psiFile));
58+
RunUtils.asyncAnalyseAndUpdatePanel(project, Collections.singleton(psiFile));
59+
});
60+
}
5661
}
5762
});
5863

@@ -74,12 +79,12 @@ public void after(@NotNull List<? extends VFileEvent> events) {
7479
}
7580
}
7681
// fixme debug only
77-
DCLogger.info("MyBulkFileListener.after ends");
82+
DCLogger.info("MyBulkFileListener.after ends for: " + events);
7883
}
7984

8085
@Override
8186
public void before(@NotNull List<? extends VFileEvent> events) {
82-
DCLogger.info("MyBulkFileListener.before begins");
87+
DCLogger.info("MyBulkFileListener.before begins for: " + events);
8388
for (Project project : AnalysisData.getAllCachedProject()) {
8489
if (project.isDisposed()) continue;
8590
Set<PsiFile> filesRemoved =
@@ -107,7 +112,7 @@ public void before(@NotNull List<? extends VFileEvent> events) {
107112
});
108113
}
109114
}
110-
DCLogger.info("MyBulkFileListener.before ends");
115+
DCLogger.info("MyBulkFileListener.before ends for: " + events);
111116
}
112117

113118
private Set<PsiFile> getFilteredFilesByEventTypes(

src/test/.dcignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
testData
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package ai.deepcode.jbplugin;
2+
3+
import ai.deepcode.jbplugin.core.DeepCodeParams;
4+
import com.intellij.openapi.project.Project;
5+
import com.intellij.testFramework.fixtures.BasePlatformTestCase;
6+
7+
/**
8+
* See: https://www.jetbrains.org/intellij/sdk/docs/basics/testing_plugins/testing_plugins.html See:
9+
* https://www.jetbrains.org/intellij/sdk/docs/tutorials/writing_tests_for_plugins.html
10+
*/
11+
public abstract class MyBasePlatformTestCase extends BasePlatformTestCase {
12+
protected Project project;
13+
14+
@Override
15+
protected void setUp() throws Exception {
16+
super.setUp();
17+
project = myFixture.getProject();
18+
}
19+
20+
// !!! Will works only with already logged sessionToken
21+
protected static final String loggedToken =
22+
"aeedc7d1c2656ea4b0adb1e215999f588b457cedf415c832a0209c9429c7636e";
23+
24+
@Override
25+
protected String getTestDataPath() {
26+
return "src/test/testData";
27+
}
28+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package ai.deepcode.jbplugin;
2+
3+
import com.intellij.testFramework.PlatformTestCase;
4+
5+
/**
6+
* See: https://www.jetbrains.org/intellij/sdk/docs/basics/testing_plugins/testing_plugins.html See:
7+
* https://www.jetbrains.org/intellij/sdk/docs/tutorials/writing_tests_for_plugins.html
8+
*/
9+
public abstract class MyPlatformTestCase extends PlatformTestCase {
10+
11+
// !!! Will works only with already logged sessionToken
12+
protected static final String loggedToken =
13+
"aeedc7d1c2656ea4b0adb1e215999f588b457cedf415c832a0209c9429c7636e";
14+
15+
}

0 commit comments

Comments
 (0)