-
Notifications
You must be signed in to change notification settings - Fork 1
Implemented error reporting #139
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
5b84d32
Inserted error reporting part. But it doesn't work, problems with aut…
RamSaw ce61ea4
added TriggerExceptionAction to comfortable test of error reporting.
RamSaw 81df035
Implemented reporting, all is ok, but it remains
RamSaw 0878a9c
Merge with master
RamSaw 4bf77c3
ClassRefactoringPanel removed import.
RamSaw c9af2dc
Added more convenient constants naming, added labels support, added u…
RamSaw e73a449
Created more suitable enum for getting information.
RamSaw dbcdaeb
Added user id in output and added notification string which asks for …
RamSaw 3a67fb3
Comment error trigger action, now branch is ready for merge with master.
RamSaw 0d6a35a
Corrected marks.
RamSaw d1ad348
Corrected message in error notification.
RamSaw File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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
189 changes: 189 additions & 0 deletions
189
...main/java/org/jetbrains/research/groups/ml_methods/error_reporting/AnonymousFeedback.java
This file contains hidden or 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,189 @@ | ||
| package org.jetbrains.research.groups.ml_methods.error_reporting; | ||
|
|
||
| import com.intellij.openapi.diagnostic.SubmittedReportInfo; | ||
| import com.intellij.openapi.diagnostic.SubmittedReportInfo.SubmissionStatus; | ||
| import org.eclipse.egit.github.core.Issue; | ||
| import org.eclipse.egit.github.core.Label; | ||
| import org.eclipse.egit.github.core.RepositoryId; | ||
| import org.eclipse.egit.github.core.client.GitHubClient; | ||
| import org.eclipse.egit.github.core.client.PageIterator; | ||
| import org.eclipse.egit.github.core.service.IssueService; | ||
| import org.jetbrains.research.groups.ml_methods.error_reporting.ErrorReportInformation.InformationType; | ||
| import org.jetbrains.research.groups.ml_methods.utils.ArchitectureReloadedBundle; | ||
|
|
||
| import javax.annotation.Nullable; | ||
| import java.util.*; | ||
|
|
||
| import static org.jetbrains.research.groups.ml_methods.error_reporting.ErrorReportInformation.InformationType.*; | ||
|
|
||
| /** | ||
| * Provides functionality to create and send GitHub issues when an exception is thrown by a plugin. | ||
| */ | ||
| class AnonymousFeedback { | ||
| private final static String TOKEN_FILE = "errorReporterToken"; | ||
| private final static String GIT_REPO_USER = "ml-in-programming"; | ||
| private final static String GIT_REPO = "ArchitectureReloaded"; | ||
| private final static String ISSUE_LABEL_BUG = "bug"; | ||
| private final static String ISSUE_LABEL_AUTO_GENERATED = "auto-generated"; | ||
| private final static String GIT_ISSUE_TITLE = "[auto-generated:%s] %s"; | ||
| private final static String HTML_URL_TO_CREATE_NEW_ISSUE = "https://github.com/ml-in-programming/ArchitectureReloaded/issues/new"; | ||
| private final static EnumMap<InformationType, String> usersInformationToPresentableForm | ||
| = new EnumMap<>(InformationType.class); | ||
|
|
||
| static { | ||
| usersInformationToPresentableForm.put(PLUGIN_NAME, "Plugin Name"); | ||
| usersInformationToPresentableForm.put(PLUGIN_VERSION, "Plugin Version"); | ||
| usersInformationToPresentableForm.put(OS_NAME, "OS Name"); | ||
| usersInformationToPresentableForm.put(JAVA_VERSION, "Java Version"); | ||
| usersInformationToPresentableForm.put(JAVA_VM_VENDOR, "Java VM Vendor"); | ||
| usersInformationToPresentableForm.put(APP_NAME, "App Name"); | ||
| usersInformationToPresentableForm.put(APP_FULL_NAME, "App Full Name"); | ||
| usersInformationToPresentableForm.put(APP_VERSION_NAME, "App Version Name"); | ||
| usersInformationToPresentableForm.put(IS_EAP, "Is EAP"); | ||
| usersInformationToPresentableForm.put(APP_BUILD, "App Build"); | ||
| usersInformationToPresentableForm.put(APP_VERSION, "App Version"); | ||
| usersInformationToPresentableForm.put(LAST_ACTION, "Last Action"); | ||
| usersInformationToPresentableForm.put(PERMANENT_INSTALLATION_ID, "User's Permanent Installation ID"); | ||
| } | ||
|
|
||
| private AnonymousFeedback() { | ||
| } | ||
|
|
||
| /** | ||
| * Makes a connection to GitHub. Checks if there is an issue that is a duplicate and based on this, creates either a | ||
| * new issue or comments on the duplicate (if the user provided additional information). | ||
| * | ||
| * @param errorReportInformation Information collected by {@link ErrorReportInformation} | ||
| * @return The report info that is then used in {@link GitHubErrorReporter} to show the user a balloon with the link | ||
| * of the created issue. | ||
| */ | ||
| static SubmittedReportInfo sendFeedback(ErrorReportInformation errorReportInformation) { | ||
|
|
||
| final SubmittedReportInfo result; | ||
| try { | ||
| final String gitAccessToken = GitHubAccessTokenScrambler.decrypt(AnonymousFeedback.class.getResourceAsStream(TOKEN_FILE)); | ||
|
|
||
| GitHubClient client = new GitHubClient(); | ||
| client.setOAuth2Token(gitAccessToken); | ||
| RepositoryId repoID = new RepositoryId(GIT_REPO_USER, GIT_REPO); | ||
| IssueService issueService = new IssueService(client); | ||
|
|
||
| Issue newGibHubIssue = createNewGibHubIssue(errorReportInformation); | ||
| Issue duplicate = findFirstDuplicate(newGibHubIssue.getTitle(), issueService, repoID); | ||
| boolean isNewIssue = true; | ||
| if (duplicate != null) { | ||
| String newErrorComment = generateGitHubIssueBody(errorReportInformation, false); | ||
| issueService.createComment(repoID, duplicate.getNumber(), newErrorComment); | ||
| newGibHubIssue = duplicate; | ||
| isNewIssue = false; | ||
| } else { | ||
| newGibHubIssue = issueService.createIssue(repoID, newGibHubIssue); | ||
| } | ||
|
|
||
| final long id = newGibHubIssue.getNumber(); | ||
| final String htmlUrl = newGibHubIssue.getHtmlUrl(); | ||
| final String message = ArchitectureReloadedBundle.message(isNewIssue ? "git.issue.text" : "git.issue.duplicate.text", htmlUrl, id); | ||
| result = new SubmittedReportInfo(htmlUrl, message, isNewIssue ? SubmissionStatus.NEW_ISSUE : SubmissionStatus.DUPLICATE); | ||
| return result; | ||
| } catch (Exception e) { | ||
| return new SubmittedReportInfo(HTML_URL_TO_CREATE_NEW_ISSUE, | ||
| ArchitectureReloadedBundle.message("report.error.connection.failure", | ||
| HTML_URL_TO_CREATE_NEW_ISSUE), | ||
| SubmissionStatus.FAILED); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Collects all issues on the repo and finds the first duplicate that has the same title. For this to work, the title | ||
| * contains the hash of the stack trace. | ||
| * | ||
| * @param uniqueTitle Title of the newly created issue. Since for auto-reported issues the title is always the same, | ||
| * it includes the hash of the stack trace. The title is used so that I don't have to match | ||
| * something in the whole body of the issue. | ||
| * @param service Issue-service of the GitHub lib that lets you access all issues | ||
| * @param repo The repository that should be used | ||
| * @return The duplicate if one is found or null | ||
| */ | ||
| @Nullable | ||
| private static Issue findFirstDuplicate(String uniqueTitle, final IssueService service, RepositoryId repo) { | ||
| Map<String, String> searchParameters = new HashMap<>(2); | ||
| searchParameters.put(IssueService.FILTER_STATE, IssueService.STATE_OPEN); | ||
| final PageIterator<Issue> pages = service.pageIssues(repo, searchParameters); | ||
| for (Collection<Issue> page : pages) { | ||
| for (Issue issue : page) { | ||
| if (issue.getTitle().equals(uniqueTitle)) { | ||
| return issue; | ||
| } | ||
| } | ||
| } | ||
| return null; | ||
| } | ||
|
|
||
| /** | ||
| * Turns collected information of an error into a new (offline) GitHub issue | ||
| * | ||
| * @param errorReportInformation A map of the information. Note that I remove items from there when they should not go in the issue | ||
| * body as well. When creating the body, all remaining items are iterated. | ||
| * @return The new issue | ||
| */ | ||
| private static Issue createNewGibHubIssue(ErrorReportInformation errorReportInformation) { | ||
| String errorMessage = errorReportInformation.get(ERROR_MESSAGE); | ||
| if (errorMessage == null || errorMessage.isEmpty()) { | ||
| errorMessage = "Unspecified error"; | ||
| } | ||
| String errorHash = errorReportInformation.get(ERROR_HASH); | ||
| if (errorHash == null) { | ||
| errorHash = ""; | ||
| } | ||
|
|
||
| final Issue gitHubIssue = new Issue(); | ||
| final String body = generateGitHubIssueBody(errorReportInformation, true); | ||
| gitHubIssue.setTitle(String.format(GIT_ISSUE_TITLE, errorHash, errorMessage)); | ||
| gitHubIssue.setBody(body); | ||
| Label bugLabel = new Label(); | ||
| bugLabel.setName(ISSUE_LABEL_BUG); | ||
| Label autoGeneratedLabel = new Label(); | ||
| autoGeneratedLabel.setName(ISSUE_LABEL_AUTO_GENERATED); | ||
| gitHubIssue.setLabels(Arrays.asList(autoGeneratedLabel, bugLabel)); | ||
| return gitHubIssue; | ||
| } | ||
|
|
||
| /** | ||
| * Creates the body of the GitHub issue. It will contain information about the system, error report information | ||
| * provided by the user and the full stack trace. Everything is formatted using markdown. | ||
| * | ||
| * @param errorReportInformation Details provided by {@link ErrorReportInformation} | ||
| * @return A markdown string representing the GitHub issue body. | ||
| */ | ||
| private static String generateGitHubIssueBody(ErrorReportInformation errorReportInformation, boolean addStacktrace) { | ||
| String errorDescription = errorReportInformation.get(ERROR_DESCRIPTION); | ||
| if (errorDescription == null) { | ||
| errorDescription = ""; | ||
| } | ||
| String stackTrace = errorReportInformation.get(ERROR_STACKTRACE); | ||
| if (stackTrace == null || stackTrace.isEmpty()) { | ||
| stackTrace = "invalid stacktrace"; | ||
| } | ||
|
|
||
| StringBuilder result = new StringBuilder(); | ||
| if (!errorDescription.isEmpty()) { | ||
| result.append(errorDescription); | ||
| result.append("\n\n----------------------\n\n"); | ||
| } | ||
| for (Map.Entry<InformationType, String> usersInformationEntry : usersInformationToPresentableForm.entrySet()) { | ||
| result.append("- "); | ||
| result.append(usersInformationEntry.getValue()); | ||
| result.append(": "); | ||
| result.append(errorReportInformation.get(usersInformationEntry.getKey())); | ||
| result.append("\n"); | ||
| } | ||
|
|
||
| if (addStacktrace) { | ||
| result.append("\n```\n"); | ||
| result.append(stackTrace); | ||
| result.append("\n```\n"); | ||
| } | ||
|
|
||
| return result.toString(); | ||
| } | ||
| } |
35 changes: 35 additions & 0 deletions
35
.../java/org/jetbrains/research/groups/ml_methods/error_reporting/AnonymousFeedbackTask.java
This file contains hidden or 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,35 @@ | ||
| package org.jetbrains.research.groups.ml_methods.error_reporting; | ||
|
|
||
| import com.intellij.openapi.diagnostic.SubmittedReportInfo; | ||
| import com.intellij.openapi.progress.ProgressIndicator; | ||
| import com.intellij.openapi.progress.Task.Backgroundable; | ||
| import com.intellij.openapi.project.Project; | ||
| import com.intellij.util.Consumer; | ||
| import org.jetbrains.annotations.NotNull; | ||
| import org.jetbrains.annotations.Nullable; | ||
|
|
||
|
|
||
| /** | ||
| * Encapsulates the sending of feedback into a background task that is run by {@link GitHubErrorReporter} | ||
| */ | ||
| public class AnonymousFeedbackTask extends Backgroundable { | ||
| private final Consumer<SubmittedReportInfo> myCallback; | ||
| private final ErrorReportInformation errorReportInformation; | ||
|
|
||
| AnonymousFeedbackTask(@Nullable Project project, | ||
| @NotNull String title, | ||
| boolean canBeCancelled, | ||
| ErrorReportInformation errorReportInformation, | ||
| final Consumer<SubmittedReportInfo> callback) { | ||
| super(project, title, canBeCancelled); | ||
|
|
||
| this.errorReportInformation = errorReportInformation; | ||
| myCallback = callback; | ||
| } | ||
|
|
||
| @Override | ||
| public void run(@NotNull ProgressIndicator indicator) { | ||
| indicator.setIndeterminate(true); | ||
| myCallback.consume(AnonymousFeedback.sendFeedback(errorReportInformation)); | ||
| } | ||
| } |
64 changes: 64 additions & 0 deletions
64
...java/org/jetbrains/research/groups/ml_methods/error_reporting/ErrorReportInformation.java
This file contains hidden or 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,64 @@ | ||
| package org.jetbrains.research.groups.ml_methods.error_reporting; | ||
|
|
||
| import com.intellij.openapi.application.ApplicationNamesInfo; | ||
| import com.intellij.openapi.application.PermanentInstallationID; | ||
| import com.intellij.openapi.application.ex.ApplicationInfoEx; | ||
| import com.intellij.openapi.diagnostic.Attachment; | ||
| import com.intellij.util.SystemProperties; | ||
|
|
||
| import java.util.EnumMap; | ||
|
|
||
| import static org.jetbrains.research.groups.ml_methods.error_reporting.ErrorReportInformation.InformationType.*; | ||
|
|
||
| /** | ||
| * Collects information about the running IDEA and the error | ||
| */ | ||
| class ErrorReportInformation { | ||
| public enum InformationType { | ||
| ERROR_DESCRIPTION, PLUGIN_NAME, PLUGIN_VERSION, OS_NAME, JAVA_VERSION, JAVA_VM_VENDOR, | ||
| APP_NAME, APP_FULL_NAME, APP_VERSION_NAME, IS_EAP, APP_BUILD, APP_VERSION, LAST_ACTION, | ||
| PERMANENT_INSTALLATION_ID, ERROR_MESSAGE, ERROR_STACKTRACE, ERROR_HASH, ATTACHMENT_NAME, ATTACHMENT_VALUE | ||
| } | ||
|
|
||
| private final EnumMap<InformationType, String> information = new EnumMap<>(InformationType.class); | ||
|
|
||
| private ErrorReportInformation(GitHubErrorBean error, | ||
| ApplicationInfoEx appInfo, | ||
| ApplicationNamesInfo namesInfo) { | ||
| information.put(ERROR_DESCRIPTION, error.getDescription()); | ||
|
|
||
| information.put(PLUGIN_NAME, error.getPluginName()); | ||
| information.put(PLUGIN_VERSION, error.getPluginVersion()); | ||
| information.put(OS_NAME, SystemProperties.getOsName()); | ||
| information.put(JAVA_VERSION, SystemProperties.getJavaVersion()); | ||
| information.put(JAVA_VM_VENDOR, SystemProperties.getJavaVmVendor()); | ||
| information.put(APP_NAME, namesInfo.getProductName()); | ||
| information.put(APP_FULL_NAME, namesInfo.getFullProductName()); | ||
| information.put(APP_VERSION_NAME, appInfo.getVersionName()); | ||
| information.put(IS_EAP, Boolean.toString(appInfo.isEAP())); | ||
| information.put(APP_BUILD, appInfo.getBuild().asString()); | ||
| information.put(APP_VERSION, appInfo.getFullVersion()); | ||
| information.put(PERMANENT_INSTALLATION_ID, PermanentInstallationID.get()); | ||
| information.put(LAST_ACTION, error.getLastAction()); | ||
|
|
||
| information.put(ERROR_MESSAGE, error.getMessage()); | ||
| information.put(ERROR_STACKTRACE, error.getStackTrace()); | ||
| information.put(ERROR_HASH, error.getExceptionHash()); | ||
|
|
||
| for (Attachment attachment : error.getAttachments()) { | ||
| information.put(ATTACHMENT_NAME, attachment.getName()); | ||
| information.put(ATTACHMENT_VALUE, attachment.getEncodedBytes()); | ||
| } | ||
|
|
||
| } | ||
|
|
||
| static ErrorReportInformation getUsersInformation(GitHubErrorBean error, | ||
| ApplicationInfoEx appInfo, | ||
| ApplicationNamesInfo namesInfo) { | ||
| return new ErrorReportInformation(error, appInfo, namesInfo); | ||
| } | ||
|
|
||
| public String get(InformationType informationType) { | ||
| return information.get(informationType); | ||
| } | ||
| } |
67 changes: 67 additions & 0 deletions
67
.../org/jetbrains/research/groups/ml_methods/error_reporting/GitHubAccessTokenScrambler.java
This file contains hidden or 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,67 @@ | ||
| package org.jetbrains.research.groups.ml_methods.error_reporting; | ||
|
|
||
|
|
||
| import org.apache.commons.codec.binary.Base64; | ||
|
|
||
| import javax.crypto.Cipher; | ||
| import javax.crypto.spec.IvParameterSpec; | ||
| import javax.crypto.spec.SecretKeySpec; | ||
| import java.io.FileOutputStream; | ||
| import java.io.InputStream; | ||
| import java.io.ObjectInputStream; | ||
| import java.io.ObjectOutputStream; | ||
|
|
||
| /** | ||
| * Provides functionality to encode and decode secret tokens to make them not directly readable. Let me be clear: | ||
| * THIS IS THE OPPOSITE OF SECURITY! | ||
| */ | ||
| public class GitHubAccessTokenScrambler { | ||
| private static final String myInitVector = "RandomInitVector"; | ||
| private static final String myKey = "GitHubErrorToken"; | ||
|
|
||
| public static void main(String[] args) { | ||
| if (args.length != 2) { | ||
| return; | ||
| } | ||
| String horse = args[0]; | ||
| String outputFile = args[1]; | ||
| try { | ||
| final String e = encrypt(horse); | ||
| final ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(outputFile)); | ||
| o.writeObject(e); | ||
| o.close(); | ||
| } catch (Exception e) { | ||
| e.printStackTrace(); | ||
| } | ||
| } | ||
|
|
||
| private static String encrypt(String value) { | ||
| try { | ||
| IvParameterSpec iv = new IvParameterSpec(myInitVector.getBytes("UTF-8")); | ||
| SecretKeySpec keySpec = new SecretKeySpec(myKey.getBytes("UTF-8"), "AES"); | ||
|
|
||
| Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING"); | ||
| cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv); | ||
|
|
||
| byte[] encrypted = cipher.doFinal(value.getBytes()); | ||
| return Base64.encodeBase64String(encrypted); | ||
| } catch (Exception ex) { | ||
| ex.printStackTrace(); | ||
| } | ||
| return null; | ||
| } | ||
|
|
||
| static String decrypt(InputStream inputStream) throws Exception { | ||
| String in; | ||
| final ObjectInputStream o = new ObjectInputStream(inputStream); | ||
| in = (String) o.readObject(); | ||
| IvParameterSpec iv = new IvParameterSpec(myInitVector.getBytes("UTF-8")); | ||
| SecretKeySpec keySpec = new SecretKeySpec(myKey.getBytes("UTF-8"), "AES"); | ||
|
|
||
| Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING"); | ||
| cipher.init(Cipher.DECRYPT_MODE, keySpec, iv); | ||
|
|
||
| byte[] original = cipher.doFinal(Base64.decodeBase64(in)); | ||
| return new String(original); | ||
| } | ||
| } |
23 changes: 23 additions & 0 deletions
23
src/main/java/org/jetbrains/research/groups/ml_methods/error_reporting/GitHubErrorBean.java
This file contains hidden or 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,23 @@ | ||
| package org.jetbrains.research.groups.ml_methods.error_reporting; | ||
|
|
||
| import com.intellij.errorreport.bean.ErrorBean; | ||
|
|
||
| import java.util.Arrays; | ||
|
|
||
| /** | ||
| * Extends the standard class to provide the hash of the thrown exception stack trace. | ||
| */ | ||
| class GitHubErrorBean extends ErrorBean { | ||
|
|
||
| private String myExceptionHash; | ||
|
|
||
| GitHubErrorBean(Throwable throwable, String lastAction) { | ||
| super(throwable, lastAction); | ||
| final long hashCode = Integer.toUnsignedLong(Arrays.hashCode(throwable.getStackTrace())); | ||
| myExceptionHash = Long.toHexString(hashCode); | ||
| } | ||
|
|
||
| String getExceptionHash() { | ||
| return myExceptionHash; | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
может быть следовать одному стандарту описания зависимостей?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
какому?
В features-extraction есть такое:
testCompile group: 'org.hamcrest', name: 'hamcrest-all', version: '1.3'
Там тогда тоже надо менять
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ну хотя бы в пределах одного файла
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
так там остальное это jar и модули, они по другому подключаются же.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Не понял, как ты хочешь написать.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ну через colon
'org.eclipse.mylyn.github:org.eclipse.egit.github.core:2.1.5'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maven при копировании для gradle предлагает тот вариант, который сейчас.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ну да и ладно, пусть так будет