Skip to content
This repository has been archived by the owner on Mar 2, 2020. It is now read-only.

Commit

Permalink
fix: jira problems
Browse files Browse the repository at this point in the history
  • Loading branch information
junkerm committed Apr 3, 2019
1 parent 6087465 commit 73227b8
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import com.specmate.model.base.BaseFactory;
import com.specmate.model.base.Folder;
import com.specmate.model.base.IContainer;
import com.specmate.model.base.IContentElement;
import com.specmate.model.requirements.Requirement;
import com.specmate.model.support.util.SpecmateEcoreUtil;
import com.specmate.persistency.IChange;
Expand Down Expand Up @@ -45,10 +46,10 @@ public void run() {
}

private void syncRequirementsFromSources() {
logService.log(LogService.LOG_INFO, "Synchronizing requirements");
Resource resource = transaction.getResource();
for (IRequirementsSource source : requirementsSources) {
logService.log(LogService.LOG_INFO, "Retrieving requirements from " + source.getId());
this.logService.log(LogService.LOG_INFO, "Synchronizing requirements");
Resource resource = this.transaction.getResource();
for (IRequirementsSource source : this.requirementsSources) {
this.logService.log(LogService.LOG_INFO, "Retrieving requirements from " + source.getId());
try {
Collection<Requirement> requirements = source.getRequirements();
if (requirements == null) {
Expand All @@ -65,22 +66,22 @@ private void syncRequirementsFromSources() {
List<Requirement> tosync = Arrays.asList(current);

try {
transaction.doAndCommit(new IChange<Object>() {
this.transaction.doAndCommit(new IChange<Object>() {
@Override
public Object doChange() throws SpecmateException {
syncContainers(localContainer, tosync, source);
return null;
}
});
} catch (Exception e) {
logService.log(LogService.LOG_ERROR, e.getMessage());
transaction.rollback();
this.logService.log(LogService.LOG_ERROR, e.getMessage());
this.transaction.rollback();
}

}
} catch (Exception e) {
logService.log(LogService.LOG_ERROR, e.getMessage());
transaction.rollback();
this.logService.log(LogService.LOG_ERROR, e.getMessage());
this.transaction.rollback();
}

}
Expand All @@ -96,56 +97,64 @@ private void syncContainers(IContainer localContainer, Collection<Requirement> r
// Build hashset (extid -> requirement) for remote requirements
HashMap<String, EObject> remoteRequirementsMap = new HashMap<>();
buildExtIdMap(requirements.iterator(), remoteRequirementsMap);
logService.log(LogService.LOG_INFO, "Retrieved " + remoteRequirementsMap.entrySet().size() + " requirements.");
this.logService.log(LogService.LOG_INFO,
"Retrieved " + remoteRequirementsMap.entrySet().size() + " requirements.");

// find new requirements
remoteRequirementsMap.keySet().removeAll(localRequirementsMap.keySet());

logService.log(LogService.LOG_INFO, "Adding " + remoteRequirementsMap.size() + " new requirements.");
this.logService.log(LogService.LOG_INFO, "Adding " + remoteRequirementsMap.size() + " new requirements.");

// add new requirements to local container and all folders on the way
for (Entry<String, EObject> entry : remoteRequirementsMap.entrySet()) {
Requirement requirementToAdd = (Requirement) entry.getValue();
boolean valid = ensureValid(requirementToAdd);
if (!valid) {
logService.log(LogService.LOG_WARNING, "Found invalid requirement with id " + requirementToAdd.getId());
this.logService.log(LogService.LOG_WARNING,
"Found invalid requirement with id " + requirementToAdd.getId());
continue;
}
IContainer reqContainer;
try {
reqContainer = source.getContainerForRequirement((Requirement) entry.getValue());

} catch (SpecmateException e) {
logService.log(LogService.LOG_ERROR, e.getMessage());
this.logService.log(LogService.LOG_ERROR, e.getMessage());
continue;
}
IContainer foundContainer = (IContainer) SpecmateEcoreUtil.getEObjectWithId(reqContainer.getId(),
localContainer.eContents());
if (foundContainer == null) {
logService.log(LogService.LOG_DEBUG, "Creating new folder " + reqContainer.getName());
this.logService.log(LogService.LOG_DEBUG, "Creating new folder " + reqContainer.getName());
foundContainer = BaseFactory.eINSTANCE.createFolder();
SpecmateEcoreUtil.copyAttributeValues(reqContainer, foundContainer);
valid = ensureValid(foundContainer);
if (!valid) {
this.logService.log(LogService.LOG_WARNING,
"Found invalid folder with id " + foundContainer.getId());
continue;
}
localContainer.getContents().add(foundContainer);
}

logService.log(LogService.LOG_DEBUG, "Adding requirement " + requirementToAdd.getId());
this.logService.log(LogService.LOG_DEBUG, "Adding requirement " + requirementToAdd.getId());
foundContainer.getContents().add(requirementToAdd);
}
}

private boolean ensureValid(Requirement requirementToAdd) {
if (StringUtils.isEmpty(requirementToAdd.getId())) {
private boolean ensureValid(IContentElement element) {
if (StringUtils.isEmpty(element.getId())) {
return false;
}
if (StringUtils.isEmpty(requirementToAdd.getName())) {
requirementToAdd.setName(requirementToAdd.getId());
if (StringUtils.isEmpty(element.getName())) {
element.setName(element.getId());
}
if (requirementToAdd.getName().length() > MAX_FIELD_LENGTH) {
requirementToAdd.setName(requirementToAdd.getName().substring(0, MAX_FIELD_LENGTH - 1));
if (element.getName().length() > MAX_FIELD_LENGTH) {
element.setName(element.getName().substring(0, MAX_FIELD_LENGTH - 1));
}
requirementToAdd.setName(requirementToAdd.getName().replaceAll("[,\\|;]", " "));
if (requirementToAdd.getDescription() != null
&& requirementToAdd.getDescription().length() > MAX_FIELD_LENGTH) {
requirementToAdd.setDescription(requirementToAdd.getDescription().substring(0, MAX_FIELD_LENGTH - 1));
element.setName(element.getName().replaceAll("[,\\|;]", " "));
if (element.getDescription() != null && element.getDescription().length() > MAX_FIELD_LENGTH) {
element.setDescription(element.getDescription().substring(0, MAX_FIELD_LENGTH - 1));
}
return true;
}
Expand All @@ -159,9 +168,9 @@ private IContainer getOrCreateLocalContainer(Resource resource, String name) {
}

Folder folder = BaseFactory.eINSTANCE.createFolder();
folder.setName(name);
// TODO: sanitize id
folder.setId(name);
String validName = name.replaceAll("[,\\|;]", " ");
folder.setName(validName);
folder.setId(validName);
resource.getContents().add(folder);
return folder;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.atlassian.jira.rest.client.api.JiraRestClient;
import com.atlassian.jira.rest.client.api.RestClientException;
import com.atlassian.jira.rest.client.api.domain.Issue;
import com.atlassian.jira.rest.client.api.domain.IssueField;
import com.atlassian.jira.rest.client.api.domain.SearchResult;
import com.atlassian.jira.rest.client.internal.async.AsynchronousJiraRestClientFactory;
import com.specmate.common.cache.ICache;
Expand Down Expand Up @@ -75,20 +76,20 @@ public class JiraConnector extends DetailsService implements IRequirementsSource
public void activate(Map<String, Object> properties) throws SpecmateException {
validateConfig(properties);

id = (String) properties.get(IProjectConfigService.KEY_CONNECTOR_ID);
url = (String) properties.get(JiraConnectorConfig.KEY_JIRA_URL);
projectName = (String) properties.get(JiraConnectorConfig.KEY_JIRA_PROJECT);
this.id = (String) properties.get(IProjectConfigService.KEY_CONNECTOR_ID);
this.url = (String) properties.get(JiraConnectorConfig.KEY_JIRA_URL);
this.projectName = (String) properties.get(JiraConnectorConfig.KEY_JIRA_PROJECT);
String username = (String) properties.get(JiraConnectorConfig.KEY_JIRA_USERNAME);
String password = (String) properties.get(JiraConnectorConfig.KEY_JIRA_PASSWORD);

try {
jiraClient = new AsynchronousJiraRestClientFactory().createWithBasicHttpAuthentication(new URI(url),
username, password);
this.jiraClient = new AsynchronousJiraRestClientFactory()
.createWithBasicHttpAuthentication(new URI(this.url), username, password);
} catch (URISyntaxException e) {
throw new SpecmateInternalException(ErrorCode.JIRA, e);
}

defaultFolder = createFolder(projectName + "-Default", projectName + "-Default");
this.defaultFolder = createFolder(this.projectName + "-Default", this.projectName + "-Default");

this.cache = this.cacheService.createCache(JIRA_STORY_CACHE_NAME, 500, 3600, new ICacheLoader<String, Issue>() {

Expand All @@ -105,7 +106,7 @@ public Issue load(String key) throws SpecmateException {
@Deactivate
public void deactivate() throws SpecmateInternalException {
try {
jiraClient.close();
this.jiraClient.close();
this.cacheService.removeCache(JIRA_STORY_CACHE_NAME);
} catch (IOException e) {
throw new SpecmateInternalException(ErrorCode.INTERNAL_PROBLEM, "Could not close JIRA client.", e);
Expand Down Expand Up @@ -149,7 +150,7 @@ public Collection<Requirement> getRequirements() throws SpecmateException {
List<Issue> stories = getStoriesForEpic(epic);
for (Issue story : stories) {
Requirement requirement = createRequirement(story);
requirmentEpics.put(requirement, epic);
this.requirmentEpics.put(requirement, epic);
requirements.add(requirement);
}
}
Expand All @@ -158,21 +159,21 @@ public Collection<Requirement> getRequirements() throws SpecmateException {
}

private List<Issue> getStoriesForEpic(Issue epic) throws SpecmateException {
return this.getIssues("project=" + projectName + " AND issueType=story AND \"Epic Link\"=\"" + epic.getKey()
+ "\" ORDER BY assignee, resolutiondate");
return this.getIssues("project=" + this.projectName + " AND issueType=story AND \"Epic Link\"=\""
+ epic.getKey() + "\" ORDER BY assignee, resolutiondate");
}

private List<Issue> getStoriesWithoutEpic() throws SpecmateException {
return this.getIssues("project=" + projectName
return this.getIssues("project=" + this.projectName
+ " AND issueType=story AND \"Epic Link\" IS EMPTY ORDER BY assignee, resolutiondate");
}

private List<Issue> getEpics() throws SpecmateException {
return this.getIssues("project=" + projectName + " AND issueType=epic ORDER BY id");
return this.getIssues("project=" + this.projectName + " AND issueType=epic ORDER BY id");
}

private Issue getStory(String id) throws SpecmateException {
List<Issue> issues = this.getIssues("project=" + projectName + " AND id=" + id);
List<Issue> issues = this.getIssues("project=" + this.projectName + " AND id=" + id);
if (issues == null || issues.size() == 0) {
throw new SpecmateInternalException(ErrorCode.INTERNAL_PROBLEM, "JIRA Issue not found: " + id);
}
Expand All @@ -185,12 +186,12 @@ private List<Issue> getIssues(String jql) throws SpecmateException {
int maxResults = Integer.MAX_VALUE;
while (issues.size() < maxResults) {
try {
SearchResult searchResult = jiraClient.getSearchClient().searchJql(jql, -1, issues.size(), null)
SearchResult searchResult = this.jiraClient.getSearchClient().searchJql(jql, -1, issues.size(), null)
.claim();
maxResults = searchResult.getTotal();
searchResult.getIssues().forEach(issue -> issues.add(issue));
logService.log(LogService.LOG_DEBUG, "Loaded ~" + searchResult.getMaxResults() + " issues from Jira "
+ url + " project: " + projectName);
this.logService.log(LogService.LOG_DEBUG, "Loaded ~" + searchResult.getMaxResults()
+ " issues from Jira " + this.url + " project: " + this.projectName);
} catch (RestClientException e) {
if (e.getStatusCode().get() == 400) {
return issues;
Expand All @@ -202,34 +203,34 @@ private List<Issue> getIssues(String jql) throws SpecmateException {

}

logService.log(LogService.LOG_INFO,
"Finished loading of " + issues.size() + " issues from Jira " + url + " project: " + projectName);
this.logService.log(LogService.LOG_INFO, "Finished loading of " + issues.size() + " issues from Jira "
+ this.url + " project: " + this.projectName);

return issues;
}

@Override
public IContainer getContainerForRequirement(Requirement requirement) throws SpecmateException {
Issue epic = requirmentEpics.get(requirement);
Issue epic = this.requirmentEpics.get(requirement);
if (epic == null) {
return defaultFolder;
return this.defaultFolder;
}
return epicFolders.get(epic);
return this.epicFolders.get(epic);
}

@Override
public boolean authenticate(String username, String password) throws SpecmateException {
try {
JiraRestClient client = new AsynchronousJiraRestClientFactory()
.createWithBasicHttpAuthentication(new URI(url), username, password);
client.getProjectClient().getProject(projectName).claim();
.createWithBasicHttpAuthentication(new URI(this.url), username, password);
client.getProjectClient().getProject(this.projectName).claim();
} catch (URISyntaxException e) {
e.printStackTrace();
throw new SpecmateAuthorizationException("Jira authentication failed.", e);
} catch (RestClientException e) {
Integer status = e.getStatusCode().get();
if (status == 401) {
logService.log(LogService.LOG_INFO,
this.logService.log(LogService.LOG_INFO,
"Invalid credentials provided for jira project " + this.projectName + '.');
return false;
}
Expand All @@ -252,10 +253,13 @@ private static Requirement createRequirement(Issue story) throws SpecmateExcepti
requirement.setStatus(story.getStatus().getName());
requirement.setLive(true);
try {
JSONObject teamObject = (JSONObject) story.getFieldByName("Team").getValue();
if (teamObject != null) {
String team = (String) teamObject.get("value");
requirement.setImplementingITTeam(team);
IssueField teamField = story.getFieldByName("Team");
if (teamField != null) {
JSONObject teamObject = (JSONObject) teamField.getValue();
if (teamObject != null) {
String team = (String) teamObject.get("value");
requirement.setImplementingITTeam(team);
}
}
} catch (JSONException e) {
throw new SpecmateInternalException(ErrorCode.JIRA, e);
Expand All @@ -264,11 +268,11 @@ private static Requirement createRequirement(Issue story) throws SpecmateExcepti
}

private void createFolderIfNotExists(Issue epic) {
if (!epicFolders.containsKey(epic)) {
if (!this.epicFolders.containsKey(epic)) {
String folderId = epic.getKey();
String folderName = folderId + ": " + epic.getSummary();
Folder folder = createFolder(folderId, folderName);
epicFolders.put(epic, folder);
this.epicFolders.put(epic, folder);
}
}

Expand Down

0 comments on commit 73227b8

Please sign in to comment.