generated from JetBrains/intellij-platform-plugin-template
-
-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
18 changed files
with
804 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
74 changes: 74 additions & 0 deletions
74
src/main/kotlin/com/dsoftware/ghmanager/PluginErrorReportSubmitter.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
package com.dsoftware.ghmanager | ||
|
||
import com.intellij.ide.BrowserUtil | ||
import com.intellij.ide.plugins.PluginManagerCore.getPlugin | ||
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.util.SystemInfo | ||
import com.intellij.util.Consumer | ||
import java.awt.Component | ||
import java.net.URLEncoder | ||
import java.nio.charset.StandardCharsets | ||
|
||
internal class PluginErrorReportSubmitter : ErrorReportSubmitter() { | ||
private val REPORT_URL = | ||
"https://github.com/cunla/ghactions-manager/issues/new?assignees=&labels=&projects=&template=bug_report.md" | ||
|
||
override fun getReportActionText(): String { | ||
return "Report Issue on Plugin Issues Tracker" | ||
} | ||
|
||
override fun submit( | ||
events: Array<IdeaLoggingEvent>, | ||
additionalInfo: String?, | ||
parentComponent: Component, | ||
consumer: Consumer<in SubmittedReportInfo?> | ||
): Boolean { | ||
val event = events[0] | ||
val throwableTitle = event.throwableText.lines()[0] | ||
|
||
val sb = StringBuilder(REPORT_URL) | ||
|
||
val titleEncoded = URLEncoder.encode(event.throwable?.message ?: throwableTitle, StandardCharsets.UTF_8) | ||
sb.append("&title=${titleEncoded}") | ||
|
||
val pluginVersion = getPlugin(pluginDescriptor.pluginId)?.version ?: "unknown" | ||
|
||
val body = """ | ||
### Describe the bug | ||
A clear and concise description of what the bug is. | ||
Add a screenshot if it is relevant. | ||
**Describe the bug:** | ||
${additionalInfo ?: ""} | ||
${event.message ?: ""} | ||
#### Stack trace | ||
{{{PLACEHOLDER}}} | ||
### Steps to reproduce | ||
<!-- Steps to reproduce the issue. --> | ||
### Expected behavior | ||
<!-- A clear and concise description of what you expected to happen. --> | ||
### Additional context | ||
Plugin version: $pluginVersion | ||
IDE: ${ApplicationInfo.getInstance().fullApplicationName} (${ApplicationInfo.getInstance().build.asString()}) | ||
OS: ${SystemInfo.getOsNameAndVersion()} | ||
""".trimIndent().replace("{{{PLACEHOLDER}}}", event.throwableText) | ||
sb.append("&body=${URLEncoder.encode(body, StandardCharsets.UTF_8)}") | ||
BrowserUtil.browse(sb.toString()) | ||
|
||
consumer.consume(SubmittedReportInfo(SubmittedReportInfo.SubmissionStatus.NEW_ISSUE)) | ||
return true | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
196 changes: 196 additions & 0 deletions
196
src/main/kotlin/com/dsoftware/ghmanager/psi/GitHubActionCache.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
package com.dsoftware.ghmanager.psi | ||
|
||
import com.dsoftware.ghmanager.api.GhApiRequestExecutor | ||
import com.dsoftware.ghmanager.data.GhActionsService | ||
import com.dsoftware.ghmanager.psi.model.GitHubAction | ||
import com.dsoftware.ghmanager.ui.ToolbarUtil | ||
import com.dsoftware.ghmanager.ui.settings.GhActionsSettingsService | ||
import com.fasterxml.jackson.databind.JsonNode | ||
import com.intellij.collaboration.api.dto.GraphQLRequestDTO | ||
import com.intellij.collaboration.api.dto.GraphQLResponseDTO | ||
import com.intellij.openapi.components.PersistentStateComponent | ||
import com.intellij.openapi.components.Service | ||
import com.intellij.openapi.components.State | ||
import com.intellij.openapi.components.Storage | ||
import com.intellij.openapi.components.service | ||
import com.intellij.openapi.diagnostic.logger | ||
import com.intellij.openapi.project.Project | ||
import com.intellij.util.ResourceUtil | ||
import com.intellij.util.ThrowableConvertor | ||
import com.intellij.util.concurrency.annotations.RequiresEdt | ||
import org.jetbrains.plugins.github.api.GithubApiContentHelper | ||
import org.jetbrains.plugins.github.api.GithubApiRequest.Post | ||
import org.jetbrains.plugins.github.api.GithubApiResponse | ||
import org.jetbrains.plugins.github.api.data.graphql.GHGQLError | ||
import org.jetbrains.plugins.github.exceptions.GithubAuthenticationException | ||
import org.jetbrains.plugins.github.exceptions.GithubConfusingException | ||
import org.jetbrains.plugins.github.exceptions.GithubJsonException | ||
import org.jetbrains.plugins.github.util.GHCompatibilityUtil | ||
import java.io.IOException | ||
import java.util.concurrent.ScheduledFuture | ||
|
||
@Service(Service.Level.PROJECT) | ||
@State(name = "GitHubActionCache", storages = [Storage("githubActionCache.xml")]) | ||
class GitHubActionCache(private val project: Project) : PersistentStateComponent<GitHubActionCache.State?> { | ||
private var state = State() | ||
val actionsToResolve = mutableSetOf<String>() | ||
private val task: ScheduledFuture<*> | ||
|
||
private val ghActionsService = project.service<GhActionsService>() | ||
private val settingsService = project.service<GhActionsSettingsService>() | ||
private val serverPath: String | ||
private var requestExecutor: GhApiRequestExecutor? = null | ||
|
||
init { | ||
this.serverPath = determineServerPath() | ||
ghActionsService.gitHubAccounts.firstOrNull()?.let { account -> | ||
val token = if (settingsService.state.useGitHubSettings) { | ||
GHCompatibilityUtil.getOrRequestToken(account, project) | ||
} else { | ||
settingsService.state.apiToken | ||
} | ||
requestExecutor = if (token == null) null else GhApiRequestExecutor.create(token) | ||
} | ||
task = ToolbarUtil.executeTaskAtCustomFrequency(project, 5) { | ||
actionsToResolve.removeAll(state.actions.keys) | ||
actionsToResolve.forEach { | ||
resolveGithubAction(it) | ||
} | ||
} | ||
} | ||
|
||
class State { | ||
val actions = TimedCache() | ||
} | ||
|
||
override fun loadState(state: State) { | ||
this.state = state | ||
} | ||
|
||
fun cleanup() { | ||
state.actions.cleanup() | ||
} | ||
|
||
private fun determineServerPath(): String { | ||
val mappings = ghActionsService.knownRepositoriesState.value | ||
if (mappings.isEmpty()) { | ||
LOG.info("No repository mappings, using default graphql url") | ||
return "https://api.github.com/graphql" | ||
} else { | ||
val mapping = mappings.iterator().next() | ||
return mapping.repository.serverPath.toGraphQLUrl() | ||
} | ||
} | ||
|
||
fun getAction(fullActionName: String): GitHubAction? { | ||
if (state.actions.containsKey(fullActionName)) { | ||
return state.actions[fullActionName] | ||
} | ||
LOG.info("Action $fullActionName not found in cache, adding to resolve list") | ||
actionsToResolve.add(fullActionName) | ||
return null | ||
} | ||
|
||
@RequiresEdt | ||
private fun resolveGithubAction(fullActionName: String) { | ||
if (state.actions.containsKey(fullActionName)) { | ||
return | ||
} | ||
val requestExecutor = this.requestExecutor | ||
if (requestExecutor == null) { | ||
LOG.warn("Failed to get latest version of action $fullActionName: no GitHub account found") | ||
return | ||
} | ||
LOG.info("Resolving action $fullActionName") | ||
val actionOrg = fullActionName.split("/".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[0] | ||
val actionName = fullActionName.split("/".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[1] | ||
val query = ResourceUtil.getResource( | ||
GhActionsService::class.java.classLoader, | ||
"graphql/query", | ||
"getLatestRelease.graphql" | ||
)?.readText() ?: "" | ||
|
||
val request = TraversedParsed( | ||
serverPath, | ||
query, | ||
mapOf("owner" to actionOrg, "name" to actionName), | ||
JsonNode::class.java, | ||
"repository", | ||
"latestRelease", | ||
"tag", | ||
"name" | ||
) | ||
try { | ||
val response = requestExecutor.execute(request) | ||
val version = response.toString().replace("\"", "") | ||
state.actions[fullActionName] = GitHubAction(actionName, version) | ||
} catch (e: IOException) { | ||
LOG.warn("Failed to get latest version of action $fullActionName", e) | ||
} | ||
} | ||
|
||
|
||
class TraversedParsed<out T : Any>( | ||
url: String, | ||
private val query: String, | ||
private val variablesObject: Any, | ||
private val clazz: Class<out T>, | ||
private vararg val pathFromData: String | ||
) : Post<T>(GithubApiContentHelper.JSON_MIME_TYPE, url) { | ||
|
||
override val body: String | ||
get() = GithubApiContentHelper.toJson(GraphQLRequestDTO(query, variablesObject), true) | ||
|
||
|
||
protected fun throwException(errors: List<GHGQLError>): Nothing { | ||
if (errors.any { it.type.equals("INSUFFICIENT_SCOPES", true) }) | ||
throw GithubAuthenticationException("Access token has not been granted the required scopes.") | ||
|
||
if (errors.size == 1) throw GithubConfusingException(errors.single().toString()) | ||
throw GithubConfusingException(errors.toString()) | ||
} | ||
|
||
override fun extractResult(response: GithubApiResponse): T { | ||
return parseResponse(response, clazz, pathFromData) | ||
?: throw GithubJsonException("Non-nullable entity is null or entity path is invalid") | ||
} | ||
|
||
private fun <T> parseResponse( | ||
response: GithubApiResponse, | ||
clazz: Class<T>, | ||
pathFromData: Array<out String> | ||
): T? { | ||
val result: GraphQLResponseDTO<out JsonNode, GHGQLError> = parseGQLResponse(response, JsonNode::class.java) | ||
val data = result.data | ||
if (data != null && !data.isNull) { | ||
var node: JsonNode = data | ||
for (path in pathFromData) { | ||
node = node[path] ?: break | ||
} | ||
if (!node.isNull) return GithubApiContentHelper.fromJson(node.toString(), clazz, true) | ||
} | ||
val errors = result.errors | ||
if (errors == null) return null | ||
else throwException(errors) | ||
} | ||
|
||
private fun <T> parseGQLResponse( | ||
response: GithubApiResponse, | ||
dataClass: Class<out T> | ||
): GraphQLResponseDTO<out T, GHGQLError> { | ||
return response.readBody(ThrowableConvertor { | ||
@Suppress("UNCHECKED_CAST") | ||
GithubApiContentHelper.readJsonObject( | ||
it, GraphQLResponseDTO::class.java, dataClass, GHGQLError::class.java, | ||
gqlNaming = true | ||
) as GraphQLResponseDTO<T, GHGQLError> | ||
}) | ||
} | ||
} | ||
|
||
override fun getState(): State = state | ||
|
||
companion object { | ||
private val LOG = logger<GitHubActionCache>() | ||
} | ||
} |
Oops, something went wrong.