Content
View differences
Updated by Andrej Sandorf about 3 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 * TBD
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">text</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">textarea</code>, <code class="op-uc-code">wiki renderer</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"><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">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"><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">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">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">Integer values display as <code class="op-uc-code">5.0</code><br>or we must scan for actual usage</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">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><br><code class="op-uc-code">labels</code> (multi), multi-grouppicker</p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">list</code><br>(labels out-of-scope)</p></td><td class="op-uc-table--cell"><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></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">version</code> single</p></td><td class="op-uc-table--cell"><p class="op-uc-p">Version picker</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">component</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p">Components</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">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">issuelinks</code> array</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> — 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
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">text</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">textarea</code>, <code class="op-uc-code">wiki renderer</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"><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">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"><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">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">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">Integer values display as <code class="op-uc-code">5.0</code><br>or we must scan for actual usage</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">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><br><code class="op-uc-code">labels</code> (multi), multi-grouppicker</p></td><td class="op-uc-table--cell"><p class="op-uc-p"><code class="op-uc-code">list</code><br>(labels out-of-scope)</p></td><td class="op-uc-table--cell"><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></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">version</code> single</p></td><td class="op-uc-table--cell"><p class="op-uc-p">Version picker</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">component</code></p></td><td class="op-uc-table--cell"><p class="op-uc-p">Components</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">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">issuelinks</code> array</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> — 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