Blog

So gelingt die Migration von Redmine zu Jira

JUN 25, 2020

Jira hat sich zum Branchenstandard für die Projektverwaltung entwickelt und bietet bei der Konfiguration von Workflows für einzelne Projekte deutlich mehr Möglichkeiten als Redmine. Jira unterstützt Agile Entwicklung mit Scrum vollständig, während Redmine nur begrenzte Unterstützung für verschiedene Arbeitsweisen bietet. Doch wie gelingt der Wechsel zu Jira, wenn ihr derzeit Redmine nutzt?

Mads Jensen

Mads works as a consultant at Eficode in Denmark. He is passionate about automation and testing, and in general to get the most of the tools he uses. He occasionally contributes to open-source projects, in particular to the Django web framework. He likes riding his bike for both sport and transportation and enjoys watching movies.

1. Warum von Redmine zu Jira migrieren?

Jira bietet einige Vorteile gegenüber Redmine, die auch in Atlassians eigenem Vergleich der beiden Tools hervorgehoben werden:

  • Jira unterstützt Scrum vollständig und umfasst Boards sowie Statistiken für Sprints. Sprints können eine beliebige Anzahl von Wochen dauern, und die Auslastung jedes Teammitglieds in jedem Sprint ist leicht erkennbar.

  • Workflows lassen sich einfach an die Anforderungen des Unternehmens anpassen, beispielsweise sodass ein Issue alle verschiedenen Phasen durchlaufen muss, bevor es geschlossen werden kann. Anders als bei Redmine ist es mit Jira zudem möglich, einen Workflow für ein bestimmtes Projekt zu konfigurieren. In Redmine werden Workflow und Status projektübergreifend global geteilt.

  • Workflows unterstützen Validatoren, Bedingungen und Post-Funktionen, mit denen sich Prozesse automatisieren lassen. Die Standardinstallation von Jira bietet einige Optionen für Bedingungen, die auf einen Workflow angewendet werden können.

  • Boards, die den Status von Issues anzeigen, lassen sich sehr detailliert anpassen. In Jira können Abfragen konfiguriert werden, die für die täglichen Scrum Stand-ups hilfreich sind. So lässt sich leicht erkennen, woran einzelne Teammitglieder am Vortag gearbeitet haben. In Redmine müssen diese Filter jeden Tag neu eingerichtet werden.

  • Feldkonfigurationsschemata sind sehr flexibel und können verwendet werden, um festzulegen, welche Felder in einem bestimmten Projekt und für bestimmte Issue-Typen Pflichtfelder sind.

Redmine unterstützt Scrum nicht vollständig und ist stärker auf eine Kanban-Arbeitsweise ausgerichtet. Redmine kennt keine Epics, sondern Stories, Bugs und Sub-Tasks. Jira umfasst Epics, Stories, Sub-Tasks und Bugs.

Darüber hinaus bietet Jira zwei Board-Typen: einen für Scrum und einen für Kanban. Beide Boards können mit Abfragen konfiguriert werden, damit häufige Suchen nicht wiederholt werden müssen.

Redmine hat einige Vorteile

Redmine bietet ein Zeiterfassungsmodul mit einer höheren Detailtiefe als Jira standardmäßig bietet. Zusätzlich zu den Feldern für aufgewendete Zeit und Kommentare in Jira gibt es in Redmine ein weiteres Feld für Aktivitäten.

Redmine ist außerdem Open-Source-Software und erfordert daher keine Lizenzen. Das kann ein Grund sein, bei Redmine zu bleiben, da das Projekt weiterhin aktiv gepflegt wird.

2. Daten exportieren und konvertieren

Für den Wechsel von Redmine zu Jira müssen alle aktuellen Arbeiten von einem System in das andere migriert werden. Die Migration umfasst folgende Schritte:

  1. Daten exportieren

  2. Daten konvertieren

  3. Daten importieren

  4. Darstellung in Jira anpassen

Für diese Migration gibt es mehrere Möglichkeiten. Unabhängig von der gewählten Methode sollte der Schritt zur Anpassung der Darstellung jedoch weitgehend gleich sein.

Vor Jira 8.4

Bis einschließlich Jira 8.3 bietet Atlassian den Import aus verschiedenen Drittanbieter-Tools wie Redmine, Trac oder Trello an. Diese Tools sind in der Standardinstallation von Jira enthalten. Diese Option übernimmt im Wesentlichen die ersten drei oben genannten Schritte der Migration.

jira-import-tools

Nach Eingabe der Zugangsdaten werdet ihr gefragt, welche Projekte importiert werden sollen und in welche Jira-Projekte, wie benutzerdefinierte Felder zugeordnet werden sollen und wie Verknüpfungen erstellt werden sollen.

jira-import-map-links

Leider hat Atlassian die Unterstützung für die automatischen Import-Plugins ab Jira 8.4 eingestellt. Das bedeutet, dass ein Import nur noch per CSV oder JSON möglich ist.

Wir haben uns für die automatisierten Tools entschieden. Der Importer übernimmt Aufgaben, die beim JSON-Import zusätzliche Überlegungen erfordern würden, ist jedoch weniger flexibel.

Beim Erstellen eines Projekts in Jira muss eine Projektvorlage ausgewählt werden, die den Workflow und die verfügbaren Status beschreibt. Für die Migration haben wir eine eigene Projektvorlage verwendet, um die Status aus Redmine in Jira abzubilden.

In Redmine-Projekten standen mehr Status zur Auswahl als in den standardmäßigen Projektvorlagen von Jira. Daher mussten wir Jira so anpassen, dass die Status aus Redmine abgebildet wurden.

jira-workflow-redmine

In unserem Fall mussten wir eine Projektvorlage anpassen, um die Status korrekt abzubilden. Die Projektvorlagen lassen sich so anpassen, dass sie Status enthalten, zu denen keine Übergänge möglich sind, die aber für die Nachbearbeitung benötigt werden. So können Teams individuell auswählen, in welchen Status Tickets verschoben werden sollen. Mehrere Status in Redmine konnten einem Status in Jira zugeordnet werden. Da dies jedoch Annahmen für andere bedeutet hätte, entschieden wir uns, einige Status vorübergehend beizubehalten. Einige gelb markierte Status werden für denselben Zweck verwendet. Möglicherweise sollten Tickets mit dem Status „In Test“ eigentlich den Status „In Progress“ haben. Falls ja, lassen sie sich einfach gesammelt verschieben. Hätten wir während des Imports Annahmen getroffen, wäre das nicht möglich gewesen.

Probleme mit dem Importer

Bei jedem Import eines neuen Projekts wird ein neues Custom Field erstellt, das eine Zuordnung vom alten System zu Jira herstellt. Dieses Feld verhindert, dass dieselben Issues erneut importiert werden. Es bedeutet aber auch, dass diese Felder zusätzlich zusammengeführt werden müssen. ScriptRunner bietet eine Funktion, mit der sich solche Felder anhand eines vordefinierten Filters in einem einzigen Custom Field zusammenführen lassen. Je mehr Projekte ihr importiert, desto länger wird die Liste der Custom Fields – und desto leichter verliert man den Überblick. In Jira könnt ihr anpassen, wie die Daten von Issues dargestellt werden. Wenn ihr dies auf ein einziges Feld beschränkt, lässt sich auch der Screen einfacher anpassen. Außerdem könnt ihr den betroffenen Teams so leicht Anweisungen dazu geben, wie sie nach alten Issues suchen können. Beachtet, dass beim Hinzufügen eines Felds zu einem Ansichts-Screen Name und Wert nur angezeigt werden, wenn ein Wert vorhanden ist.

Die Resolution-Status wurden nicht korrekt zugeordnet. Das Migrationstool übertrug einen Resolution-Status „1“ nach Jira, der nicht beschreibt, wie das Issue gelöst wurde. Dem Kunden waren die bereits gelösten alten Issues nicht besonders wichtig. Daher wurde der Resolution-Status als Option aus dem Resolution-Screen entfernt. So wird verhindert, dass neue Tickets mit diesem bedeutungslosen Resolution-Status gelöst werden. In einem Workflow lassen sich für einen Übergang bestimmte Eigenschaften festlegen, die sich auf den Resolution-Screen auswirken. Die Projekte enthalten diesen ungewöhnlichen Resolution-Status zwar weiterhin, neue Tickets können diesen Wert jedoch nicht als Resolution-Status festlegen.

Die vom Importer vergebenen Issue-Nummern, zum Beispiel PROJ-1234, sind zufällig. Steigende Issue-Nummern spiegeln daher nicht das Erstellungsdatum eines Issues wider.

Das Importer-Tool importiert nicht alle relevanten Daten. Für Redmine-Projekte mit Unterprojekten erstellten wir in Jira eine Komponente mit demselben Namen wie das jeweilige Unterprojekt in Redmine. Komponenten in Jira sind flexibler als Unterprojekte in Redmine, da sie einen Standardverantwortlichen für Issues haben können. In unserem Fall mussten wir für Issues die Werte für Story Points, die Fix Versions (auch Release genannt) sowie für Projekte mit Unterprojekten die Komponente festlegen. Wir durchliefen einfach eine Liste relevanter Parameter und führten dann für jedes Issue REST-API-Aufrufe aus. Die netrc-Datei enthält Anmeldedaten zur Authentifizierung des Benutzers bei Jira.

In Jira gibt es mehrere Custom Fields, die gesetzt werden können, wenn für ein Projekt der entsprechende Kontext konfiguriert wurde. Das Custom Field 10006 ist für Story Points vorgesehen. Die IDs der Custom Fields findet ihr in der Jira-Administration. Beachtet: Wenn ihr für eure Migration weitere Custom Fields in Jira verwenden möchtet, müsst ihr für das jeweilige Feld einen Kontext konfigurieren, damit ihr es für ein Projekt setzen könnt. Andernfalls schlägt der REST-API-Aufruf mit einem Hinweis fehl, dass das Feld für das Issue nicht gesetzt werden kann.

Jira 8.4 und höher

Atlassian hat angekündigt, dass die Importer-Plugins ab Jira 8.4 nicht mehr verfügbar sind. JSON- oder CSV-Dateien können jedoch weiterhin importiert werden. Das bedeutet natürlich mehr Aufwand, da alle relevanten Daten über die REST API des Tools extrahiert werden müssen, von dem ihr migriert. Einige Tools stellen möglicherweise keine REST API bereit, oder die REST-Endpunkte liefern nicht alle Daten, die ihr abrufen möchtet. Wenn ihr Jira 8.4 oder höher nutzt und von einem alten System migrieren möchtet, findet ihr bei Atlassian eine ausführliche Dokumentation zum Format, das für den Import verwendet werden kann. CSV ist wahrscheinlich nur dann eine gute Wahl, wenn der Datensatz recht klein ist und nur sehr grundlegende Informationen zu den Issues enthält. CSV ist deutlich weniger umfangreich als JSON, da es nur eine Zeile pro Issue gibt. Mit JSON lassen sich die Daten leichter überprüfen und mit Tools wie jq abfragen. Das vereinfacht die Bearbeitung und Prüfung erheblich. 

Redmine verfügt über eine REST API, die das Extrahieren der erforderlichen Daten unterstützt. Dazu gehören Benutzer, Issues mit Metadaten (Kommentare, Beziehungen, Releases) und Projekte. Einige Daten lassen sich nicht über die REST API extrahieren, beispielsweise die Release-Daten eines Projekts. Sie müssen manuell über die Redmine-Oberfläche extrahiert werden.

Wir hatten kein fertiges Konvertierungsskript. Allerdings mussten wir Python-Code schreiben, der JSON ausgibt, um die Sub-Task-Links korrekt zu importieren. Diesen um Benutzer, Projekte und Issues – einschließlich Anhängen – zu erweitern, scheint machbar zu sein. Wir verwerfen die copied_to-Links, da diese bereits vom Importer-Plugin verarbeitet wurden.

Das Skript verwendet f-strings, die mit Python 3.6 eingeführt wurden. Das Skript kann wie folgt aufgerufen werden:python import-links.py <Jira project key>

Darstellung in Jira anpassen

Obwohl wir die Daten mithilfe der Importer-Plugins importiert und konvertiert haben, gibt es nach der Migration einige Punkte zu beachten. In Jira gibt es für die verschiedenen Issue-Typen Screens, die entweder für ein einzelnes Projekt gelten oder von mehreren Projekten gemeinsam genutzt werden können. Für jeden Issue-Typ gibt es drei Screens:

  • Ein Ansichts-Screen

  • Ein Erstellungs-Screen

  • Ein Aktualisierungs-Screen

Für die Ansicht sollte die Redmine-Issue-ID enthalten sein. Umgekehrt sollte das externe Issue in den Masken zum Aktualisieren und Erstellen ausgeschlossen werden. Die Attribute „Komponente“ und „Fix-Version“ sind für alle drei Masken bereits standardmäßig konfiguriert.

Boards gibt es in Redmine nicht. Deshalb wurden für die verschiedenen Projekte zwei Boards erstellt: ein Scrum-Board und ein Kanban-Board. Die Boards sind mit Spalten für „Unentschieden“ (benötigt weitere Informationen), „To Do“, „In Bearbeitung“, „Verifizierung“ und „Erledigt“ konfiguriert. Der Administrator kann festlegen, welche Issues in den verschiedenen Spalten angezeigt werden. Zusätzlich kann er Schnellfilter hinzufügen. Wir haben einige Schnellfilter eingerichtet, um Issues für die verschiedenen Teammitglieder und Komponenten einzubeziehen, da Jira die Komponenten nicht auf der linken Seite des Backlogs auflistet. Es gibt einen Tab für Epics und Versionen, sodass sich einfach nach diesen Werten filtern und Issues in einen Sprint verschieben lassen. Komponenten hätten unterhalb von Epics angezeigt werden sollen, an der Stelle der Markierung.

missing-components-backlog-1

3. Probleme mit der Standardkonfiguration? So haben wir sie gelöst.

Wir haben die Migration mit Importer-Plugins durchgeführt. Unabhängig von der Methode gibt es jedoch immer einige Punkte zu beachten.

Welche Daten möchtet ihr importieren?

Die REST API ermöglicht nicht die Bearbeitung aller Daten in Jira. So kann beispielsweise das Abschlussdatum eines Sprints nicht über die REST API festgelegt werden, wodurch die Sprint-Statistiken verloren gehen. Mit der Erweiterung ScriptRunner ist dies jedoch möglich. Wenn diese Erweiterung in eurem System nicht verfügbar ist, müsst ihr damit zurechtkommen.

Kommentare werden möglicherweise nicht dem richtigen Benutzer zugeordnet

Beim Import mit dem Plugin-Tool werden Benutzer aus den betroffenen Projekten importiert. Hat ein Benutzer einen Kommentar geschrieben, ordnet Jira ihn korrekt zu. Wird ein Benutzer jedoch aufgrund eines Problems nicht importiert – wahrscheinlich, weil er deaktiviert wurde –, wird der Kommentar mit der Person als Autor erstellt, die den Importer in Jira ausführt. In diesen Fällen war ScriptRunner hilfreich, um den Kommentar zu löschen und mit dem richtigen Autor neu zu erstellen.

Falls ScriptRunner nicht verfügbar ist, könnt ihr den Importer erneut ausführen, nachdem ihr die Issues gelöscht habt, bei denen die Person, die den Importer ausgeführt hat, als Kommentarautor eingetragen ist. Der Benutzer muss vor dem erneuten Ausführen des Importers manuell in Jira mit demselben Benutzernamen angelegt werden. Denkt daran, dass der Benutzer inaktiv sein sollte und eine beliebige E-Mail-Adresse verwendet werden kann. Der Importer nutzt die externe Issue-ID, um festzustellen, welche Issues bereits importiert wurden. Das Custom Field kann während der Migration nicht umbenannt werden, da ein neues Custom Field erstellt und alle Issues importiert würden. Dadurch würden sämtliche Informationen dupliziert.

Fehler in den Importer-Plugins

Wenn Sub-Tasks in Jira erfasste Arbeitszeit enthalten, fasst die übergeordnete Story diese Werte zusammen. So lässt sich leicht erkennen, wie viel Zeit insgesamt aufgewendet wurde. Das Problem war, dass der Importer die Sub-Tasks nicht korrekt verknüpfte und dadurch die Berechnung der aufgewendeten Zeit verfälschte.

Um dieses Problem zu lösen, haben wir ein kleines Python-Skript geschrieben, das JSON ausgibt, um die Verknüpfungen korrekt zu importieren. Das Python-Skript ist oben dargestellt. Diese Python-Funktion lädt alle Beziehungstypen eines Redmine-Issues, zum Beispiel copied_to, das den Klonen- oder Duplikatbeziehungen in Jira entspricht.

Einschränkungen der Redmine REST API

Redmine stellt die Daten sowie den Offen-/Geschlossen-Status eines Releases nicht über die REST API bereit. Die Daten waren nur über Webseiten verfügbar. Deshalb haben wir außerdem ein kleines Python-Skript geschrieben, das die Daten aus den HTML-Seiten extrahiert, damit sie über die REST API festgelegt werden konnten.

Die Importer-Plugins verhalten sich nicht optimal.

Wir haben einige Probleme mit den Importer-Plugins erlebt, die im obigen Text hervorgehoben werden. Für die meisten betroffenen Teams bestand das Ziel darin, in Jira arbeiten zu können. Daher konnten historische Daten etwas anders dargestellt werden als im migrierten Tool.

Skripte zum Extrahieren von Daten aus Jira 8.4 (und auch Jira 7) und späteren Versionen zu schreiben, ist eine gute Investition, weil sich damit besser steuern lässt, wie Daten importiert werden. Redmine kennt im Gegensatz zu Jira keine Unterscheidung zwischen Ersteller und Melder. Idealerweise sollten bei allen importierten Tickets für Ersteller und Melder dieselben Werte hinterlegt sein. Der Importer setzt den Ersteller jedoch auf die Person, die den Importer ausführt. Das kann den Vorteil haben, dass sich leicht erkennen lässt, dass diese Tickets aus einem Drittsystem stammen.

Lösungsdaten importierter Issues

ScriptRunner enthält ebenfalls einige Funktionen, zum Beispiel eine, die den Lösungsstatus eines Tasks korrigiert. Sie behält jedoch das Lösungsdatum nicht bei und unterstützt nur die Massenbearbeitung von mehr als 1.000 Issues gleichzeitig. Das Lösungsdatum wird für verschiedene Statistiken und Diagramme benötigt. Atlassian setzt das Limit von 1.000 Issues bei der Massenbearbeitung über die Benutzeroberfläche durch. Das Problem mit dem Lösungsdatum im integrierten Skript lässt sich durch ein eigenes Skript lösen. Ein solches findet ihr in unserem code-utils-Repository.

Viele Custom Fields für externe Issue-IDs

Beim Import vieler einzelner Projekte wird für jedes importierte Projekt ein Custom Field für externe Issue-IDs erstellt. Dieses Verhalten war uns nicht vollständig bewusst, bis einige Projekte importiert und angelegt worden waren. Das Problem bei mehreren Custom Fields für externe Issue-IDs besteht darin, dass Verknüpfungen zwischen Issues in unterschiedlichen Projekten nicht erstellt werden.

Eine mögliche Lösung besteht darin, ein Zwischenprojekt zu verwenden, um alle Issues aus Redmine – gegebenenfalls in Teilen – zu importieren und sie anschließend per Massenverschiebung in neue Projekte zu übertragen. Diese Lösung sollte mit beiden Methoden zum Importieren der Issues umsetzbar sein.

Wenn anschließend alles in Jira importiert wurde, könnt ihr wie oben beschrieben das Skript verwenden, um die Verknüpfungen zwischen Issues aus verschiedenen Projekten zu erstellen. Dabei spielt es keine Rolle, dass einige Verknüpfungen bereits bestehen.

4. Endergebnis und Erkenntnisse.

Workflow-Änderungen

Wenn ältere Projekte in eine bestehende Jira-Instanz importiert werden, kann es sinnvoll sein zu prüfen, wie die beiden Tools genutzt wurden. Jira verwendet Workflows, um festzulegen, wie Vorgänge überführt werden können und ob ein Vorgang alle verschiedenen Phasen durchlaufen muss, bevor er geschlossen werden kann.

ScriptRunner

Wie oben beschrieben, kann ScriptRunner euch dabei helfen, die Daten nach dem Import in Jira anzupassen. Ursprünglich sollte es nur zur Nachbearbeitung der importierten Daten eingesetzt werden, erwies sich aber auch als nützlich, um Bedingungen und Post-Funktionen in den Workflows für Übergänge festzulegen. Bedingungen und Validatoren können verhindern, dass dieselben Zustände auftreten, z. B. geschlossene Stories mit offenen Sub-Tasks – eines der mitgelieferten Skripte von ScriptRunner. Einige Funktionen können als Post-Funktionen verwendet werden, z. B. um die übergeordnete Story zu schließen, sobald alle Sub-Tasks geschlossen sind. Da ScriptRunner die gesamte interne Plugin-API von Jira und nicht nur die REST-API bereitstellt, könnt ihr Funktionen schreiben, die genau zu eurer Arbeitsweise passen.

Investiert in ScriptRunner

Bevor ihr eine Migration von einem Drittanbieter-Tool startet, solltet ihr den Kauf der ScriptRunner-Erweiterung in Betracht ziehen, da sie über eine Konsole Zugriff auf alle APIs von Jira bietet. Die REST-API hat gewisse Einschränkungen, zum Beispiel bei Sprints, bei denen sich nicht alle Metadaten bearbeiten lassen. ScriptRunner eignet sich hervorragend für die Nachbearbeitung importierter Daten. Im Web findet ihr zahlreiche Snippets, die ihr mit etwas Programmiererfahrung bearbeiten und anpassen könnt. Die Konsole bietet Autovervollständigung für den Code. Die ScriptRunner-Snippets, die wir im Workflow und bei der Nachbearbeitung verwendet haben, sind Open Source und im Praqma code-utils repository verfügbar. Das folgende Snippet kann als Bedingung für den Resolve-Übergang verwendet werden, um zu verhindern, dass Stories mit offenen Sub-Tasks geschlossen werden. Adaptavist bietet ein gutes Tutorial dazu, wie ihr benutzerdefinierte Bedingungen für einen Übergang erstellt.

Auch wenn ihr die Skriptkonsole nur gelegentlich nutzen möchtet, stehen einige JQL-Funktionen zur Verfügung, die ihr bei der Suche nach Vorgängen verwenden könnt. Zudem lassen sich damit neue benutzerdefinierte JQL-Funktionen erstellen.

scriptrunner console

Fazit

Im Migrationsprozess haben wir die bestehenden Workflows vereinfacht, sodass alle Teams denselben Workflow nutzten.

Die Teams begannen, Atlassians Scrum-Funktionen wie Epics und Sprints innerhalb der von Jira unterstützten Scrum-Methodik umfassend zu nutzen.

Würden wir es noch einmal machen, würden wir die Importer-Plugins sorgfältiger auswählen. Sie leisten gute Arbeit, erfordern aber Zeit für das Schreiben von Skripten, die überprüfen, ob die Daten tatsächlich korrekt importiert wurden. Dennoch können sie Bereinigungsaufgaben hinterlassen, die sich vermeiden lassen, wenn mehr Zeit in Skripte für die Extraktion und Anpassung der Daten investiert wird. Die Dokumentation beschreibt genau, wie die Felder beim Einsatz des Importers zugeordnet werden.

Das ursprüngliche Nummernschema (externe Vorgangs-ID) ist aus mehreren Gründen wichtig. Es stellt sicher, dass derselbe Vorgang nicht zweimal importiert werden kann, und dient als Verknüpfung zwischen Jira und Redmine. Durch die Verwendung von nur einem benutzerdefinierten Feld für die externe Vorgangs-ID lassen sich zudem die Verknüpfungen zwischen Vorgängen in unterschiedlichen Projekten erhalten.

ScriptRunner erwies sich sowohl für Bereinigungen als auch für die mitgelieferten JQL-Funktionen als sehr nützlich, die sich für Abfragen in Boards und bei der Suche nach Vorgängen verwenden lassen. Außerdem haben wir es für Änderungen an Workflows eingesetzt.

  • DevOps
  • Atlassian

Subscribe to our newsletter