Миграция из jira cloud в сущестующий инстанс jira Data Center

An error occurred:

Trying to export Automation Rule found problem: Could not find object: Priority with id: [1]

At Most frequent errors found in export you can find advice to fix this problem

Удалили встроенные правила автоматизации.

Found custom field with values for issues in exported project(s), with id: 10020, name: [CHART] Time in Status and type: com.atlassian.jira.ext.charting:timeinstatus. This field does not exist. Check if its type is defined in a plugin that has been disabled.

Непонятно что за плагин такой для клауда. Точно не https://marketplace.atlassian.com/apps/1211756/time-in-status?hosting=datacenter&tab=overview Поле для клауда нативное: https://jira.atlassian.com/browse/JRACLOUD-76409 в DC реализации для него нет - удалили все следующим образом:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.ofbiz.OfBizDelegator
import groovy.sql.GroovyRowResult
import groovy.sql.Sql
import org.ofbiz.core.entity.ConnectionFactory
import org.ofbiz.core.entity.DelegatorInterface

import java.sql.Connection

//select("""select * from customfieldvalue where customfield = 10020;""")

update("""DELETE FROM customfieldvalue WHERE customfield = 10020;""")
//update("delete/insert ...")
def select(String query) {
    OfBizDelegator delegator = ComponentAccessor.getOfBizDelegator();
    DelegatorInterface delegatorInterface = delegator.getDelegatorInterface();
    String helperName = delegatorInterface.getGroupHelperName("default");
    Connection connection = ConnectionFactory.getConnection(helperName);
    Sql sql = new Sql(connection);

    List<GroovyRowResult> resultRows = []
    try {
        resultRows.addAll(sql.rows(query));
    } finally {
        //sql.close()
        connection.close()
    }

    return resultRows
}

def update(String query) {
    OfBizDelegator delegator = ComponentAccessor.getOfBizDelegator();
    DelegatorInterface delegatorInterface = delegator.getDelegatorInterface();
    String helperName = delegatorInterface.getGroupHelperName("default");
    Connection connection = ConnectionFactory.getConnection(helperName);
    Sql sql = new Sql(connection);
    def numberOfUpdated
    try {
        numberOfUpdated = sql.executeUpdate(query);
    } finally {
        //sql.close()
        connection.close()
    }
    return numberOfUpdated
}

Found custom field with values for issues in exported project(s), with id: 10043, name: Request language and type: com.atlassian.servicedesk.servicedesk-lingo-integration-plugin:sd-request-language. This field does not exist. Check if its type is defined in a plugin that has been disabled.

Сразу удалил все значения поменяв id в предыдущем скрипте

import com.atlassian.jira.bc.user.UserService
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.user.UserUtils
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.security.login.LoginManager
import javax.ws.rs.core.Response
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.search.SearchProvider
import com.atlassian.jira.jql.parser.JqlQueryParser
import com.atlassian.jira.web.bean.PagerFilter
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.bc.issue.search.SearchService
import com.atlassian.jira.web.bean.PagerFilter
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.comments.CommentManager
import com.atlassian.jira.event.type.EventDispatchOption

def commentManager = ComponentAccessor.getComponent(CommentManager.class);

def loginManager = ComponentAccessor.getComponentOfType(LoginManager.class)
def userUtil = ComponentAccessor.getUserUtil()

def newUser = userUtil.getUserByName("sysadmin")

def usersToDelete = ComponentAccessor.userManager.getAllUsers()
.findAll{!userUtil.getGroupNamesForUser(it.name).contains("from_cloud")}
//.findAll{it.getDirectoryId()==1}
//.findAll{!it.getEmailAddress().contains("domain.ru")}
//.findAll{it.isActive()==false}
//.findAll{it.name == "qm:1bf2f9d2-2a2d-4ba2-9259-e62227560afc:063cc686-abb6-4b7c-adc7-03cb0c440517"}
/*.collect{
    def oldUser = it
    def issues = runJQL("""reporter in ("${oldUser.name}")""", currentUser)
    for (issue in issues) {
        issue.reporter = newUser
        update(issue)
    }
}
.collect{
    def oldUser = it
    def issues = runJQL("""assignee in ("${oldUser.name}")""", currentUser)
    for (issue in issues) {
        issue.assignee = newUser
        update(issue)
    }
}
.collect{
    def oldUser = it
    def issues = runJQL("""groovyFunction  in my_commented('by "${oldUser.name}"')""", currentUser)
    for (issue in issues) {
        def comments = commentManager.getComments(issue).findAll{it.getAuthorApplicationUser().equals(oldUser)}
        comments.collect {
            commentManager.create(issue,newUser,newUser,it.getBody(),it.getGroupLevel(),it.getRoleLevelId(),it.getCreated(),it.getUpdated(),false)
            commentManager.delete(it);
        }
    }
}*/

//return usersToDelete[0]

def runJQL(String jql, ApplicationUser user) {
    def issuesSearch
    def searchService = ComponentAccessor.getComponent(SearchService.class)
    def issueManager = ComponentAccessor.getIssueManager()

    def parseJQLResult = searchService.parseQuery(user, jql)

    if (parseJQLResult.isValid()) {
      //return "qw"
        def result = searchService.search(user, parseJQLResult.getQuery(), PagerFilter.getUnlimitedFilter())
        def documentIssues = result.results
      //return documentIssues.class.methods as String
        return documentIssues.collect { issueManager.getIssueObject(it.id) }
    } else {
        log.error("Invalid JQL: " + jql);
        log.debug("SendRFCReportToConfluenceSRV out")
    }
    return issuesSearch
}

def userService = ComponentAccessor.getComponent(UserService)
//def usersToDelete = ["qm:1bf2f9d2-2a2d-4ba2-9259-e62227560afc:259efcfa-f5f8-46dd-b6cb-7b67055f8949"]

usersToDelete?.collect { it ->
    final UserService.DeleteUserValidationResult result = userService.validateDeleteUser(currentUser, it)

    //if (result.isValid()) {
    try {
        userService.removeUser(currentUser, result)
      //return "User with username $it removed"
    } catch (any) { return "error=${result.errorCollection}"}
       //log.info "User with username $it removed"
    //}
    //else {
        //return "Failed to remove user with username $it. " + result.getErrorCollection().errorMessages
      //log.error "Failed to remove user with username $it. " + result.getErrorCollection().errorMessages
    //}
}

def findUserByEmail(String email) {
    UserUtils.getUserByEmail(email)
}

def update(Issue issue){
    def im = ComponentAccessor.getIssueManager()
    im.updateIssue(currentUser, issue, EventDispatchOption.ISSUE_UPDATED, false)
}

Переименование юзеров

import com.atlassian.jira.bc.user.UserService
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.user.UserUtils
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.security.login.LoginManager
import javax.ws.rs.core.Response
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.search.SearchProvider
import com.atlassian.jira.jql.parser.JqlQueryParser
import com.atlassian.jira.web.bean.PagerFilter
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.bc.issue.search.SearchService
import com.atlassian.jira.web.bean.PagerFilter
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.comments.CommentManager
import com.atlassian.jira.event.type.EventDispatchOption
import com.atlassian.jira.bc.user.ApplicationUserBuilder;
import com.atlassian.jira.bc.user.UserService;
import com.atlassian.jira.component.ComponentAccessor;
import com.atlassian.jira.util.ErrorCollection;

def commentManager = ComponentAccessor.getComponent(CommentManager.class);
def loginManager = ComponentAccessor.getComponentOfType(LoginManager.class)
def userUtil = ComponentAccessor.getUserUtil()

def userRename(ApplicationUser user) {
    UserService userService = ComponentAccessor.getComponent(UserService.class);
    ApplicationUserBuilder applicationUserBuilder = userService.newUserBuilder(user);

    if (user.getEmailAddress().contains("@yourdomain.ru")){
        def name = user.getEmailAddress().replace("@yourdomain.ru", "")
        applicationUserBuilder.name("${name}@dmz.abc");
    }
    if (user.getEmailAddress().contains("@seconddomain.ru")){
        def name = user.getEmailAddress().replace("@seconddomain.ru", "")
        applicationUserBuilder.name("${name}@dmz.abc");
    }

    ApplicationUser userForValidation = applicationUserBuilder.build();

    UserService.UpdateUserValidationResult updateUserValidationResult = userService.validateUpdateUser(userForValidation);
    if (updateUserValidationResult.isValid()) {
        userService.updateUser(updateUserValidationResult);
    } else {
        return updateUserValidationResult.getErrorCollection();
    }
}

Еще могут появляться такие ошибки: Data import for project ABC did NOT complete.

Backup validation info: ERRORS: The backup project 'ProjectName' requires custom field named 'Approvals' with full key 'com.atlassian.servicedesk.approvals-plugin:sd-approvals'. In the current instance of Jira the plugin is at version '4.18.0-REL-0008', but this custom field was not installed in the backup data. You may want to create an XML backup with this version of the plugin installed. The backup project 'ProjectName' requires custom field named 'Organizations' with full key 'com.atlassian.servicedesk:sd-customer-organizations'. In the current instance of Jira the plugin is at version '4.18.0-REL-0008', but this custom field was not installed in the backup data. You may want to create an XML backup with this version of the plugin installed. The backup project 'ProjectName' requires custom field named 'Request Type' with full key 'com.atlassian.servicedesk:vp-origin'. In the current instance of Jira the plugin is at version '4.18.0-REL-0008', but this custom field was not installed in the backup data. You may want to create an XML backup with this version of the plugin installed. The backup project 'ProjectName' requires custom field named 'Request language' with full key 'com.atlassian.servicedesk.servicedesk-lingo-integration-plugin:sd-request-language'. In the current instance of Jira the plugin is at version '4.18.0-REL-0008', but this custom field was not installed in the backup data. You may want to create an XML backup with this version of the plugin installed. The backup project 'ProjectName' requires custom field named 'Request participants' with full key 'com.atlassian.servicedesk:sd-request-participants'. In the current instance of Jira the plugin is at version '4.18.0-REL-0008', but this custom field was not installed in the backup data. You may want to create an XML backup with this version of the plugin installed. The backup project 'ProjectName' requires custom field named 'Satisfaction date' with full key 'com.atlassian.servicedesk:sd-request-feedback-date'. In the current instance of Jira the plugin is at version '4.18.0-REL-0008', but this custom field was not installed in the backup data. You may want to create an XML backup with this version of the plugin installed. The backup project 'ProjectName' requires custom field named 'Satisfaction' with full key 'com.atlassian.servicedesk:sd-request-feedback'. In the current instance of Jira the plugin is at version '4.18.0-REL-0008', but this custom field was not installed in the backup data. You may want to create an XML backup with this version of the plugin installed.

По наименованию полей понятно что все это от сервис деска, непонятно только откуда взялось в клауде так как SD проектов там не было, в развернутой копии в админке таких филдов тоже нет(возможно проекты были в клауде раньше их удалили а филды в базе остались) в DC сервис деска не будет, поэтому решение тривиальное:

DELETE from CUSTOMFIELD where CFNAME = 'Approvals';

Ошибка уже выглядит страшнее, так как нет ни файла ни номера строки на котором все поломалось: Data import for project with key: ABC There was a problem parsing the backup XML file at /opt/atlassian/jira/temp/com.awnaba.projectconfigurator1667750639802/data/data.zip: com.atlassian.jira.exception.ParseException: The entityId of entityName '11139' is missing INFO 19:07:35,910 Project Import: Parsing the backup file '/opt/atlassian/jira/temp/com.awnaba.projectconfigurator1667750639802/data/data.zip' to obtain a Backup Overview. INFO 19:07:40,992 Project Import: Backup Overview was successfully extracted from '/opt/atlassian/jira/temp/com.awnaba.projectconfigurator1667750639802/data/data.zip'. WARN 19:07:45,893 Encountered a parsing exception. com.atlassian.jira.exception.ParseException: The entityId of entityName '11139' is missing

grep решил проблему в файле entities.xml нашел такую строку:

<EntityProperty id="11139"/>

sudo grep -rn 'id="11139"' ~/Downloads/data project_configurator_2022-11-07_00-41

Нашел по номеру строки, удалил её, перепаковал и все ок

И тут следующая ошибка:

Data import for project ABC did NOT complete.

Mapping results info: Custom fields ERRORS: The custom field 'Epic Color' of type 'Colour of Epic' is required for the import but does not exist in the current Jira instance. The custom field 'Epic Name' of type 'Name of Epic' is required for the import but does not exist in the current Jira instance. The custom field 'Epic Status' of type 'Status of Epic' is required for the import but does not exist in the current Jira instance. The custom field 'Flagged' of type 'Checkboxes' is required for the import but does not exist in the current Jira instance. The custom field 'Sprint' of type 'Jira Sprint Field' is required for the import but does not exist in the current Jira instance. The custom field 'Story point estimate' of type 'Number Field' is required for the import but does not exist in the current Jira instance.

Это мы уже решали сто раз - причина в том что в целевом инстансе филды называются по русски. Решается переименованием системных филдов в русский в локальном бэкапе, перед переименованием их нужно разблокировать: Здесь еще есть Flagged и кастомфилд Story point estimate - просто снёс

Еще ошибка:

Data import for project ABC did NOT complete.

Mapping results info: Statuses ERRORS: The status 'TESTING' is required for the import but does not exist in the current Jira instance. The status 'TESTING' is in use by an issue of type 'Task' in the backup file. The workflow 'Base SANE workflow for agile/scrum/kanban teams + nuts', which is associated with issue type 'Task', does not use this status. You must either edit the workflow to use the status or associate a workflow with issue type 'Task' that uses the status. The status 'TESTING' is in use by an issue of type 'Epic' in the backup file. The workflow 'Base SANE workflow for agile/scrum/kanban teams + nuts', which is associated with issue type 'Epic', does not use this status. You must either edit the workflow to use the status or associate a workflow with issue type 'Epic' that uses the status. The status 'TESTING' is in use by an issue of type 'Bug' in the backup file. The workflow 'Base SANE workflow for agile/scrum/kanban teams + nuts', which is associated with issue type 'Bug', does not use this status. You must either edit the workflow to use the status or associate a workflow with issue type 'Bug' that uses the status. The status 'TESTING' is in use by an issue of type 'Sub-task' in the backup file. The workflow 'Base SANE workflow for agile/scrum/kanban teams + nuts', which is associated with issue type 'Sub-task', does not use this status. You must either edit the workflow to use the status or associate a workflow with issue type 'Sub-task' that uses the status. The status 'IN REVIEW' is required for the import but does not exist in the current Jira instance. The status 'IN REVIEW' is in use by an issue of type 'Epic' in the backup file. The workflow 'Base SANE workflow for agile/scrum/kanban teams + nuts', which is associated with issue type 'Epic', does not use this status. You must either edit the workflow to use the status or associate a workflow with issue type 'Epic' that uses the status. The status 'IN REVIEW' is in use by an issue of type 'Task' in the backup file. The workflow 'Base SANE workflow for agile/scrum/kanban teams + nuts', which is associated with issue type 'Task', does not use this status. You must either edit the workflow to use the status or associate a workflow with issue type 'Task' that uses the status. The status 'IN REVIEW' is in use by an issue of type 'Bug' in the backup file. The workflow 'Base SANE workflow for agile/scrum/kanban teams + nuts', which is associated with issue type 'Bug', does not use this status. You must either edit the workflow to use the status or associate a workflow with issue type 'Bug' that uses the status. The status 'IN REVIEW' is in use by an issue of type 'Sub-task' in the backup file. The workflow 'Base SANE workflow for agile/scrum/kanban teams + nuts', which is associated with issue type 'Sub-task', does not use this status. You must either edit the workflow to use the status or associate a workflow with issue type 'Sub-task' that uses the status. The status 'BLOCKED' is required for the import but does not exist in the current Jira instance. The status 'BLOCKED' is in use by an issue of type 'Task' in the backup file. The workflow 'Base SANE workflow for agile/scrum/kanban teams + nuts', which is associated with issue type 'Task', does not use this status. You must either edit the workflow to use the status or associate a workflow with issue type 'Task' that uses the status. The status 'BLOCKED' is in use by an issue of type 'Epic' in the backup file. The workflow 'Base SANE workflow for agile/scrum/kanban teams + nuts', which is associated with issue type 'Epic', does not use this status. You must either edit the workflow to use the status or associate a workflow with issue type 'Epic' that uses the status. The status 'BLOCKED' is in use by an issue of type 'Bug' in the backup file. The workflow 'Base SANE workflow for agile/scrum/kanban teams + nuts', which is associated with issue type 'Bug', does not use this status. You must either edit the workflow to use the status or associate a workflow with issue type 'Bug' that uses the status. The status 'BLOCKED' is in use by an issue of type 'Sub-task' in the backup file. The workflow 'Base SANE workflow for agile/scrum/kanban teams + nuts', which is associated with issue type 'Sub-task', does not use this status. You must either edit the workflow to use the status or associate a workflow with issue type 'Sub-task' that uses the status. The status 'REOPEN' is required for the import but does not exist in the current Jira instance. The status 'REOPEN' is in use by an issue of type 'Task' in the backup file. The workflow 'Base SANE workflow for agile/scrum/kanban teams + nuts', which is associated with issue type 'Task', does not use this status. You must either edit the workflow to use the status or associate a workflow with issue type 'Task' that uses the status. The status 'REOPEN' is in use by an issue of type 'Bug' in the backup file. The workflow 'Base SANE workflow for agile/scrum/kanban teams + nuts', which is associated with issue type 'Bug', does not use this status. You must either edit the workflow to use the status or associate a workflow with issue type 'Bug' that uses the status.

Просто переименовал статусы в проде из Reopen в REOPEN

Далее следующая ошибка: Data import for project with key: ABC Data import failed with exception: Entity com.atlassian.greenhopper.service.sprint.SprintAO does not have field CREATED_DATE java.lang.NullPointerException: Entity com.atlassian.greenhopper.service.sprint.SprintAO does not have field CREATED_DATE at java.base/java.util.Objects.requireNonNull(Objects.java:246) at net.java.ao.EntityManager.create(EntityManager.java:342) at net.java.ao.EntityManager.create(EntityManager.java:402)

Решилось

ALTER TABLE "AO_60DB71_SPRINT" DROP COLUMN "CREATED_DATE";