diff --git a/README.md b/README.md index 186e424..a82e8c7 100644 --- a/README.md +++ b/README.md @@ -134,25 +134,7 @@ Backlog側に同一プロジェクトキーがある場合は、以下の仕様 MacOSにおいて、`テキストエディット`アプリでマッピングファイルを編集するとダブルクオーテーションが変換されてしまいます。 「環境設定」→「スマート引用符」のチェックを外してください。 -## 第三者のトラッキングシステム - -当アプリケーションでは、利用状況把握のために、サードパーティのサービス(Mixpanel)によって、移行先のURL、移行先のプロジェクトキーなどの情報を収集します。 -トラッキングするデータについてはMixpanelのプライバシーポリシーを参照してください。また、お客様のデータがMixpanelで使用されることを望まない場合は、以下に掲げる方法で使用停止(オプトアウト)することができます。 - -次のようにoptOutオプションを使用することで使用停止(オプトアウト)することができます。 - - java -jar backlog-migration-cybozulive-[latest version].jar \ - import \ - --backlog.key XXXXXXXXXXXXX \ - --backlog.url https://xxxxxxx.backlog.jp \ - --projectKey BACKLOG_PROJECT - --optOut - -### Mixpanel - -[Mixpanelのプライバシーポリシー](https://mixpanel.com/privacy/ "Mixpanelのプライバシーポリシー") - -## License +## ライセンス MIT License @@ -171,7 +153,6 @@ https://backlog.com/ja/contact/ # Backlog Migration for CybozuLive Migrate your projects from CybozuLive to [Backlog]. -(英語の下に日本文が記載されています) * Backlog * [https://backlog.com](https://backlog.com/) @@ -203,8 +184,6 @@ Create a working directory. $ cd work Download jar file. - - [link is here] Create a data directory. @@ -282,22 +261,22 @@ This program is for the users with the Space's **administrator** roles. - Can not migrate bulletin forum and event attachments - The ToDo category can not be migrated. -### About limitations in Backlog -- Importing users will be terminated if the number of users will exceed the limit in Backlog. +### About limitations in the Backlog +- Importing users will be terminated if the number of users exceeds the limit in the Backlog. - Empty comments are not registered. ## Re-importing -When the project key in Backlog and CybozuLive matches, they will be considered as the same project and data will be imported as follows. +When the project key in the Backlog and CybozuLive matches, they will be considered as the same project and data will be imported as follows. **If the person migrating data is not in the project.** The project will not be imported and the following message will be shown. Join the project to migrate data. -Importing to this project failed. You are not a member of this project. Join the project to add issues. +To migrate this project, you have to join. Join the project to add issues. | Item | Specifications | |:-----------|------------| -| Project | The project will not be added when there is a project with same project key. The issues and wikis will be added to the existing project. | +| Project | The project will not be added when there is a project with the same project key. The issues and wikis will be added to the existing project. | | Issues | Issues with matching subject, creator, creation date are not registered. | ## Important points @@ -306,24 +285,6 @@ Importing to this project failed. You are not a member of this project. Join th In MacOS, when you edit the mapping file with `TextEdit` application, double quotes will be converted. Please uncheck "Preferences" → "Smart quotes". -## Third party tracking system - -In this application, we collect information such as source URL, destination URL, migration source project key, migration destination project key, by third party service (Mixpanel) in order to grasp usage situation. -Please refer to Mixpanel's privacy policy for data to be tracked. Also, if you do not want your data to be used in Mixpanel, you can suspend (opt out) by the following methods. - -If you want to opt out, please use the optOut option. - - java -jar backlog-migration-cybozulive-[latest version].jar \ - import \ - --backlog.key XXXXXXXXXXXXX \ - --backlog.url https://xxxxxxx.backlog.jp \ - --projectKey BACKLOG_PROJECT - --optOut - -### Mixpanel - -[Mixpanel's Privacy Policy](https://mixpanel.com/privacy/ "Mixpanel's Privacy Policy") - ## License MIT License @@ -332,6 +293,6 @@ MIT License ## Inquiry -Please contact us if you encounter any problems during the CybozuLive to Backlog migration. +Please contact us if you encounter any problems during the CybozuLive to the Backlog migration. https://backlog.com/contact/ diff --git a/build.sbt b/build.sbt index 8bd6750..56e869c 100644 --- a/build.sbt +++ b/build.sbt @@ -2,30 +2,12 @@ name := "backlog-migration-cybozulive" lazy val commonSettings = Seq( - version := "0.1.0b3", - scalaVersion := "2.12.6", - libraryDependencies ++= Seq( - "org.fusesource.jansi" % "jansi" % "1.17", - "com.osinka.i18n" %% "scala-i18n" % "1.0.2", - "ch.qos.logback" % "logback-classic" % "1.2.3", - "com.typesafe" % "config" % "1.3.3", - "org.scalatest" %% "scalatest" % "3.0.5" % Test - ) + version := "0.2.0b1", + scalaVersion := "2.12.6" ) lazy val backlogMigrationCommon = (project in file("modules/common")) .settings(commonSettings) - .settings( - unmanagedBase := baseDirectory.value / "libs", - libraryDependencies ++= Seq( - "com.google.inject" % "guice" % "4.2.0", - "io.spray" %% "spray-json" % "1.3.4", - "com.mixpanel" % "mixpanel-java" % "1.4.4", - "net.codingwell" %% "scala-guice" % "4.2.0", - "com.netaporter" %% "scala-uri" % "0.4.16", - "com.github.pathikrit" %% "better-files" % "3.4.0" - ) - ) lazy val backlogMigrationImporter = (project in file("modules/importer")) .settings(commonSettings) @@ -56,7 +38,8 @@ lazy val root = (project in file(".")) "io.monix" %% "monix-reactive" % monixVersion, "io.monix" %% "monix-execution" % monixVersion, "io.monix" %% "monix-eval" % monixVersion, - "org.apache.commons" % "commons-csv" % "1.5" + "org.apache.commons" % "commons-csv" % "1.5", + "org.scalatest" %% "scalatest" % "3.0.5" % Test ) }, assemblyJarName in assembly := { diff --git a/modules/common b/modules/common index 4f0e10b..8390ca6 160000 --- a/modules/common +++ b/modules/common @@ -1 +1 @@ -Subproject commit 4f0e10bfa980f58eb37ba5f264c74a86bcc83151 +Subproject commit 8390ca6461ccb680bcf817e71bfa75c119c7f3e7 diff --git a/modules/importer b/modules/importer index 548ba61..1542e95 160000 --- a/modules/importer +++ b/modules/importer @@ -1 +1 @@ -Subproject commit 548ba61070b8617915294f2e4b17afa83b9f015f +Subproject commit 1542e95ac89e79e178f719a7a416f87ae9460b61 diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index 330aa03..c21f781 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -1,14 +1,13 @@ -app { +application { name = "Backlog Migration for CybozuLive" - version = "0.1.0b3" - title = ${app.name} ${app.version} (c) nulab.inc - fileName = backlog-migration-cybozulive-${app.version}.jar + version = "0.2.0b1" + title = ${application.name} ${application.version} (c) nulab.inc + fileName = backlog-migration-cybozulive-${application.version}.jar language = default + product = "cybozulive" + backlog4jVersion = "2.3.0" dataDirectory = "./backlog-migration" - mixpanel { - token = "5be8b628b7103858164142d02cb38347" - backlogtoolToken = "0512c52e553b9283143bed99e61c27e4" - product = "cybozulive" - } + export-limit-at-once = 100 + akka.mailbox-pool = 100 } diff --git a/src/main/resources/messages.txt b/src/main/resources/messages.txt index 5479a27..f198008 100644 --- a/src/main/resources/messages.txt +++ b/src/main/resources/messages.txt @@ -97,6 +97,9 @@ common.filter=Filter common.importOnly=Only Import common.fitIssueKey=Fit Issue Key +# CLI +cli.error.unknown=Unknown error + # Message message.exporting=Exporting message.exported=Exported diff --git a/src/main/resources/messages_ja.txt b/src/main/resources/messages_ja.txt index fd8d353..dac451b 100644 --- a/src/main/resources/messages_ja.txt +++ b/src/main/resources/messages_ja.txt @@ -97,6 +97,8 @@ common.filter=フィルター common.importOnly=インポートのみ実行 common.fitIssueKey=課題キーを一致させる +# CLI +cli.error.unknown=予期しないエラーが発生しました。 # Message message.exporting=エクスポートしています... diff --git a/src/main/scala/com/nulabinc/backlog/c2b/App.scala b/src/main/scala/com/nulabinc/backlog/c2b/App.scala index f4cedaa..e8d13a5 100644 --- a/src/main/scala/com/nulabinc/backlog/c2b/App.scala +++ b/src/main/scala/com/nulabinc/backlog/c2b/App.scala @@ -5,7 +5,6 @@ import java.util.Locale import akka.actor.ActorSystem import akka.stream.ActorMaterializer import com.github.chaabaj.backlog4s.apis.AllApi -import com.github.chaabaj.backlog4s.datas.UserT import com.github.chaabaj.backlog4s.interpreters.AkkaHttpInterpret import com.nulabinc.backlog.c2b.Config._ import com.nulabinc.backlog.c2b.core._ @@ -17,7 +16,7 @@ import com.nulabinc.backlog.c2b.persistence.interpreters.file.LocalStorageInterp import com.nulabinc.backlog.c2b.persistence.interpreters.sqlite.SQLiteInterpreter import com.nulabinc.backlog.c2b.services._ import com.nulabinc.backlog.migration.common.conf.BacklogApiConfiguration -import com.nulabinc.backlog.migration.common.utils.{ConsoleOut, DateUtil, TrackingData} +import com.nulabinc.backlog.migration.common.utils.ConsoleOut import com.osinka.i18n.Messages import monix.eval.Task import monix.execution.Scheduler @@ -131,7 +130,6 @@ object App extends Logger { } def `import`(config: Config, language: String): AppProgram[Unit] = { - import com.github.chaabaj.backlog4s.dsl.syntax._ val backlogApi = AllApi.accessKey(s"${config.backlogUrl}/api/v2/", config.backlogKey) val backlogApiConfiguration = BacklogApiConfiguration( @@ -155,27 +153,6 @@ object App extends Logger { mappingContext <- MappingFiles.createMappingContext() _ <- BacklogExport.all(config)(mappingContext) _ <- AppDSL.`import`(backlogApiConfiguration) - // MixPanel - environment <- AppDSL.getBacklogEnvironment(backlogApiConfiguration) - backlogToolEnvNames = Seq("backlogtool", "us-6") - token = if (backlogToolEnvNames.contains(environment._2)) - Config.App.Mixpanel.backlogtoolToken - else - Config.App.Mixpanel.token - user <- AppDSL.fromBacklog(backlogApi.userApi.byId(UserT.myself).orFail) - space <- AppDSL.fromBacklog(backlogApi.spaceApi.current.orFail) - data = TrackingData( - product = Config.App.Mixpanel.product, - spaceId = environment._1, - envname = environment._2, - userId = user.id.value, - srcUrl = "", - dstUrl = config.backlogUrl, - srcProjectKey = "", - dstProjectKey = config.projectKey, - srcSpaceCreated = "", - dstSpaceCreated = DateUtil.isoFormat(space.created.toDate)) - _ <- AppDSL.sendTrackingData(token, data) } yield () } diff --git a/src/main/scala/com/nulabinc/backlog/c2b/Config.scala b/src/main/scala/com/nulabinc/backlog/c2b/Config.scala index 2ac9a98..5aca03a 100644 --- a/src/main/scala/com/nulabinc/backlog/c2b/Config.scala +++ b/src/main/scala/com/nulabinc/backlog/c2b/Config.scala @@ -30,17 +30,17 @@ object Config { private val config = ConfigFactory.load() object App { - private val appConfig = config.getConfig("app") + private val applicationConfig = config.getConfig("application") - val name: String = appConfig.getString("name") - val version: String = appConfig.getString("version") - val title: String = appConfig.getString("title") - val fileName: String = appConfig.getString("fileName") - val language: String = appConfig.getString("language") - val dataDirectory: String = appConfig.getString("dataDirectory") + val name: String = applicationConfig.getString("name") + val version: String = applicationConfig.getString("version") + val title: String = applicationConfig.getString("title") + val fileName: String = applicationConfig.getString("fileName") + val language: String = applicationConfig.getString("language") + val dataDirectory: String = applicationConfig.getString("dataDirectory") object Mixpanel { - private val mixpanelConfig = appConfig.getConfig("mixpanel") + private val mixpanelConfig = applicationConfig.getConfig("mixpanel") val token: String = mixpanelConfig.getString("token") val backlogtoolToken: String = mixpanelConfig.getString("backlogtoolToken") diff --git a/src/main/scala/com/nulabinc/backlog/c2b/interpreters/AppInterpreter.scala b/src/main/scala/com/nulabinc/backlog/c2b/interpreters/AppInterpreter.scala index c579dba..2db9571 100644 --- a/src/main/scala/com/nulabinc/backlog/c2b/interpreters/AppInterpreter.scala +++ b/src/main/scala/com/nulabinc/backlog/c2b/interpreters/AppInterpreter.scala @@ -15,10 +15,8 @@ import com.nulabinc.backlog.c2b.persistence.dsl.StorageDSL.StorageProgram import com.nulabinc.backlog.c2b.persistence.dsl.StoreDSL.StoreProgram import com.nulabinc.backlog.c2b.persistence.interpreters._ import com.nulabinc.backlog.migration.common.conf.BacklogApiConfiguration -import com.nulabinc.backlog.migration.common.utils.{IOUtil, MixpanelUtil, TrackingData} +import com.nulabinc.backlog.migration.common.utils.IOUtil import com.nulabinc.backlog.migration.importer.core.Boot -import com.nulabinc.backlog4j.BacklogClientFactory -import com.nulabinc.backlog4j.conf.BacklogPackageConfigure import monix.eval.Task import monix.execution.Scheduler import monix.reactive.{Consumer, Observable} @@ -41,8 +39,6 @@ private case class FromTask[A](task: Task[A]) extends AppADT[Try[A]] case class Export(file: File, content: String) extends AppADT[File] case class Import(backlogApiConfiguration: BacklogApiConfiguration) extends AppADT[PrintStream] -case class SendTrackingData(token: String, data: TrackingData) extends AppADT[Unit] -case class GetBacklogEnvironment(backlogApiConfiguration: BacklogApiConfiguration) extends AppADT[(Long, String)] object AppDSL { @@ -93,12 +89,6 @@ object AppDSL { def `import`(backlogApiConfiguration: BacklogApiConfiguration): AppProgram[PrintStream] = Free.liftF(Import(backlogApiConfiguration)) - - def sendTrackingData(token: String, trackingData: TrackingData): AppProgram[Unit] = - Free.liftF(SendTrackingData(token, trackingData)) - - def getBacklogEnvironment(backlogApiConfiguration: BacklogApiConfiguration): AppProgram[(Long, String)] = - Free.liftF(GetBacklogEnvironment(backlogApiConfiguration)) } class AppInterpreter(backlogInterpreter: BacklogHttpInterpret[Future], @@ -148,18 +138,6 @@ class AppInterpreter(backlogInterpreter: BacklogHttpInterpret[Future], } ) - def sendTrackingData(token: String, trackingData: TrackingData): Task[Unit] = Task { - MixpanelUtil.track(token = token, data = trackingData) - } - - def getBacklogEnvironment(backlogApiConfiguration: BacklogApiConfiguration): Task[(Long, String)] = Task { - val backlogPackageConfigure = new BacklogPackageConfigure(backlogApiConfiguration.url) - val configure = backlogPackageConfigure.apiKey(backlogApiConfiguration.key) - val backlogClient = new BacklogClientFactory(configure).newClient() - val environment = backlogClient.getEnvironment - (environment.getSpaceId, environment.getName) - } - def terminate(): Task[Unit] = Task.deferFuture { backlogInterpreter match { case akkaInterpreter: AkkaHttpInterpret => @@ -192,7 +170,5 @@ class AppInterpreter(backlogInterpreter: BacklogHttpInterpret[Future], case ConsumeStream(prgs) => consumeStream(prgs) case Export(file, content) => export(file, content) case Import(config) => `import`(config) - case SendTrackingData(token, trackingData) => sendTrackingData(token, trackingData) - case GetBacklogEnvironment(config) => getBacklogEnvironment(config) } } diff --git a/src/main/scala/com/nulabinc/backlog/c2b/services/BacklogExport.scala b/src/main/scala/com/nulabinc/backlog/c2b/services/BacklogExport.scala index 7ada1c0..afef1d4 100644 --- a/src/main/scala/com/nulabinc/backlog/c2b/services/BacklogExport.scala +++ b/src/main/scala/com/nulabinc/backlog/c2b/services/BacklogExport.scala @@ -229,6 +229,9 @@ object BacklogExport extends Logger { event.copy(id = newId, comments = comments) }.map { event => issueConverter.from(event, issueType) match { + case Right(backlogIssue) if backlogIssue.summary.value.isEmpty => + log.warn(s"Event title is empty. Ignored. Id: $eventId Memo: ${event.memo}") + AppDSL.pure(()) case Right(backlogIssue) => for { _ <- exportIssue(paths, backlogIssue, event.startDateTime, index, total)