Skip to content

Commit

Permalink
(GH-69) added an ErrorReportSubmitter
Browse files Browse the repository at this point in the history
which will open the "new issue" page on
GitHub to let a user create the issue there.
  • Loading branch information
nils-a committed Jan 19, 2021
1 parent 90d62bf commit b6979f0
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 1 deletion.
112 changes: 112 additions & 0 deletions rider/src/main/kotlin/net/cakebuild/shared/GitHubErrorReporter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package net.cakebuild.shared

import com.intellij.ide.BrowserUtil
import com.intellij.ide.plugins.IdeaPluginDescriptor
import com.intellij.openapi.application.ApplicationInfo
import com.intellij.openapi.diagnostic.ErrorReportSubmitter
import com.intellij.openapi.diagnostic.IdeaLoggingEvent
import com.intellij.openapi.diagnostic.SubmittedReportInfo
import com.intellij.openapi.diagnostic.SubmittedReportInfo.SubmissionStatus.FAILED
import com.intellij.openapi.diagnostic.SubmittedReportInfo.SubmissionStatus.NEW_ISSUE
import com.intellij.util.Consumer
import java.awt.Component
import java.net.URLEncoder

// Most of this was heavily inspired by
// https://github.com/exigow/intellij-gdscript/ ... /ReportSubmitter.kt
// and is there licensed under MIT by Jakub Błach (@exigow)

class GitHubErrorReporter : ErrorReportSubmitter() {
override fun getReportActionText() = "Create an issue on GitHub"

@Suppress("TooGenericExceptionCaught")
override fun submit(
events: Array<out IdeaLoggingEvent>,
additionalInfo: String?,
parentComponent: Component,
consumer: Consumer<SubmittedReportInfo>
): Boolean {

try {
if (events.isNotEmpty()) {
val event = events.first()
val issue = collectIssueDetails(event, additionalInfo)
submitOnGithub(issue)
}
} catch (e: Exception) {
consumer.consume(SubmittedReportInfo(FAILED))
return false
}
consumer.consume(SubmittedReportInfo(NEW_ISSUE))
return true
}

private fun collectIssueDetails(event: IdeaLoggingEvent, additionalInfo: String?) =
Report(
title = event.throwableText.lines().first(),
pluginVersion = discoverPluginVersion(),
ideVersion = discoverIdeaVersion(),
additionalInfo = additionalInfo,
stacktrace = event.throwableText
)

private fun discoverPluginVersion() =
(pluginDescriptor as? IdeaPluginDescriptor)?.version

private fun discoverIdeaVersion() =
ApplicationInfo.getInstance().build.toString()

private fun submitOnGithub(report: Report) {
val markdown = MarkdownDescriptionBaker.bake(report)
val title = report.title ?: "no title"
val url = GithubLinkGenerator.generateUrl(title, markdown)
BrowserUtil.browse(url)
}

private object GithubLinkGenerator {
fun generateUrl(title: String, body: String): String {
val encodedTitle = encode(title)
val encodedBody = encode(body)
return "https://github.com/cake-build/cake-rider/issues/new" +
"?labels=Bug" +
"&title=$encodedTitle" +
"&body=$encodedBody"
}

private fun encode(text: String) =
URLEncoder.encode(text, "UTF-8")
}

private object MarkdownDescriptionBaker {
fun bake(report: Report) = createEntries(report)
.filterValues { it != null }
.map { bakeAttribute(it.key, it.value!!) }
.joinToString("\n")

private fun createEntries(report: Report) = mapOf(
"Plugin version" to report.pluginVersion,
"IDE version" to report.ideVersion,
"Additional information" to report.additionalInfo,
"Exception" to report.title,
"Stacktrace" to report.stacktrace
)

private fun bakeAttribute(label: String, text: String) =
if (isMultiline(text)) {
"$label:\n```text\n$text\n```"
} else {
"$label: ```$text```"
}

private fun isMultiline(text: String) =
text.lines().size != 1
}

private data class Report(
val title: String?,
val pluginVersion: String?,
val ideVersion: String?,
val additionalInfo: String?,
val stacktrace: String?
)
}
3 changes: 2 additions & 1 deletion rider/src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
id="net.cakebuild.settings.cake.runner.paths" displayName="Search paths" nonDefaultProject="false" />
<projectConfigurable parentId="net.cakebuild.settings.cake" instance="net.cakebuild.settings.CakeRunnerSettingsConfigurable"
id="net.cakebuild.settings.cake.runner" displayName="Runner" nonDefaultProject="false" />
<projectService serviceImplementation="net.cakebuild.settings.CakeSettings"/>
<projectService serviceImplementation="net.cakebuild.settings.CakeSettings" />
<errorHandler implementation="net.cakebuild.shared.GitHubErrorReporter" />
</extensions>

<actions>
Expand Down

0 comments on commit b6979f0

Please sign in to comment.