Content
View differences
Updated by Andrej Sandorf about 14 hours ago
**As** an admin migrating from Jira to OpenProject
**I want to** migrate custom fields of my Jira Issues to custom fields in OpenProject
**so that** I have a more complete work package
<br>
**Acceptance criteria**
* Custom fields for custom field types OpenProject has a corresponding field type are migrated
<br>
**Technical notes**
Plan outline:
1. For the selected projects scan the issue payloads, collect only the \`customfield\_XXXXX\` IDs that have non-null values in the selected projects, store field definitions in \`jira\_fields\`
2. Map and create custom fields
1. Re-use CFs which have the correct type
2. Create new CFs with the same name but mismatching type
3. Create new CFs not found
4. Prepare special CFs like "Field context" lists
3. Associated the CFs with each work package type encountered during import (add to work package form?)
4. Set CF values on work packages at creation time, populate hierarchy items as needed
Caveats:
As with other data, a flag is set so existing CFs are not deleted on revert.
When creating CFs with different names, the names in the issue history have to be updated, too.
<br>
**Straight forward:**
<figure class="table op-uc-figure_align-center op-uc-figure"><table class="op-uc-table"><thead class="op-uc-table--head"><tr class="op-uc-table--row"><th class="op-uc-table--cell op-uc-table--cell_head"><p class="op-uc-p">Jira field type</p></th><th class="op-uc-table--cell op-uc-table--cell_head"><p class="op-uc-p">Example Jira CF</p></th><th class="op-uc-table--cell op-uc-table--cell_head"><p class="op-uc-p">OP target</p></th><th class="op-uc-table--cell op-uc-table--cell_head"><p class="op-uc-p">Notes</p></th></tr></thead><tbody><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">string</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">textfield</code>, <code class="op-uc-code">grouppicker</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">string</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><br data-cke-filler="true"></p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">date</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">datepicker</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">date</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><br data-cke-filler="true"></p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">cascadingselect</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">cascadingselect</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">hierarchy</code> (Enterprise)</p></td><td class="op-uc-table--cell"><p class="op-uc-p"><br data-cke-filler="true"></p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">string</code> with <code class="op-uc-code">url</code> plugin</p></td><td class="op-uc-table--cell"><p class="op-uc-p">URL custom field</p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">link</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><br data-cke-filler="true"></p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">number</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">float</code>, <code class="op-uc-code">story points</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">float</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><br data-cke-filler="true"></p></td></tr></tbody></table></figure>
**To discuss:**
<figure class="table op-uc-figure_align-center op-uc-figure"><table class="op-uc-table"><thead class="op-uc-table--head"><tr class="op-uc-table--row"><th class="op-uc-table--cell op-uc-table--cell_head"><p class="op-uc-p">Jira field type</p></th><th class="op-uc-table--cell op-uc-table--cell_head"><p class="op-uc-p">Example Jira CF</p></th><th class="op-uc-table--cell op-uc-table--cell_head"><p class="op-uc-p">Possible OP target</p></th><th class="op-uc-table--cell op-uc-table--cell_head"><p class="op-uc-p">Notes</p></th></tr></thead><tbody><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">text</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">textarea</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">longtext</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p">format is depending on the Jira renderer (<code class="op-uc-code">wiki renderer</code>/<code class="op-uc-code">plain renderer</code>)<br>There is no API endpoint for this <a class="op-uc-link" href="https://community.atlassian.com/forums/Jira-questions/Is-there-a-way-to-get-the-renderer-for-a-text-field-from-rest/qaq-p/460653">[1]</a>, <br>the /rest/api/3/fieldconfiguration/{id}/fields endpoint with renderer info is Cloud-only (API v3). <br>Text is converted into Markdown as Wiki markup, which may result in unexpected formatting.</p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">string</code> boolean-pattern</p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">checkboxes</code><br>Boolean flags (<code class="op-uc-code">"true"</code>/<code class="op-uc-code">"false"</code>)</p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">bool</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><mention class="mention" data-id="73933" data-type="work_package" data-text="##73933">##73933</mention> </p></td></tr><tr class="op-uc-p">checkboxes is a list, create multiple custom fields?</p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">cascadingselect</code> on Community Edition</p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">cascadingselect</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><br data-cke-filler="true"></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><br data-cke-filler="true"></p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">datetime</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">datetime</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">date</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><mention class="mention" data-id="32646" data-type="work_package" data-text="##32646">##32646</mention> </p><p class="op-uc-p"><br>Time-of-day class="op-uc-p">Time-of-day and timezone lost</p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">user</code> single</p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">userpicker</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p">our user select? </p></td><td class="op-uc-table--cell"><p class="op-uc-p">(TODO: check scoping/context)</p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">array</code> of <code class="op-uc-code">user</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">multiuserpicker</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p">same as single</p></td><td class="op-uc-table--cell"><p class="op-uc-p"><br data-cke-filler="true"></p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">array</code> of <code class="op-uc-code">string</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">options</code> <code class="op-uc-code">multi-grouppicker</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">list</code></p></td><td class="op-uc-table--cell"><ul class="op-uc-list"><li class="op-uc-list--item"><p class="op-uc-p">"Field context", must be split and create per project, otherwise list entries are selectable which are not valid for a project</p></li><li class="op-uc-list--item"><p class="op-uc-p">Entries in an option list can be disabled in JIra, OP does not support that yet => currently imported as normal list entries)</p></li><li class="op-uc-list--item"><p class="op-uc-p">The API endpoint to retrieve options is marked "experimental", so as a fallback the list is filled from the actual values used in the issue.</p></li></ul></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">array</code> of <code class="op-uc-code">label</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">labels</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p">out-of-scope</p></td><td class="op-uc-table--cell"><p class="op-uc-p"><br data-cke-filler="true"></p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">version</code> single</p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">version-picker</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><br data-cke-filler="true"></p></td><td class="op-uc-table--cell"><p class="op-uc-p">Do we create versions? Those will be global</p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">array</code> of <code class="op-uc-code">version</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p">Fix versions, affects versions</p></td><td class="op-uc-table--cell"><p class="op-uc-p"><br data-cke-filler="true"></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><br data-cke-filler="true"></p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">array</code> of <code class="op-uc-code">component</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">coomponents</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p">out-of-scope</p></td><td class="op-uc-table--cell"><p class="op-uc-p"><br data-cke-filler="true"></p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">array</code> of <code class="op-uc-code">issuelink</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">issuelinks</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><br data-cke-filler="true"></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><br data-cke-filler="true"></p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">any</code> — sprint</p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">gh-sprint</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><br data-cke-filler="true"></p></td><td class="op-uc-table--cell"><p class="op-uc-p">State, board, date info lost</p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">any</code> — epic link</p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">gh-epic-link</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><br data-cke-filler="true"></p></td><td class="op-uc-table--cell"><p class="op-uc-p">(issue key, e.g. <code class="op-uc-code">PROJ-42</code>)</p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">any</code> — unknown plugins</p></td><td class="op-uc-table--cell"><p class="op-uc-p">Various Atlassian plugins</p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">string</code> (<code class="op-uc-code">value.to_s</code>)</p></td><td class="op-uc-table--cell"><p class="op-uc-p">May produce raw JSON string dump</p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p"><br data-cke-filler="true"></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><br data-cke-filler="true"></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><br data-cke-filler="true"></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><br data-cke-filler="true"></p></td></tr></tbody></table></figure><br>
**Out of scope**
* Fields like `labels` or `components` currently have no migration path because of missing custom field types in OpenProject
**I want to** migrate custom fields of my Jira Issues to custom fields in OpenProject
**so that** I have a more complete work package
<br>
**Acceptance criteria**
* Custom fields for custom field types OpenProject has a corresponding field type are migrated
<br>
**Technical notes**
Plan outline:
1. For the selected projects scan the issue payloads, collect only the \`customfield\_XXXXX\` IDs that have non-null values in the selected projects, store field definitions in \`jira\_fields\`
2. Map and create custom fields
1. Re-use CFs which have the correct type
2. Create new CFs with the same name but mismatching type
3. Create new CFs not found
4. Prepare special CFs like "Field context" lists
3. Associated the CFs with each work package type encountered during import (add to work package form?)
4. Set CF values on work packages at creation time, populate hierarchy items as needed
Caveats:
As with other data, a flag is set so existing CFs are not deleted on revert.
When creating CFs with different names, the names in the issue history have to be updated, too.
<br>
**Straight forward:**
<figure class="table op-uc-figure_align-center op-uc-figure"><table class="op-uc-table"><thead class="op-uc-table--head"><tr class="op-uc-table--row"><th class="op-uc-table--cell op-uc-table--cell_head"><p class="op-uc-p">Jira field type</p></th><th class="op-uc-table--cell op-uc-table--cell_head"><p class="op-uc-p">Example Jira CF</p></th><th class="op-uc-table--cell op-uc-table--cell_head"><p class="op-uc-p">OP target</p></th><th class="op-uc-table--cell op-uc-table--cell_head"><p class="op-uc-p">Notes</p></th></tr></thead><tbody><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">string</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">textfield</code>, <code class="op-uc-code">grouppicker</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">string</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><br data-cke-filler="true"></p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">date</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">datepicker</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">date</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><br data-cke-filler="true"></p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">cascadingselect</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">cascadingselect</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">hierarchy</code> (Enterprise)</p></td><td class="op-uc-table--cell"><p class="op-uc-p"><br data-cke-filler="true"></p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">string</code> with <code class="op-uc-code">url</code> plugin</p></td><td class="op-uc-table--cell"><p class="op-uc-p">URL custom field</p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">link</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><br data-cke-filler="true"></p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">number</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">float</code>, <code class="op-uc-code">story points</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">float</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><br data-cke-filler="true"></p></td></tr></tbody></table></figure>
**To discuss:**
<figure class="table op-uc-figure_align-center op-uc-figure"><table class="op-uc-table"><thead class="op-uc-table--head"><tr class="op-uc-table--row"><th class="op-uc-table--cell op-uc-table--cell_head"><p class="op-uc-p">Jira field type</p></th><th class="op-uc-table--cell op-uc-table--cell_head"><p class="op-uc-p">Example Jira CF</p></th><th class="op-uc-table--cell op-uc-table--cell_head"><p class="op-uc-p">Possible OP target</p></th><th class="op-uc-table--cell op-uc-table--cell_head"><p class="op-uc-p">Notes</p></th></tr></thead><tbody><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">text</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">textarea</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">longtext</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p">format is depending on the Jira renderer (<code class="op-uc-code">wiki renderer</code>/<code class="op-uc-code">plain renderer</code>)<br>There is no API endpoint for this <a class="op-uc-link" href="https://community.atlassian.com/forums/Jira-questions/Is-there-a-way-to-get-the-renderer-for-a-text-field-from-rest/qaq-p/460653">[1]</a>, <br>the /rest/api/3/fieldconfiguration/{id}/fields endpoint with renderer info is Cloud-only (API v3). <br>Text is converted into Markdown as Wiki markup, which may result in unexpected formatting.</p></td></tr><tr class="op-uc-table--row"><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">string</code> boolean-pattern</p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">checkboxes</code><br>Boolean flags (<code class="op-uc-code">"true"</code>/<code class="op-uc-code">"false"</code>)</p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">bool</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><mention class="mention" data-id="73933" data-type="work_package" data-text="##73933">##73933</mention> </p></td></tr><tr
**Out of scope**
* Fields like `labels` or `components` currently have no migration path because of missing custom field types in OpenProject