Fix issue #1066 - Exception when importing projects from YouTrack (constraint exception, duplicate entry for linked issues)

This commit is contained in:
Robin Shen 2022-12-31 20:12:41 +08:00
parent 6d01037f8c
commit 775d026c01
5 changed files with 66 additions and 74 deletions

View File

@ -246,9 +246,7 @@ public class DefaultClusterManager implements ClusterManager {
} catch (Exception e) {
throw ExceptionUtils.unchecked(e);
}
} else {
// logger.info("Waiting for cluster leader...");
}
}
}
}

View File

@ -394,7 +394,7 @@ public class ImportServer implements Serializable, Validatable {
+ "/issues/" + oldNumber + "/comments");
for (JsonNode commentNode: list(client, apiEndpoint, logger)) {
String commentContent = commentNode.get("body").asText(null);
if (commentContent != null) {
if (StringUtils.isNotBlank(commentContent)) {
IssueComment comment = new IssueComment();
comment.setIssue(issue);
comment.setContent(commentContent);

View File

@ -1,59 +1,16 @@
package io.onedev.server.plugin.imports.github;
import java.io.Serializable;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.Nullable;
import javax.validation.ConstraintValidatorContext;
import javax.validation.constraints.NotEmpty;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;
import org.apache.http.client.utils.URIBuilder;
import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
import org.joda.time.format.ISODateTimeFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.unbescape.html.HtmlEscape;
import com.fasterxml.jackson.databind.JsonNode;
import edu.emory.mathcs.backport.java.util.Collections;
import io.onedev.commons.bootstrap.SensitiveMasker;
import io.onedev.commons.utils.ExplicitException;
import io.onedev.commons.utils.StringUtils;
import io.onedev.commons.utils.TaskLogger;
import io.onedev.server.OneDev;
import io.onedev.server.entitymanager.IssueManager;
import io.onedev.server.entitymanager.MilestoneManager;
import io.onedev.server.entitymanager.ProjectManager;
import io.onedev.server.entitymanager.SettingManager;
import io.onedev.server.entitymanager.UserManager;
import io.onedev.server.entitymanager.*;
import io.onedev.server.entityreference.ReferenceMigrator;
import io.onedev.server.git.command.LsRemoteCommand;
import io.onedev.server.model.Issue;
import io.onedev.server.model.IssueComment;
import io.onedev.server.model.IssueField;
import io.onedev.server.model.IssueSchedule;
import io.onedev.server.model.Milestone;
import io.onedev.server.model.Project;
import io.onedev.server.model.User;
import io.onedev.server.model.*;
import io.onedev.server.model.support.LastUpdate;
import io.onedev.server.model.support.administration.GlobalIssueSetting;
import io.onedev.server.model.support.inputspec.InputSpec;
@ -66,6 +23,27 @@ import io.onedev.server.util.validation.Validatable;
import io.onedev.server.util.validation.annotation.ClassValidating;
import io.onedev.server.web.editable.annotation.Editable;
import io.onedev.server.web.editable.annotation.Password;
import org.apache.http.client.utils.URIBuilder;
import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
import org.joda.time.format.ISODateTimeFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.unbescape.html.HtmlEscape;
import javax.annotation.Nullable;
import javax.validation.ConstraintValidatorContext;
import javax.validation.constraints.NotEmpty;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;
import java.io.Serializable;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
@Editable
@ClassValidating
@ -344,23 +322,26 @@ public class ImportServer implements Serializable, Validatable {
String apiEndpoint = getApiEndpoint("/repos/" + gitHubRepo
+ "/issues/" + oldNumber + "/comments");
for (JsonNode commentNode: list(client, apiEndpoint, logger)) {
IssueComment comment = new IssueComment();
comment.setIssue(issue);
comment.setContent(commentNode.get("body").asText(null));
comment.setDate(ISODateTimeFormat.dateTimeNoMillis()
.parseDateTime(commentNode.get("created_at").asText())
.toDate());
login = commentNode.get("user").get("login").asText();
user = getUser(client, users, login, logger);
if (user != null) {
comment.setUser(user);
} else {
comment.setUser(OneDev.getInstance(UserManager.class).getUnknown());
nonExistentLogins.add(login);
}
String commentContent = commentNode.get("body").asText(null);
if (StringUtils.isNotBlank(commentContent)) {
IssueComment comment = new IssueComment();
comment.setIssue(issue);
comment.setContent(commentContent);
comment.setDate(ISODateTimeFormat.dateTimeNoMillis()
.parseDateTime(commentNode.get("created_at").asText())
.toDate());
issue.getComments().add(comment);
login = commentNode.get("user").get("login").asText();
user = getUser(client, users, login, logger);
if (user != null) {
comment.setUser(user);
} else {
comment.setUser(OneDev.getInstance(UserManager.class).getUnknown());
nonExistentLogins.add(login);
}
issue.getComments().add(comment);
}
}
issue.setCommentCount(issue.getComments().size());

View File

@ -606,10 +606,12 @@ public class ImportServer implements Serializable, Validatable {
for (JsonNode noteNode: list(client, apiEndpoint, logger)) {
if (!noteNode.get("system").asBoolean()) {
String commentContent = noteNode.get("body").asText(null);
if (commentContent != null) {
if (StringUtils.isNotBlank(commentContent)) {
if (!dryRun) {
commentContent = processAttachments(issue.getUUID(), issueFQN,
commentContent, attachmentRootUrl, tooLargeAttachments);
if (StringUtils.isBlank(commentContent))
continue;
}
IssueComment comment = new IssueComment();

View File

@ -25,6 +25,8 @@ import io.onedev.server.util.validation.Validatable;
import io.onedev.server.util.validation.annotation.ClassValidating;
import io.onedev.server.web.editable.annotation.Editable;
import io.onedev.server.web.editable.annotation.Password;
import org.apache.commons.lang3.tuple.ImmutableTriple;
import org.apache.commons.lang3.tuple.Triple;
import org.apache.http.client.utils.URIBuilder;
import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
import org.slf4j.Logger;
@ -888,7 +890,7 @@ public class ImportServer implements Serializable, Validatable {
for (JsonNode commentNode: issueNode.get("comments")) {
String commentContent = commentNode.get("text").asText(null);
if (commentContent != null || !commentNode.get("attachments").isEmpty()) {
if (StringUtils.isNotBlank(commentContent) || !commentNode.get("attachments").isEmpty()) {
IssueComment comment = new IssueComment();
comment.setIssue(issue);
if (!dryRun) {
@ -897,10 +899,14 @@ public class ImportServer implements Serializable, Validatable {
attachmentNodes.add(attachmentNode);
String processedContent = processAttachments(issue.getUUID(), readableId,
commentContent, attachmentNodes, tooLargeAttachments);
if (processedContent != null)
if (StringUtils.isNotBlank(processedContent))
comment.setContent(processedContent);
else
continue;
} else if (StringUtils.isNotBlank(commentContent)) {
comment.setContent(commentContent);
} else {
continue;
}
comment.setDate(new Date(commentNode.get("created").asLong(System.currentTimeMillis())));
if (commentNode.hasNonNull("author")) {
@ -981,18 +987,23 @@ public class ImportServer implements Serializable, Validatable {
dao.persist(comment);
}
}
Set<Triple<Long, Long, Long>> linkTriples = new HashSet<>();
for (Map.Entry<Long, Pair<LinkSpec, List<Long>>> entry: issueLinkInfo.entrySet()) {
Issue source = issueMappings.get(entry.getKey());
if (source != null) {
for (Long targetNumber: entry.getValue().getSecond()) {
Issue target = issueMappings.get(targetNumber);
if (target != null) {
IssueLink link = new IssueLink();
link.setSource(source);
link.setTarget(target);
link.setSpec(entry.getValue().getFirst());
OneDev.getInstance(IssueLinkManager.class).save(link);
var triple = new ImmutableTriple<>(source.getId(), target.getId(),
entry.getValue().getFirst().getId());
if (linkTriples.add(triple)) {
IssueLink link = new IssueLink();
link.setSource(source);
link.setTarget(target);
link.setSpec(entry.getValue().getFirst());
OneDev.getInstance(IssueLinkManager.class).save(link);
}
}
}
}