Skip to content

Commit

Permalink
Merge branch 'release/0.1.0b3'
Browse files Browse the repository at this point in the history
  • Loading branch information
shomatan committed Feb 2, 2018
2 parents fc6d6e0 + bc985af commit 676e0b6
Show file tree
Hide file tree
Showing 49 changed files with 540 additions and 483 deletions.
29 changes: 23 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Download

Please download the jar file from this link, and run from the command line as follows.

https://github.com/nulab/BacklogMigration-Jira/releases/download/0.1.0b2/backlog-migration-jira-0.1.0b2.jar
https://github.com/nulab/BacklogMigration-Jira/releases/download/0.1.0b3/backlog-migration-jira-0.1.0b3.jar

java -jar backlog-migration-jira-[latest version].jar

Expand Down Expand Up @@ -135,7 +135,16 @@ Sample commands:
## Limitation

### Supported JIRA version
JIRA **SaaS and JIRA REST API v2** is supported.
#### Cloud version
We support.

#### Server version(Limited)
We support the following versions.

- 6.3.4

Can not migrate the change logs.
Can not migrate the status. It always be **Open**.

### Backlog's user roles
This program is for the users with the Space's **administrator** roles.
Expand Down Expand Up @@ -233,7 +242,7 @@ https://github.com/nulab/BacklogMigration-Jira/releases

こちらのリンクからjarファイルをダウンロードし、以下のようにコマンドラインから実行します。

https://github.com/nulab/BacklogMigration-Jira/releases/download/0.1.0b2/backlog-migration-jira-0.1.0b2.jar
https://github.com/nulab/BacklogMigration-Jira/releases/download/0.1.0b3/backlog-migration-jira-0.1.0b3.jar

java -jar backlog-migration-jira-[最新バージョン].jar

Expand Down Expand Up @@ -343,7 +352,15 @@ descriptionにある項目を使い、空白を埋める必要が有ります。
## 制限事項

### JIRAの対応バージョン
JIRAの対応バージョンは **SaaS版かつJIRA REST API v2** になります。
#### クラウド版
対応しております。

#### Server版(一部機能のみ)
以下のバージョンで確認しております。
- 6.3.4

変更履歴は移行できません。
状態は移行できません。状態は常に **未対応** となります。

### 実行できるユーザー
Backlogの **管理者権限** が必要になります。
Expand Down Expand Up @@ -416,6 +433,6 @@ MIT License

お問い合わせは下記サイトからご連絡ください。

https://www.backlog.jp/contact/
https://backlog.com/ja/contact/

[Backlog]: https://www.backlog.jp/
[Backlog]: https://backlog.com/ja/
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import sbt.Keys._

lazy val projectVersion = "0.1.0b2"
lazy val projectVersion = "0.1.0b3"

lazy val commonSettings = Seq(
organization := "com.nulabinc",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package com.nulabinc.backlog.j2b.exporter

import com.nulabinc.backlog.j2b.jira.domain.export.Field
import com.nulabinc.backlog.j2b.jira.domain.export.FieldType.CustomLabels
import com.nulabinc.jira.client.domain.{Component, Version}
import com.nulabinc.jira.client.domain.changeLog._
import com.nulabinc.jira.client.domain.field.{CustomLabel, Field}

object ChangeLogFilter {

Expand Down Expand Up @@ -33,13 +34,11 @@ object ChangeLogFilter {
case LinkChangeLogItemField => item.copy(field = DefaultField("link_issue"), fieldId = None)
case _ => item.field match {
case DefaultField(fieldId) => definitions.find(_.name == fieldId) match {
case Some(definition) if definition.schema.isDefined =>
if (definition.schema.get.customType.contains(CustomLabel))
item.copy(
fromDisplayString = item.fromDisplayString.map(_.replace(" ", ",")),
toDisplayString = item.toDisplayString.map(_.replace(" ", ","))
)
else item
case Some(definition) if definition.schema == CustomLabels =>
item.copy(
fromDisplayString = item.fromDisplayString.map(_.replace(" ", ",")),
toDisplayString = item.toDisplayString.map(_.replace(" ", ","))
)
case _ => item
}
case _ => item
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ private [exporter] class CommentReducer(issueId: Long, changeLogReducer: ChangeL
case None =>
StringUtil.notEmpty(changeLogContent.result().trim)
}
comment.copy(optIssueId = Some(issueId), optContent = optNewContent, isCreateIssue = false, changeLogs = newChangeLogs)
comment.copy(optIssueId = Some(issueId), optContent = optNewContent, changeLogs = newChangeLogs)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ import javax.inject.Inject

import com.nulabinc.backlog.j2b.exporter.console.RemainingTimeCalculator
import com.nulabinc.backlog.j2b.jira.conf.JiraBacklogPaths
import com.nulabinc.backlog.j2b.jira.domain.export._
import com.nulabinc.backlog.j2b.jira.domain.mapping.MappingCollectDatabase
import com.nulabinc.backlog.j2b.jira.domain.{CollectData, JiraProjectKey}
import com.nulabinc.backlog.j2b.jira.domain.{CollectData, FieldConverter, IssueFieldConverter, JiraProjectKey}
import com.nulabinc.backlog.j2b.jira.service._
import com.nulabinc.backlog.j2b.jira.utils.DateChangeLogConverter
import com.nulabinc.backlog.j2b.jira.writer._
import com.nulabinc.backlog.migration.common.utils.{ConsoleOut, Logging, ProgressBar}
import com.nulabinc.jira.client.domain._
import com.nulabinc.jira.client.domain.changeLog.{AssigneeFieldId, ComponentChangeLogItemField, CustomFieldFieldId, FixVersion}
import com.nulabinc.jira.client.domain.field.Field
import com.nulabinc.jira.client.domain.issue._
import com.osinka.i18n.Messages

Expand All @@ -39,7 +39,7 @@ class Exporter @Inject()(projectKey: JiraProjectKey,
extends Logging
with DateChangeLogConverter {

private val console = (ProgressBar.progress _)(Messages("common.issues"), Messages("message.exporting"), Messages("message.exported"))
// private val console = (ProgressBar.progress _)(Messages("common.issues"), Messages("message.exporting"), Messages("message.exported"))
// private val issuesInfoProgress = (ProgressBar.progress _)(Messages("common.issues_info"), Messages("message.collecting"), Messages("message.collected"))

def export(backlogPaths: JiraBacklogPaths): CollectData = {
Expand All @@ -63,10 +63,11 @@ class Exporter @Inject()(projectKey: JiraProjectKey,
ConsoleOut.boldln(Messages("message.executed", Messages("common.issue_type"), Messages("message.exported")), 1)

// issue
val statuses = statusService.all()
val total = issueService.count()
val fields = fieldService.all()
val statuses = statusService.all()
val total = issueService.count()
val calculator = new RemainingTimeCalculator(total)
val fields = FieldConverter.toExportField(fieldService.all())

fetchIssue(calculator, statuses, categories, versions, fields, 1, total, 0, 100)

// version & milestone
Expand All @@ -86,6 +87,7 @@ class Exporter @Inject()(projectKey: JiraProjectKey,
collectedData.outputJiraStatusesToFile(backlogPaths.jiraStatusesJson)

collectedData

}

private def fetchIssue(calculator: RemainingTimeCalculator,
Expand All @@ -101,43 +103,44 @@ class Exporter @Inject()(projectKey: JiraProjectKey,
issues.zipWithIndex.foreach {
case (issue, i) => {

// Issue fields
val issueFields = IssueFieldConverter.toExportIssueFields(issue.issueFields)

// Change logs
val issueChangeLogs = issueService.changeLogs(issue) // API Call

// comments
val comments = commentService.issueComments(issue)

// milestone
val milestones = MilestoneExtractor.extract(fields, issue.issueFields)
val milestones = MilestoneExtractor.extract(fields, issueFields)
milestones.foreach(m => mappingCollectDatabase.addMilestone(m))

// filter change logs and custom fields
val filteredIssueFields = IssueFieldFilter.filterMilestone(fields, issueFields)
val issueWithFilteredChangeLogs: Issue = issue.copy(
changeLogs = {
val filtered = ChangeLogFilter.filter(fields, components, versions, issueChangeLogs)
convertDateChangeLogs(filtered, fields)
},
issueFields = IssueFieldFilter.filterMilestone(fields, issue.issueFields)
}
)

def saveIssueFieldValue(id: String, fieldValue: FieldValue): Unit = fieldValue match {
case StringFieldValue(value) => mappingCollectDatabase.addCustomField(id, Some(value))
case NumberFieldValue(value) => mappingCollectDatabase.addCustomField(id, Some(value.toString))
case ArrayFieldValue(values) => values.map(v => mappingCollectDatabase.addCustomField(id, Some(v.value)))
case OptionFieldValue(value) => saveIssueFieldValue(id, value.value)
case AnyFieldValue(value) => mappingCollectDatabase.addCustomField(id, Some(value))
case UserFieldValue(user) => mappingCollectDatabase.addCustomField(id, Some(user.key))
case UserFieldValue(user) => mappingCollectDatabase.addCustomField(id, Some(user.identifyKey))
case other => mappingCollectDatabase.addCustomField(id, Some(other.value))
}

issueWithFilteredChangeLogs.issueFields.foreach(v => saveIssueFieldValue(v.id, v.value))
filteredIssueFields.foreach(v => saveIssueFieldValue(v.id, v.value))

// collect custom fields
val sprintDefinition = fields.find(_.name == "Sprint").get
issueWithFilteredChangeLogs.changeLogs.foreach { changeLog =>
changeLog.items.foreach { changeLogItem =>
changeLogItem.fieldId match {
case Some(CustomFieldFieldId(id)) if sprintDefinition.id == id => ()
case Some(CustomFieldFieldId(id)) =>
(changeLogItem.fieldId, fields.find(_.name == "Sprint")) match {
case (Some(CustomFieldFieldId(id)), Some(sprintDefinition)) if sprintDefinition.id == id => ()
case (Some(CustomFieldFieldId(id)), _) =>
mappingCollectDatabase.addCustomField(id, changeLogItem.fromDisplayString)
mappingCollectDatabase.addCustomField(id, changeLogItem.toDisplayString)
case _ => ()
Expand All @@ -151,6 +154,7 @@ class Exporter @Inject()(projectKey: JiraProjectKey,
fields = fields,
milestones = milestones,
issue = issueWithFilteredChangeLogs,
issueFields = filteredIssueFields,
comments = comments
)
issueWriter.write(initializedBacklogIssue, issue.createdAt.toDate)
Expand All @@ -177,19 +181,28 @@ class Exporter @Inject()(projectKey: JiraProjectKey,
}
}

Set(
Some(issue.creator.key),
issue.assignee.map(_.key)
).foreach { maybeKey =>
if (!mappingCollectDatabase.userExistsFromAllUsers(maybeKey)) {
userService.optUserOfKey(maybeKey) match {
case Some(u) if maybeKey.contains(u.name) => mappingCollectDatabase.add(u)
case Some(_) => mappingCollectDatabase.add(maybeKey)
case None => mappingCollectDatabase.addIgnoreUser(maybeKey)
def assignToDB(user: User): Unit = {
if (!mappingCollectDatabase.userExistsFromAllUsers(Some(user.identifyKey))) {
(user.key, user.name) match {
case (Some(key), _) =>
userService.optUserOfKey(Some(key)) match {
case Some(u) if Some(key).contains(u.name) => mappingCollectDatabase.add(u)
case Some(_) => mappingCollectDatabase.add(Some(key))
case None => mappingCollectDatabase.addIgnoreUser(Some(key))
}
case (None, name) =>
userService.optUserOfName(Some(name)) match {
case Some(u) if Some(name).contains(u.name) => mappingCollectDatabase.add(u)
case Some(_) => mappingCollectDatabase.add(Some(name))
case None => mappingCollectDatabase.addIgnoreUser(Some(name))
}
}
}
}

assignToDB(issue.creator)
issue.assignee.foreach(assignToDB)

(changeLogUsers ++ changeLogItemUsers).foreach { maybeUserName =>
if (!mappingCollectDatabase.userExistsFromAllUsers(maybeUserName)) {
userService.optUserOfName(maybeUserName) match {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.nulabinc.backlog.j2b.exporter

import com.nulabinc.jira.client.domain.field.Field
import com.nulabinc.jira.client.domain.issue.IssueField
import com.nulabinc.backlog.j2b.jira.domain.export.{Field, IssueField}

object IssueFieldFilter {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,16 @@ package com.nulabinc.backlog.j2b.exporter
import javax.inject.Inject

import com.nulabinc.backlog.j2b.issue.writer.convert._
import com.nulabinc.backlog.j2b.jira.domain.export.Milestone
import com.nulabinc.backlog.j2b.jira.domain.export._
import com.nulabinc.backlog.j2b.jira.domain.mapping.MappingCollectDatabase
import com.nulabinc.backlog.j2b.jira.service.{IssueService, UserService}
import com.nulabinc.backlog.j2b.jira.utils._
import com.nulabinc.backlog.migration.common.convert.Convert
import com.nulabinc.backlog.migration.common.domain._
import com.nulabinc.backlog.migration.common.utils._
import com.nulabinc.jira.client.domain.{Comment, User}
import com.nulabinc.jira.client.domain.Comment
import com.nulabinc.jira.client.domain.changeLog._
import com.nulabinc.jira.client.domain.field.{DatetimeSchema, Field}
import com.nulabinc.jira.client.domain.issue._
import com.nulabinc.jira.client.domain.issue.Issue

class IssueInitializer @Inject()(implicit val issueWrites: IssueWrites,
implicit val attachmentWrites: AttachmentWrites,
Expand All @@ -30,14 +29,15 @@ class IssueInitializer @Inject()(implicit val issueWrites: IssueWrites,
fields: Seq[Field],
milestones: Seq[Milestone],
issue: Issue,
issueFields: Seq[IssueField],
comments: Seq[Comment]): BacklogIssue = {
//attachments
// val attachmentFilter = new AttachmentFilter(issue.changeLogs)
// val filteredAttachments = attachmentFilter.filter(issue.attachments)

val filteredIssue = AttachmentFilter.filteredIssue(issue, comments)

val backlogIssue = Convert.toBacklog(filteredIssue)
val backlogIssue = Convert.toBacklog((filteredIssue, issueFields))

backlogIssue.copy(
summary = summary(filteredIssue),
Expand All @@ -52,7 +52,7 @@ class IssueInitializer @Inject()(implicit val issueWrites: IssueWrites,
versionNames = versionNames(filteredIssue),
priorityName = priorityName(filteredIssue),
optAssignee = assignee(mappingCollectDatabase, filteredIssue),
customFields = filteredIssue.issueFields.flatMap(f => customField(fields, f, filteredIssue.changeLogs)),
customFields = issueFields.flatMap(f => customField(fields, f, filteredIssue.changeLogs)),
attachments = attachmentNames(filteredIssue),
optActualHours = actualHours(filteredIssue),
notifiedUsers = Seq.empty[BacklogUser]
Expand Down Expand Up @@ -157,12 +157,9 @@ class IssueInitializer @Inject()(implicit val issueWrites: IssueWrites,
val fieldDefinition = fields.find(_.id == issueField.id).get // TODO Fix get
val currentValues = issueField.value match {
case ArrayFieldValue(values) => values.map(_.value)
case value => fieldDefinition.schema match {
case Some(v) => v.schemaType match {
case DatetimeSchema => Seq(dateTimeStringToDateString(value.value))
case _ => Seq(value.value)
}
case None => Seq(value.value)
case value => fieldDefinition.schema match {
case FieldType.DateTime => Seq(dateTimeStringToDateString(value.value))
case _ => Seq(value.value)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.nulabinc.backlog.j2b.exporter

import com.nulabinc.backlog.j2b.jira.domain.export.Milestone
import com.nulabinc.jira.client.domain.field.Field
import com.nulabinc.jira.client.domain.issue.{ArrayFieldValue, IssueField}
import com.nulabinc.backlog.j2b.jira.domain.export.{ArrayFieldValue, Field, IssueField, Milestone}

object MilestoneExtractor {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class JiraClientCommentService @Inject()(jira: JiraRestClient) extends CommentSe
jira.commentAPI.issueComments(issue.id, startAt, maxResults) match {
case Right(result) =>
val appendedComments = comments ++ result.comments
if (result.hasPage) fetch(issue, startAt + maxResults, maxResults, appendedComments)
if (result.hasPage(appendedComments.length)) fetch(issue, startAt + maxResults, maxResults, appendedComments)
else appendedComments
case Left(error) =>
throw new RuntimeException(s"Cannot get issue comments: ${error.message}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,15 @@ class AttachmentFilterSpec extends Specification {
),
status = Status("1", "status"),
priority = Priority("priority"),
creator = User("key", "name", "display", "mail"),
creator = User(Some("key"), "name", "display", "mail"),
createdAt = DateTime.now,
updatedAt = DateTime.now,
changeLogs = Seq.empty[ChangeLog],
attachments = Seq(
Attachment(
id = 1,
fileName = "file1.txt",
author = User("key1", "user1", "user1", "mail1"),
author = User(Some("key1"), "user1", "user1", "mail1"),
createdAt = DateTime.now,
size = 100,
mimeType = "mine",
Expand All @@ -47,7 +47,7 @@ class AttachmentFilterSpec extends Specification {
Attachment(
id = 2,
fileName = "file2.txt",
author = User("key2", "user2", "user2", "mail2"),
author = User(Some("key2"), "user2", "user2", "mail2"),
createdAt = DateTime.now,
size = 200,
mimeType = "mine",
Expand All @@ -56,7 +56,7 @@ class AttachmentFilterSpec extends Specification {
Attachment(
id = 3,
fileName = "file3.txt",
author = User("key3" ,"user3", "user3", "mail3"),
author = User(Some("key3") ,"user3", "user3", "mail3"),
createdAt = DateTime.now,
size = 300,
mimeType = "mine",
Expand All @@ -69,7 +69,7 @@ class AttachmentFilterSpec extends Specification {
Comment(
id = 1,
body = "test1 body [^file2.txt] ",
author = User("aaa", "aaa", "aaa", "mmm"),
author = User(Some("aaa"), "aaa", "aaa", "mmm"),
createdAt = DateTime.now
)
)
Expand Down
Loading

0 comments on commit 676e0b6

Please sign in to comment.