diff --git a/plugins/tasks/tasks-api/src/com/intellij/tasks/Task.java b/plugins/tasks/tasks-api/src/com/intellij/tasks/Task.java
index 6b7717fd73f1..5ce47198299c 100644
--- a/plugins/tasks/tasks-api/src/com/intellij/tasks/Task.java
+++ b/plugins/tasks/tasks-api/src/com/intellij/tasks/Task.java
@@ -33,15 +33,29 @@ public abstract class Task {
/**
* Global unique task identifier, e.g. IDEA-00001. It's important that its format is consistent with
* {@link TaskRepository#extractId(String)}, because otherwise task won't be updated on its activation.
+ * Note that this ID is used to find issues and to compare them, so (ideally) it has to be unique.
+ *
+ * In some cases task server doesn't offer such global ID (but, for instance, pair (project-name, per-project-id) instead) or it's not
+ * what users want to see in UI (e.g. notorious id and iid in Gitlab). In this case you should generate artificial ID
+ * for internal usage and implement {@link #getPresentableId()}.
*
* @return unique global ID as described
*
- * @see com.intellij.tasks.TaskRepository#extractId(String)
- * @see com.intellij.tasks.TaskManager#activateTask(Task, boolean)
+ * @see #getPresentableId()
+ * @see TaskRepository#extractId(String)
+ * @see TaskManager#activateTask(Task, boolean)
*/
@NotNull
public abstract String getId();
+
+ /**
+ * @return ID in the form that is suitable for commit messages, dialogs, completion items, etc.
+ */
+ @NotNull
+ public String getPresentableId() {
+ return getId();
+ }
/**
* Short task description.
* @return description
@@ -100,7 +114,7 @@ public abstract class Task {
public final String toString() {
String text;
if (isIssue()) {
- text = getId() + ": " + getSummary();
+ text = getPresentableId() + ": " + getSummary();
} else {
text = getSummary();
}
diff --git a/plugins/tasks/tasks-api/src/com/intellij/tasks/TaskRepository.java b/plugins/tasks/tasks-api/src/com/intellij/tasks/TaskRepository.java
index 8051403ded0f..8c4384b574df 100644
--- a/plugins/tasks/tasks-api/src/com/intellij/tasks/TaskRepository.java
+++ b/plugins/tasks/tasks-api/src/com/intellij/tasks/TaskRepository.java
@@ -352,7 +352,7 @@ public abstract class TaskRepository {
@Nullable
public String getTaskComment(@NotNull Task task) {
return isShouldFormatCommitMessage()
- ? myCommitMessageFormat.replace("{id}", task.getId()).replace("{summary}", task.getSummary())
+ ? myCommitMessageFormat.replace("{id}", task.getPresentableId()).replace("{summary}", task.getSummary())
: null;
}
diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/EditTaskDialog.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/EditTaskDialog.java
index a25adf3907a7..4d5daa9bc9af 100644
--- a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/EditTaskDialog.java
+++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/EditTaskDialog.java
@@ -59,7 +59,7 @@ public class EditTaskDialog extends DialogWrapper {
protected EditTaskDialog(Project project, LocalTaskImpl task) {
super(project);
myTask = task;
- setTitle("Edit Task " + (task.isIssue() ? task.getId() : ""));
+ setTitle("Edit Task " + (task.isIssue() ? task.getPresentableId() : ""));
// mySummary.putClientProperty(DialogWrapperPeer.HAVE_INITIAL_SELECTION, "");
mySummary.setText(task.getSummary());
diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/TaskAutoCompletionListProvider.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/TaskAutoCompletionListProvider.java
index 6d2598d2a023..9fa080f1cc45 100644
--- a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/TaskAutoCompletionListProvider.java
+++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/TaskAutoCompletionListProvider.java
@@ -103,7 +103,7 @@ public class TaskAutoCompletionListProvider extends TextFieldWithAutoCompletionL
@NotNull
@Override
protected String getLookupString(@NotNull final Task task) {
- return task.getId();
+ return task.getPresentableId();
}
@Override
diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/TaskSearchSupport.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/TaskSearchSupport.java
index 6fb815e0edfc..ab3f60a045d2 100644
--- a/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/TaskSearchSupport.java
+++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/actions/TaskSearchSupport.java
@@ -56,7 +56,7 @@ public class TaskSearchSupport {
final Matcher matcher = getMatcher(pattern);
return ContainerUtil.mapNotNull(tasks, new NullableFunction() {
public Task fun(Task task) {
- return matcher.matches(task.getId()) || matcher.matches(task.getSummary()) ? task : null;
+ return matcher.matches(task.getPresentableId()) || matcher.matches(task.getSummary()) ? task : null;
}
});
}
diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/doc/TaskDocumentationProvider.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/doc/TaskDocumentationProvider.java
index 843a6fc7f7e2..87d980bc21e1 100644
--- a/plugins/tasks/tasks-core/src/com/intellij/tasks/doc/TaskDocumentationProvider.java
+++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/doc/TaskDocumentationProvider.java
@@ -51,7 +51,7 @@ public class TaskDocumentationProvider extends AbstractDocumentationProvider imp
final Task task = ((TaskPsiElement)element).getTask();
final StringBuilder builder = new StringBuilder();
builder.append("Summary: ").append(task.getSummary()).append("
");
- builder.append("Id: ").append(task.getId()).append("
");
+ builder.append("Id: ").append(task.getPresentableId()).append("
");
if (task.getCreated() != null) {
builder.append("Created at: ").append(task.getCreated()).append("
");
}
diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/gitlab/GitlabRepository.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/gitlab/GitlabRepository.java
index 40c42a4df2a3..8b850c2f76a6 100644
--- a/plugins/tasks/tasks-core/src/com/intellij/tasks/gitlab/GitlabRepository.java
+++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/gitlab/GitlabRepository.java
@@ -42,14 +42,17 @@ import static com.intellij.tasks.impl.httpclient.TaskResponseUtil.GsonSingleObje
public class GitlabRepository extends NewBaseRepositoryImpl {
@NonNls public static final String REST_API_PATH_PREFIX = "/api/v3/";
- private static final Pattern ID_PATTERN = Pattern.compile("\\d+");
+ @NonNls private static final String TOKEN_HEADER = "PRIVATE-TOKEN";
- public static final Gson GSON = TaskGsonUtil.createDefaultBuilder().create();
- public static final TypeToken> LIST_OF_PROJECTS_TYPE = new TypeToken>() {
- };
- public static final TypeToken> LIST_OF_ISSUES_TYPE = new TypeToken>() {
- };
- public static final GitlabProject UNSPECIFIED_PROJECT = new GitlabProject() {
+ private static final Pattern ID_PATTERN = Pattern.compile("\\d+");
+ private static final Gson GSON = TaskGsonUtil.createDefaultBuilder().create();
+
+ // @formatter:off
+ private static final TypeToken> LIST_OF_PROJECTS_TYPE = new TypeToken>() {};
+ private static final TypeToken> LIST_OF_ISSUES_TYPE = new TypeToken>() {};
+ // @formatter:on
+
+ static final GitlabProject UNSPECIFIED_PROJECT = new GitlabProject() {
@Override
public String getName() {
return "-- all issues created by you --";
@@ -88,7 +91,7 @@ public class GitlabRepository extends NewBaseRepositoryImpl {
@Override
public boolean equals(Object o) {
if (!super.equals(o)) return false;
- GitlabRepository repository = (GitlabRepository)o;
+ final GitlabRepository repository = (GitlabRepository)o;
if (!Comparing.equal(myCurrentProject, repository.myCurrentProject)) return false;
return true;
}
@@ -114,9 +117,7 @@ public class GitlabRepository extends NewBaseRepositoryImpl {
@Override
public Task findTask(@NotNull String id) throws Exception {
// doesn't work now, because Gitlab's REST API doesn't provide endpoint to find task
- // by its global ID, only by project ID and task's local ID (iid).
- //GitlabIssue issue = fetchIssue(Integer.parseInt(id));
- //return issue == null ? null : new GitlabTask(this, issue);
+ // using only its global ID, it requires both task's global ID AND task's project ID
return null;
}
@@ -155,7 +156,7 @@ public class GitlabRepository extends NewBaseRepositoryImpl {
@SuppressWarnings("UnusedDeclaration")
@NotNull
public GitlabProject fetchProject(int id) throws Exception {
- HttpGet request = new HttpGet(getRestApiUrl("project", id));
+ final HttpGet request = new HttpGet(getRestApiUrl("project", id));
return getHttpClient().execute(request, new GsonSingleObjectDeserializer(GSON, GitlabProject.class));
}
@@ -182,12 +183,14 @@ public class GitlabRepository extends NewBaseRepositoryImpl {
return getRestApiUrl("issues");
}
- @SuppressWarnings("UnusedDeclaration")
+ /**
+ * @param issueId global issue's ID (id field, not iid)
+ */
@Nullable
- public GitlabIssue fetchIssue(int id) throws Exception {
+ public GitlabIssue fetchIssue(int projectId, int issueId) throws Exception {
ensureProjectsDiscovered();
- HttpGet request = new HttpGet(getRestApiUrl("issues", id));
- ResponseHandler handler = new GsonSingleObjectDeserializer(GSON, GitlabIssue.class, true);
+ final HttpGet request = new HttpGet(getRestApiUrl("projects", projectId, "issues", issueId));
+ final ResponseHandler handler = new GsonSingleObjectDeserializer(GSON, GitlabIssue.class, true);
return getHttpClient().execute(request, handler);
}
@@ -223,7 +226,7 @@ public class GitlabRepository extends NewBaseRepositoryImpl {
return new HttpRequestInterceptor() {
@Override
public void process(HttpRequest request, HttpContext context) throws HttpException, IOException {
- request.addHeader("PRIVATE-TOKEN", myPassword);
+ request.addHeader(TOKEN_HEADER, myPassword);
//request.addHeader("Accept", "application/json");
}
};
diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/gitlab/GitlabTask.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/gitlab/GitlabTask.java
index 335cd9514eb8..a6b04356df59 100644
--- a/plugins/tasks/tasks-core/src/com/intellij/tasks/gitlab/GitlabTask.java
+++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/gitlab/GitlabTask.java
@@ -37,9 +37,17 @@ public class GitlabTask extends Task {
@NotNull
@Override
public String getId() {
+ // Will be in form :
+ //return myIssue.getProjectId() + ":" + myIssue.getId();
return String.valueOf(myIssue.getId());
}
+ @NotNull
+ @Override
+ public String getPresentableId() {
+ return "#" + myIssue.getLocalId();
+ }
+
@NotNull
@Override
public String getSummary() {
diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/LocalTaskImpl.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/LocalTaskImpl.java
index 50018ce09dea..0f96aed5c2f8 100644
--- a/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/LocalTaskImpl.java
+++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/LocalTaskImpl.java
@@ -57,6 +57,7 @@ public class LocalTaskImpl extends LocalTask {
private String myProject = null;
private String myNumber = "";
+ private String myPresentableId = "";
private boolean myIssue = false;
private TaskRepository myRepository = null;
@@ -161,6 +162,7 @@ public class LocalTaskImpl extends LocalTask {
myProject = issue.getProject();
myNumber = issue.getNumber();
+ myPresentableId = issue.getPresentableId();
}
public void setId(String id) {
@@ -394,4 +396,15 @@ public class LocalTaskImpl extends LocalTask {
public void setProject(@Nullable String project) {
myProject = project;
}
+
+ public void setPresentableId(@NotNull String presentableId) {
+ myPresentableId = presentableId;
+ }
+
+ @NotNull
+ @Override
+ public String getPresentableId() {
+ // Use global ID for compatibility
+ return StringUtil.isEmpty(myPresentableId) ? getId() : myPresentableId;
+ }
}
diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskManagerImpl.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskManagerImpl.java
index bc0ccb8e886c..0e4dcbb39761 100644
--- a/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskManagerImpl.java
+++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskManagerImpl.java
@@ -497,7 +497,7 @@ public class TaskManagerImpl extends TaskManager implements ProjectComponent, Pe
if (task.isIssue()) {
StartupManager.getInstance(myProject).runWhenProjectIsInitialized(new Runnable() {
public void run() {
- ProgressManager.getInstance().run(new com.intellij.openapi.progress.Task.Backgroundable(myProject, "Updating " + task.getId()) {
+ ProgressManager.getInstance().run(new com.intellij.openapi.progress.Task.Backgroundable(myProject, "Updating " + task.getPresentableId()) {
public void run(@NotNull ProgressIndicator indicator) {
updateIssue(task.getId());
diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskUtil.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskUtil.java
index b7db9b9a9f68..74bc704393ed 100644
--- a/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskUtil.java
+++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/impl/TaskUtil.java
@@ -72,7 +72,7 @@ public class TaskUtil {
public static String formatTask(@NotNull Task task, String format) {
return format
- .replace("{id}", task.getId())
+ .replace("{id}", task.getPresentableId())
.replace("{number}", task.getNumber())
.replace("{project}", StringUtil.notNullize(task.getProject()))
.replace("{summary}", task.getSummary());
@@ -90,7 +90,7 @@ public class TaskUtil {
public static String getTrimmedSummary(Task task) {
String text;
if (task.isIssue()) {
- text = task.getId() + ": " + task.getSummary();
+ text = task.getPresentableId() + ": " + task.getSummary();
}
else {
text = task.getSummary();
diff --git a/plugins/tasks/tasks-tests/test/com/intellij/tasks/integration/GitlabIntegrationTest.java b/plugins/tasks/tasks-tests/test/com/intellij/tasks/integration/GitlabIntegrationTest.java
index 3e5af94f2f53..a593989060f6 100644
--- a/plugins/tasks/tasks-tests/test/com/intellij/tasks/integration/GitlabIntegrationTest.java
+++ b/plugins/tasks/tasks-tests/test/com/intellij/tasks/integration/GitlabIntegrationTest.java
@@ -15,7 +15,6 @@ import com.intellij.util.containers.ContainerUtil;
import java.util.Collections;
/**
- * TODO: install Gitlab on server and add more functional tests
* @author Mikhail Golubev
*/
public class GitlabIntegrationTest extends TaskManagerTestCase {
@@ -48,14 +47,13 @@ public class GitlabIntegrationTest extends TaskManagerTestCase {
LocalTaskImpl localTask = new LocalTaskImpl(new GitlabTask(myRepository, issue));
String changeListComment = TaskUtil.getChangeListComment(localTask);
- assertEquals("project-1 2 1 Sample title", changeListComment);
+ assertEquals("project-1 2 #2 Sample title", changeListComment);
myRepository.setProjects(Collections.emptyList());
localTask = new LocalTaskImpl(new GitlabTask(myRepository, issue));
changeListComment = TaskUtil.getChangeListComment(localTask);
// Project is unknown, so "" is substituted instead
- assertEquals(" 2 1 Sample title", changeListComment);
-
+ assertEquals(" 2 #2 Sample title", changeListComment);
}
public void testIssueFilteringByState() throws Exception {
@@ -74,6 +72,25 @@ public class GitlabIntegrationTest extends TaskManagerTestCase {
assertEquals("Opened issue #1", openedIssues[0].getSummary());
}
+ // IDEA-136499
+ public void testPresentableId() throws Exception {
+ final GitlabIssue issue = myRepository.fetchIssue(5 /* ID Formatting Tests */, 10);
+ assertNotNull(issue);
+ assertEquals(10, issue.getId());
+ assertEquals(1, issue.getLocalId());
+ assertEquals(5, issue.getProjectId());
+
+ final GitlabTask task = new GitlabTask(myRepository, issue);
+ assertEquals("#1", task.getPresentableId());
+ assertEquals("1", task.getNumber());
+ assertEquals("ID Formatting Tests", task.getProject());
+ assertEquals("10", task.getId());
+ assertEquals("#1: First issue with iid = 1", task.toString());
+ myRepository.setShouldFormatCommitMessage(true);
+ assertEquals("#1 First issue with iid = 1", myRepository.getTaskComment(task));
+ }
+
+
@Override
public void setUp() throws Exception {
super.setUp();