{"id":256,"date":"2014-07-10T15:41:35","date_gmt":"2014-07-10T15:41:35","guid":{"rendered":"http:\/\/blogs.law.harvard.edu\/rprasad\/?p=256"},"modified":"2014-07-10T17:36:38","modified_gmt":"2014-07-10T17:36:38","slug":"moving-from-redmine-to-github-issues","status":"publish","type":"post","link":"https:\/\/archive.blogs.harvard.edu\/rprasad\/2014\/07\/10\/moving-from-redmine-to-github-issues\/","title":{"rendered":"Moving from Redmine to GitHub Issues"},"content":{"rendered":"<p>Recently, we moved from <a href=\"http:\/\/www.redmine.org\/\">Redmine<\/a> to <a href=\"https:\/\/github.com\/IQSS\/dataverse\/issues\">GitHub Issues<\/a> for sake of transparency\/consolidation.<br \/>\n<a href=\"http:\/\/blogs.law.harvard.edu\/rprasad\/files\/2014\/07\/Issues_\u00b7_IQSS_dataverse.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/blogs.law.harvard.edu\/rprasad\/files\/2014\/07\/Issues_\u00b7_IQSS_dataverse-150x150.png\" alt=\"Issues_\u00b7_IQSS_dataverse\" width=\"150\" height=\"150\" class=\"alignright size-thumbnail wp-image-266\" \/><\/a><br \/>\nTaking advantage of the RedMine and GitHub APIs, we wrote an unpolished\/try-to-get-the-job-done-by-wednesday python program <a href=\"https:\/\/github.com\/iqss\/redmine2github\">redmine2github<\/a> to make the switch.  The process was roughly as follows:<\/p>\n<ol>\n<li><a href=\"https:\/\/github.com\/IQSS\/redmine2github#1-download-your-open-redmine-issues\">Copy each redmine ticket to an individual JSON file<\/a>.  Information included:\n<ul>\n<li>Comments (journals)<\/li>\n<li>Relations<\/li>\n<li>Child Tickets<\/li>\n<li>etc<\/li>\n<\/ul>\n<\/li>\n<li>Manually created the following mappings. (All mappings are optional with the program)\n<ul>\n<li><a href=\"https:\/\/github.com\/IQSS\/redmine2github\/blob\/master\/src\/settings\/sample_user_map.csv\">Name Map<\/a> between Redmine and GitHub users.  This allows translation of Issue creators, Commenters, and Assignees<\/li>\n<li><a href=\"https:\/\/github.com\/IQSS\/redmine2github\/blob\/master\/src\/settings\/sample_label_map2.csv\">Label Map<\/a> to translate Redmine attributes to GitHub labels.  Note: the first column, &#8220;redmine_type&#8221; is not used by the program&#8211;it&#8217;s a reference for humans.  The file\/program are &#8220;dumb&#8221; and don&#8217;t look for name clashes in the &#8220;redmine_name&#8221; column.\n<ul>\n<li>Note: By repeating columns 3 and 4, 2 or more &#8220;redmine_name&#8221;s may be translated to the same label.  In the <a href=\"https:\/\/github.com\/IQSS\/redmine2github\/blob\/master\/src\/settings\/sample_label_map2.csv\">sample file<\/a>, the first three Redmine Names: &#8220;New&#8221;, &#8220;In Review&#8221;, and &#8220;In Design&#8221; are all moved to the label &#8220;Status: Design&#8221;<\/li>\n<li><strong>IMPORTANT<\/strong>: If a label map is used, any &#8220;redmine_name&#8221; not on the map will be ignored.  If a label map is NOT used, the &#8220;redmine_names&#8221; will be made into labels&#8211;but with no color attribute.<\/li>\n<\/ul>\n<\/li>\n<li><a href=\"https:\/\/github.com\/IQSS\/redmine2github\/blob\/master\/src\/settings\/sample_milestone_map2.csv\">Milestone Map<\/a> to translate Redmine &#8220;fixed_version&#8221; to a GitHub milestone. This works similarly to the Label Map with an import distinction below:\n<ul>\n<li><strong>IMPORTANT<\/strong>: Differently from the label map, any Redmine &#8220;fixed_version&#8221;s not found in the milestone map, will be created in GitHub.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<li>Ran the <a href=\"https:\/\/github.com\/IQSS\/redmine2github#quick-script\">issue migration (mm.migrate_issues())<\/a> several times on newly created test repositories&#8211;that were then deleted.  This helped work out bugs, etc.  <\/li>\n<li>Ran the issue migration against the real repository (this will &#8220;spam&#8221; users if you use a name map)\n<ul>\n<li>The migration creates an issue mapping file with JSON that maps { redmine issue number : github issue number }<\/li>\n<li>Part of the mapping file:<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<pre><code class=\"javascript\">{\"4096\": 647, \"4097\": 648, \"4098\": 649, \"4100\": 650, \"4101\": 651, \"4102\": 652, \"4103\": 653, \"4104\": 654, \"4105\": 655, \"4106\": 656, \"4107\": 657, \"4108\": 658, \"4109\": 659, \"4110\": 660, \"4111\": 661, \"4112\": 662, \"4113\": 663, \"4114\": 664, \"4115\": 665, \"4116\": 666, \"4117\": 667, \"4118\": 668, \"4119\": 669, \"4120\": 670, \"4121\": 671, \"4122\": 672, \"4123\": 673, \"4124\": 674, \"4125\": 675, \"4126\": 676, \"4127\": 677, \"4128\": 678, \"4129\": 679, \"4130\": 680, \"4131\": 681, \"4132\": 682, \"4133\": 683, \"4134\": 684, \"4135\": 685, \"4136\": 686, \"4137\": 687, \"4138\": 688, \"4139\": 689, \"4140\": 690, \"4141\": 691, \"4142\": 692, \"4146\": 693, \"4148\": 694, \"4149\": 695, \"4150\": 696, \"4151\": 697, \"4153\": 698, \"4154\": 699, \"4156\": 700, \"4157\": 701, \"4160\": 702, ....}\n<\/code><\/pre>\n<ol>\n<li>Run <a href=\"https:\/\/github.com\/IQSS\/redmine2github\/blob\/master\/src\/github_issues\/migration_manager.py#L223\">migration part #2 (#mm.migrate_related_tickets())<\/a> which updates the GitHub Issue descriptions with links to related and child tickets as defined in Redmine.\n<ul>\n<li>The result of the related\/child tickets looks something like:<br \/>\n<a href=\"http:\/\/blogs.law.harvard.edu\/rprasad\/files\/2014\/07\/Permissions_\u00b7_Issue__27_\u00b7_IQSS_dataverse.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/blogs.law.harvard.edu\/rprasad\/files\/2014\/07\/Permissions_\u00b7_Issue__27_\u00b7_IQSS_dataverse-150x150.png\" alt=\"Permissions_\u00b7_Issue__27_\u00b7_IQSS_dataverse\" width=\"150\" height=\"150\" class=\"size-thumbnail wp-image-285\" \/><\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"https:\/\/github.com\/IQSS\/redmine2github\/blob\/master\/src\/redmine_ticket\/redmine_issue_updater.py#L138\">Run a script to update the Redmine tickets<\/a> with a link to the new GitHub Issue.<\/li>\n<\/ol>\n<p>The final migration, runs 1&amp;2, took about 7 minutes for 700+ tickets.  The results:<\/p>\n<p><a href=\"http:\/\/blogs.law.harvard.edu\/rprasad\/files\/2014\/07\/Issues_\u00b7_IQSS_dataverse.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/blogs.law.harvard.edu\/rprasad\/files\/2014\/07\/Issues_\u00b7_IQSS_dataverse-1024x731.png\" alt=\"Issues_\u00b7_IQSS_dataverse\" width=\"584\" height=\"416\" class=\"alignleft size-large wp-image-266\" srcset=\"https:\/\/archive.blogs.harvard.edu\/rprasad\/files\/2014\/07\/Issues_\u00b7_IQSS_dataverse-1024x731.png 1024w, https:\/\/archive.blogs.harvard.edu\/rprasad\/files\/2014\/07\/Issues_\u00b7_IQSS_dataverse-300x214.png 300w, https:\/\/archive.blogs.harvard.edu\/rprasad\/files\/2014\/07\/Issues_\u00b7_IQSS_dataverse.png 1149w\" sizes=\"auto, (max-width: 584px) 100vw, 584px\" \/><\/a><\/p>\n<p>Overall, it worked fine.  We have tweaked the labels since the initial mapping.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Recently, we moved from Redmine to GitHub Issues for sake of transparency\/consolidation. Taking advantage of the RedMine and GitHub APIs, we wrote an unpolished\/try-to-get-the-job-done-by-wednesday python program redmine2github to make the switch. The process was roughly as follows: Copy each redmine ticket to an individual JSON file. Information included: Comments (journals) Relations Child Tickets etc Manually &hellip; <a href=\"https:\/\/archive.blogs.harvard.edu\/rprasad\/2014\/07\/10\/moving-from-redmine-to-github-issues\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Moving from Redmine to GitHub Issues<\/span><\/a><\/p>\n","protected":false},"author":3875,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[1],"tags":[],"class_list":["post-256","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p4JC3p-48","_links":{"self":[{"href":"https:\/\/archive.blogs.harvard.edu\/rprasad\/wp-json\/wp\/v2\/posts\/256","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/archive.blogs.harvard.edu\/rprasad\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/archive.blogs.harvard.edu\/rprasad\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/rprasad\/wp-json\/wp\/v2\/users\/3875"}],"replies":[{"embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/rprasad\/wp-json\/wp\/v2\/comments?post=256"}],"version-history":[{"count":27,"href":"https:\/\/archive.blogs.harvard.edu\/rprasad\/wp-json\/wp\/v2\/posts\/256\/revisions"}],"predecessor-version":[{"id":289,"href":"https:\/\/archive.blogs.harvard.edu\/rprasad\/wp-json\/wp\/v2\/posts\/256\/revisions\/289"}],"wp:attachment":[{"href":"https:\/\/archive.blogs.harvard.edu\/rprasad\/wp-json\/wp\/v2\/media?parent=256"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/rprasad\/wp-json\/wp\/v2\/categories?post=256"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/rprasad\/wp-json\/wp\/v2\/tags?post=256"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}