Skip to content

Commit 1d2880d

Browse files
committed
Finished and documented the error reporter
1 parent da693e4 commit 1d2880d

9 files changed

Lines changed: 119 additions & 33 deletions

File tree

resources/META-INF/plugin.xml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
<id>de.halirutan.mathematica</id>
2424
<name>Mathematica Support</name>
2525
<category>Custom Language</category>
26-
<version>2.2</version>
26+
<version>2.3</version>
2727
<idea-version since-build="163"/>
2828
<vendor email="patrick@halirutan.de" url="http://mathematicaplugin.halirutan.de">Patrick Scheibe</vendor>
2929
<depends>com.intellij.modules.lang</depends>
@@ -67,6 +67,7 @@
6767
<i>New features and bug-fixes:</i>
6868
<br/>
6969
<ul>
70+
<li>A better error reporter that creates issues on GitHub automatically</li>
7071
<li>Spell check for symbols, comments and strings</li>
7172
<li>Code folding based on section comments like (* ::Section:: *)</li>
7273
<li>SurroundWith (Ctrl+Alt+T) will now do something useful when pressed without an active selection</li>
@@ -196,22 +197,19 @@
196197
</extensions>
197198

198199
<actions>
199-
200200
<action id="Mathematica.NewMathematicaFile"
201201
class="de.halirutan.mathematica.actions.CreateMathematicaFile" text="Mathematica File"
202202
description="Create New Mathematica File">
203203
<add-to-group group-id="NewGroup" anchor="before" relative-to-action="NewFromTemplate"/>
204204

205205
</action>
206-
207-
208206
<!-- Action to test the resolving of symbol definitions and their usages -->
209207
<!--<action id="HighlightElementAndReferences" class="de.halirutan.mathematica.actions.HighlightElementAndReferences"-->
210208
<!--text="Highlight References" description="Highlights the symbol under the cursor and its references">-->
211209
<!--<add-to-group group-id="EditMenu" anchor="after" relative-to-action="TemplateParametersNavigation"/>-->
212210
<!--</action>-->
213211

214-
Action for throwing an exception just to test the reporting of errors into the YouTrack database
212+
<!--Action for throwing an exception just to test the reporting of errors into the YouTrack database-->
215213
<action id="de.halirutan.mathematica.errorreporting.TriggerExceptionAction"
216214
class="de.halirutan.mathematica.errorreporting.TriggerExceptionAction" text="FireArtificialException">
217215
<keyboard-shortcut keymap="$default" first-keystroke="shift ctrl alt F12"/>

src/de/halirutan/mathematica/errorreporting/AnonymousFeedback.java

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@
3535
import java.util.*;
3636
import java.util.Map.Entry;
3737

38+
/**
39+
* Provides functionality to create and send GitHub issues when an exception is thrown by a plugin.
40+
*/
3841
class AnonymousFeedback {
3942

4043
private final static String gitAccessToken = "097a2a4e4a94ff65a73508083da690d4565fd038";
@@ -43,8 +46,17 @@ class AnonymousFeedback {
4346

4447
private final static String issueLabel = "auto-generated";
4548

46-
private AnonymousFeedback() { }
49+
private AnonymousFeedback() {
50+
}
4751

52+
/**
53+
* Makes a connection to GitHub. Checks if there is an issue that is a duplicate and based on this, creates either a
54+
* new issue or comments on the duplicate (if the user provided additional information).
55+
*
56+
* @param environmentDetails Information collected by {@link IdeaInformationProxy}
57+
* @return The report info that is then used in {@link GitHubErrorReporter} to show the user a balloon with the link
58+
* of the created issue.
59+
*/
4860
static SubmittedReportInfo sendFeedback(LinkedHashMap<String, String> environmentDetails) {
4961

5062
final SubmittedReportInfo result;
@@ -60,9 +72,8 @@ static SubmittedReportInfo sendFeedback(LinkedHashMap<String, String> environmen
6072
Issue duplicate = findFirstDuplicate(newGibHubIssue.getTitle(), issueService, repoID);
6173
boolean isNewIssue = true;
6274
if (duplicate != null) {
63-
if(errorDescription != null) {
64-
issueService.createComment(repoID, duplicate.getNumber(), errorDescription);
65-
}
75+
errorDescription = errorDescription == null ? "Me too!" : errorDescription;
76+
issueService.createComment(repoID, duplicate.getNumber(), errorDescription);
6677
newGibHubIssue = duplicate;
6778
isNewIssue = false;
6879
} else {
@@ -79,6 +90,18 @@ static SubmittedReportInfo sendFeedback(LinkedHashMap<String, String> environmen
7990
}
8091
}
8192

93+
/**
94+
* Collects all issues on the repo and finds the first duplicate that has the same title. For this to work, the title
95+
* contains the hash of the stack trace.
96+
*
97+
* @param uniqueTitle Title of the newly created issue. Since for auto-reported issues the title is always the same,
98+
* it includes the hash of the stack trace. The title is used so that I don't have to match
99+
* something in the whole body of the issue.
100+
* @param service Issue-service of the GitHub lib that lets you access all issues
101+
* @param repo The repository that should be used
102+
* @return The duplicate if one is found or null
103+
* @throws IOException Problems when connecting to GitHub
104+
*/
82105
@Nullable
83106
private static Issue findFirstDuplicate(String uniqueTitle, final IssueService service, RepositoryId repo) throws IOException {
84107
Map<String, String> searchParameters = new HashMap<>(2);
@@ -94,6 +117,13 @@ private static Issue findFirstDuplicate(String uniqueTitle, final IssueService s
94117
return null;
95118
}
96119

120+
/**
121+
* Turns collected information of an error into a new (offline) GitHub issue
122+
*
123+
* @param details A map of the information. Note that I remove items from there when they should not go in the issue
124+
* body as well. When creating the body, all remaining items are iterated.
125+
* @return The new issue
126+
*/
97127
private static Issue createNewGibHubIssue(LinkedHashMap<String, String> details) {
98128
String errorMessage = details.get("error.message");
99129
if (errorMessage == null || errorMessage.isEmpty()) {
@@ -117,6 +147,13 @@ private static Issue createNewGibHubIssue(LinkedHashMap<String, String> details)
117147
return gitHubIssue;
118148
}
119149

150+
/**
151+
* Creates the body of the GitHub issue. It will contain information about the system, details provided by the user
152+
* and the full stack trace. Everything is formatted using markdown.
153+
*
154+
* @param details Details provided by {@link IdeaInformationProxy}
155+
* @return A markdown string representing the GitHub issue body.
156+
*/
120157
private static String generateGitHubIssueBody(LinkedHashMap<String, String> details) {
121158
String errorDescription = details.get("error.description");
122159
if (errorDescription == null) {

src/de/halirutan/mathematica/errorreporting/AnonymousFeedbackTask.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,7 @@
3333

3434

3535
/**
36-
* Sends crash reports to Github. Extensively inspired by the one used in the Android Studio.
37-
* https://android.googlesource.com/platform/tools/adt/idea/+/master/android/src/com/android/tools/idea/diagnostics/error/ErrorReporter.java
38-
* As per answer from here: http://devnet.jetbrains.com/message/5526206;jsessionid=F5422B4AF1AFD05AAF032636E5455E90#5526206
36+
* Encapsulates the sending of feedback into a background task that is run by {@link GitHubErrorReporter}
3937
*/
4038
public class AnonymousFeedbackTask extends Backgroundable {
4139
private final Consumer<SubmittedReportInfo> myCallback;

src/de/halirutan/mathematica/errorreporting/ErrorReportBundle.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,7 @@
2828
import java.util.ResourceBundle;
2929

3030
/**
31-
* This class allows for i18n of the messages displayed by the error report submitter.
32-
*
33-
* @author <a href="mailto:intellij@studer.nu">Etienne Studer</a>, Jun 13, 2006
31+
* Messages and strings used by the error reporter
3432
*/
3533
class ErrorReportBundle {
3634
private static final String BUNDLE = "de.halirutan.mathematica.errorreporting.ErrorReportBundle";

src/de/halirutan/mathematica/errorreporting/GitHubErrorBean.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import java.util.Arrays;
2727

2828
/**
29+
* Extends the standard class to provide the hash of the thrown exception stack trace.
2930
* @author patrick (17.06.17).
3031
*/
3132
class GitHubErrorBean extends ErrorBean {

src/de/halirutan/mathematica/errorreporting/GitHubErrorReporter.java

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,18 @@
5151
import java.util.LinkedHashMap;
5252

5353
/**
54-
* Sends crash reports to Github. Extensively inspired by the one used in the Android Studio.
55-
* https://android.googlesource.com/platform/tools/adt/idea/+/master/android/src/com/android/tools/idea/diagnostics/error/ErrorReporter.java
56-
* As per answer from here: http://devnet.jetbrains.com/message/5526206;jsessionid=F5422B4AF1AFD05AAF032636E5455E90#5526206
54+
* Provides error reporting functionality for the plugin. When a user experiences an exception thrown by the plugin,
55+
* this is used to create an issue on a dedicated GitHub repository. This class takes care of collecting information about
56+
* the error and starts the creation of a GitHub issue as background task.
5757
*/
5858
public class GitHubErrorReporter extends ErrorReportSubmitter {
59+
60+
@Override
61+
public boolean submit(@NotNull IdeaLoggingEvent[] events, String additionalInfo, @NotNull Component parentComponent, @NotNull Consumer<SubmittedReportInfo> consumer) {
62+
GitHubErrorBean errorBean = new GitHubErrorBean(events[0].getThrowable(), IdeaLogger.ourLastActionId);
63+
return doSubmit(events[0], parentComponent, consumer, errorBean, additionalInfo);
64+
}
65+
5966
@SuppressWarnings("BooleanMethodNameMustStartWithQuestion")
6067
private static boolean doSubmit(final IdeaLoggingEvent event,
6168
final Component parentComponent,
@@ -85,7 +92,7 @@ private static boolean doSubmit(final IdeaLoggingEvent event,
8592
bean.setAttachments(((LogMessageEx) data).getIncludedAttachments());
8693
}
8794

88-
LinkedHashMap<String, String> reportValues = IdeaITNProxy
95+
LinkedHashMap<String, String> reportValues = IdeaInformationProxy
8996
.getKeyValuePairs(bean,
9097
ApplicationManager.getApplication(),
9198
(ApplicationInfoEx) ApplicationInfo.getInstance(),
@@ -110,12 +117,9 @@ public String getReportActionText() {
110117
return ErrorReportBundle.message("report.error.to.plugin.vendor");
111118
}
112119

113-
@Override
114-
public boolean submit(@NotNull IdeaLoggingEvent[] events, String additionalInfo, @NotNull Component parentComponent, @NotNull Consumer<SubmittedReportInfo> consumer) {
115-
GitHubErrorBean errorBean = new GitHubErrorBean(events[0].getThrowable(), IdeaLogger.ourLastActionId);
116-
return doSubmit(events[0], parentComponent, consumer, errorBean, additionalInfo);
117-
}
118-
120+
/**
121+
* Provides functionality to show a error report message to the user that gives a click-able link to the created issue.
122+
*/
119123
static class CallbackWithNotification implements Consumer<SubmittedReportInfo> {
120124

121125
private final Consumer<SubmittedReportInfo> myOriginalConsumer;

src/de/halirutan/mathematica/errorreporting/IdeaITNProxy.java renamed to src/de/halirutan/mathematica/errorreporting/IdeaInformationProxy.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,9 @@
3030
import java.util.LinkedHashMap;
3131

3232
/**
33-
* Sends crash reports to Github. Extensively inspired by the one used in the Android Studio.
34-
* https://android.googlesource.com/platform/tools/adt/idea/+/master/android/src/com/android/tools/idea/diagnostics/error/ErrorReporter.java
35-
* As per answer from here: http://devnet.jetbrains.com/message/5526206;jsessionid=F5422B4AF1AFD05AAF032636E5455E90#5526206
33+
* Collects information about the running IDEA and the error
3634
*/
37-
class IdeaITNProxy {
35+
class IdeaInformationProxy {
3836
static LinkedHashMap<String, String> getKeyValuePairs(GitHubErrorBean error,
3937
Application application,
4038
ApplicationInfoEx appInfo,

src/de/halirutan/mathematica/errorreporting/TriggerExceptionAction.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,8 @@
2424
import com.intellij.openapi.actionSystem.AnActionEvent;
2525

2626
/**
27-
* This class allows to test the error reporter functionality by throwing a runtime exception when the action is
28-
* invoked.
29-
*
30-
* @author <a href="mailto:intellij@studer.nu">Etienne Studer</a>, May 30, 2006
27+
* Provides functionality to throw a runtime exception when the action is invoked. It is used to test the error reporting
28+
* functions. Don't forget to register the action in plugin.xml to make it work.
3129
*/
3230
public class TriggerExceptionAction extends AnAction {
3331
public void actionPerformed(AnActionEvent e) {
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright (c) 2017 Patrick Scheibe
3+
* Permission is hereby granted, free of charge, to any person obtaining a copy
4+
* of this software and associated documentation files (the "Software"), to deal
5+
* in the Software without restriction, including without limitation the rights
6+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
* copies of the Software, and to permit persons to whom the Software is
8+
* furnished to do so, subject to the following conditions:
9+
*
10+
* The above copyright notice and this permission notice shall be included in
11+
* all copies or substantial portions of the Software.
12+
*
13+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
* THE SOFTWARE.
20+
*/
21+
22+
/**
23+
* <p>
24+
* Reporting user errors by creating issues on a dedicated GitHub repository. First off, honor to whom honor is due:
25+
* The implementation here would not have been possible with the help of several people that provided code to show how
26+
* an auto-reporter can be implemented into IDEA. Please see
27+
* </p>
28+
* <ul>
29+
* <li>@see <a href="https://android.googlesource.com/platform/tools/adt/idea/+/master/android/src/com/android/tools/idea/diagnostics/error/ErrorReporter.java">the android implementation</a></li>
30+
* <li>@see <a href="http://devnet.jetbrains.com/message/5526206>a post on jetbrains</a></li>
31+
* </ul>
32+
* <p>
33+
* Furthermore, an earlier implementation of Jon Akhtar (https://github.com/sylvanaar) gave me the idea of finding duplicates,
34+
* so that there is only one issue per unique stack trace. With many users, it is very likely that several of them report
35+
* issue and your issue list grows infinitely.
36+
* </p>
37+
* <p>
38+
* This implementation collects several information about the running idea, the stack trace of the exception and the
39+
* details provided by the user. It creates an issue on a GitHub repo for this, including the hash of the stack trace
40+
* in the title. When an error is reported, it searches through existing issues and finds the first duplicate. If there
41+
* is no duplicate, then it will create a new issue. If there is a duplicate and the user provided further information,
42+
* then the information of the user will be created as new comment on the existing issue. The user is, of course, free
43+
* to use GitHub markdown in his description.
44+
* </p>
45+
* <p>
46+
* The information about the running IDEA are collected in {@link de.halirutan.mathematica.errorreporting.IdeaInformationProxy}.
47+
* The class {@link de.halirutan.mathematica.errorreporting.GitHubErrorBean} extends the standard class and adds the hash
48+
* of the stack trace. This then used in the map created by {@link de.halirutan.mathematica.errorreporting.IdeaInformationProxy}.
49+
* Creating a valid GitHub issue and the communication with GitHub is done in {@link de.halirutan.mathematica.errorreporting.AnonymousFeedback}
50+
* which is run as background task {@link de.halirutan.mathematica.errorreporting.AnonymousFeedbackTask}.
51+
* The main class that is also registered in the plugin.xml and starts the whole procedure is {@link de.halirutan.mathematica.errorreporting.GitHubErrorReporter}.
52+
* </p>
53+
*/
54+
package de.halirutan.mathematica.errorreporting;

0 commit comments

Comments
 (0)