Contents

1. Overview

The Atlassian Migration Assistant moves your Jira Data Center (DC) projects to Jira Cloud. While issues, attachments, and most project data are transferred correctly, the OSLC Connect for Jira integration data is not — links between Jira issues and external tools (requirements, test cases, architecture elements, etc.) still reference DC-specific internal IDs and URLs that no longer work in Cloud.

This tool finds all affected resources, looks up their new Cloud identifiers using the Atlassian mapping service, and restores the data so that the OSLC integration works again in Jira Cloud.

What data is handled
Remote Links

Links from Jira issues to external OSLC resources such as requirements, test cases, or architecture elements. After migration these links carry stale DC IDs and URLs which no longer resolve correctly.

GC Version Links

Associations between Jira project versions and Global Configuration (GC) streams or baselines. These are completely lost during migration and need to be restored.

Project Associations

Connections between Jira projects and external OSLC project areas. These define which link types (e.g. "Implements Requirement") are available in a Jira project. They are also lost during migration.

Link Type Deliverables

Mappings between OSLC link types and Jira version fields (affects-version or fix-version). These control which Global Configuration is associated to a link, and are not migrated natively by JCMA.

2. How It Works

The process follows a fixed sequence of steps. The Indexer and the Updater are the two main programs in this package.

0
Jira DC → Cloud migration (Atlassian Migration Assistant)

Your Jira projects are migrated using Atlassian's tool. After the migration, the Atlassian mapping service is available and holds a complete table of DC resource IDs mapped to their new Cloud IDs. This is the starting point for this tool.

1
Run the Indexer

The Indexer connects to your Jira DC instance, reads all OSLC-related data, and resolves the corresponding Cloud IDs from the DC→Cloud ID mapping. It then writes one Excel file per project to a folder you specify. Each file contains one sheet per resource type.

2
Review the Excel files

Open the generated Excel files and inspect the results. Each row represents one resource and shows its current status. You can optionally mark rows to be skipped or reprocessed before moving on.

3
Run the Updater

The Updater reads the Excel files and posts the corrected data to Jira Cloud and the OSLC Connect broker. The outcome of each row is written back into the same file.

4
Validate

Open Jira Cloud, navigate the migrated projects, and confirm that OSLC links, GC version associations, and project link types are all working correctly.

Safe to re-run: Both the Indexer and the Updater can be run multiple times without side effects. The Indexer appends newly found resources and refreshes an existing row only when its Jira DC properties or its Cloud ID changed (e.g. after a Jira re-migration), setting it to CHANGED so the Updater posts it again; rows where nothing changed are left untouched, whatever their status. The Updater skips rows already UPDATED and retries failed ones. If additional projects are migrated between 2 runs, they will be visible to the new run scope (--all-projects or --projects).

3. Prerequisites

Software & environment
Component Requirement Notes
Java Version 21 or later The java executable must be available on the system PATH. Run java -version to check.
Jira Data Center Version 10 or 11 The Atlassian Cloud Migration Assistant must have been used to migrate at least one project. Unless a CSV mapping file is provided with --idmappings, the ID mapping service endpoint (/rest/migration/latest/report/id-mappings) must be accessible from the machine running this tool.
Jira Cloud Any current version Projects must already have been migrated. A dedicated service account with project administration permissions is strongly recommended.
OSLC Connect for Jira Cloud (broker) Any supported version The broker must be running and reachable over the network from the machine executing this tool.
Project associations: remote applications must be registered as friend applications
⚠ Required for project association updates: Before running the Updater for project_associations, the remote OSLC applications (service providers) that the Jira projects were associated with must already be registered as friend applications in the OSLC Connect Cloud broker. If they are not registered, the POST request will fail. Run the Updater with --verify first: it reports, per project, the applications that are not registered.
Jira DC: Basic authentication must be enabled
⚠ Required configuration on Jira DC: This tool authenticates with Jira DC using HTTP Basic authentication (username and password). Basic auth is not enabled by default on all Jira DC installations. If it is not enabled, the tool will receive 401 Unauthorized errors.

Refer to the official Atlassian guide for instructions: Basic authentication – Jira Data Center (Atlassian Developer Docs).
Supported databases (for database mode)

When running the Indexer in database mode, the Jira DC database is accessed directly. The following engine is supported:

  • PostgreSQL
Network connectivity

The machine running this tool must be able to reach all of the following:

4. Configuration Files

Three properties files control how the tool connects to each system. Template files for all three are included in this package. Edit them with a plain text editor before running anything.

Security notice: These files contain passwords and API tokens. Store them in a secure location, restrict access to authorized personnel only, and never commit them to source control.
config/cloud.properties Used by: Indexer & Updater

Configures access to your Jira Cloud tenant and the OSLC Connect broker.

PropertyWhat to enter
rest.baseUrl Your Jira Cloud tenant URL, e.g. https://your-org.atlassian.net
rest.username The email address of the Jira Cloud account used for API calls. A dedicated service account is recommended over a personal account.
rest.token An API token generated from the Atlassian account settings of the user above. API tokens are distinct from passwords and can be created at id.atlassian.com.
Expiry: Atlassian API tokens expire after at most one year (policy in effect since December 2024). Plan to rotate the token before it expires to avoid service interruption.
cloud.cloudId (Recommended) Your Jira Cloud site ID. When provided, all Cloud REST calls use the Atlassian API gateway (https://api.atlassian.com/ex/jira/<cloudId>/...), which is Atlassian's recommended approach for server-to-server integration.
To find your Cloud ID, open a browser and fetch: https://your-org.atlassian.net/_edge/tenant_info — the cloudId field in the JSON response is the value to enter here.
If this property is left blank, rest.baseUrl is used as a fallback and a warning is logged.
broker.baseUrl The base URL of the OSLC Connect for Jira broker application, including the context path, e.g. https://broker.example.com/oslc-connect-jira. Required by the Updater, which exits with code 2 if it is blank.
rest.timeoutMs (Optional) Timeout of each HTTP request, in milliseconds. Defaults to 30000.

rest.baseUrl, rest.username and rest.token are required.

Authentication: Jira Cloud uses Basic authentication with an email address and an API token (not a plain password). The account must have Project Administration permission on every project being processed, or the global Jira Administer permission. The Indexer checks this and skips, with a warning, every project the account cannot administer.
config/rest.properties Used by: Indexer (REST mode)

Configures access to the Jira DC REST API. This file is used in two situations:

  • When running the Indexer in REST mode (--rest flag), as an alternative to direct database access. The same configuration is also used to reach the Atlassian ID mapping service, unless --idmappings is provided with a CSV mapping file to override it.
  • When running the Indexer in database mode (--db flag), this properties file can be passed via --idmappings to fetch DC→Cloud ID mappings from the Atlassian migration service. Alternatively, --idmappings can point to a pre-downloaded CSV mapping file instead.
PropertyWhat to enter
rest.baseUrl Base URL of the Jira DC instance, including any application context path, e.g. https://jira-dc.example.com/jira.
rest.username Jira DC username. Must have read access to all projects being indexed.
rest.password Password for the Jira DC user above.
rest.timeoutMs (Optional) Timeout of each HTTP request, in milliseconds. Defaults to 30000.
rest.batchSize (Optional) Number of issues fetched per page in REST mode. Defaults to 500.

rest.baseUrl, rest.username and rest.password are required.

Authentication: Jira DC uses Basic authentication with a username and password. Basic auth must be explicitly enabled on your Jira DC instance — see the Atlassian documentation.
config/db.properties Used by: Indexer (database mode only)

Configures a direct JDBC connection to the Jira DC database. Only needed when running the Indexer in database mode (--db flag). If you prefer to use the REST API instead, this file is not required.

PropertyWhat to enter
db.url JDBC connection URL, e.g. jdbc:postgresql://dbhost:5432/jiradb.
db.username Database username. The same user Jira uses to connect is normally sufficient. Read-only access is enough for the Indexer.
db.password Database password for the user above.
db.dialect Database engine: postgresql (or postgres).
db.batchSize (Optional) Maximum number of project IDs or keys per database query. Defaults to 100.

db.url, db.username, db.password and db.dialect are required.

Authentication: Standard database username and password. The database server must accept connections from the machine running this tool.

Step-by-Step Guide

0 Meet the Prerequisites

1 Prepare Your Configuration Files

  1. Open config/cloud.properties and fill in your Jira Cloud tenant URL, service account credentials, Cloud site ID, and broker URL.
  2. Open config/rest.properties and fill in your Jira DC base URL and credentials. It is needed in REST mode, and in database mode unless you provide a CSV mapping file with --idmappings.
  3. If you plan to use database mode (recommended), also open config/db.properties and fill in your Jira DC database connection details.
Not sure which mode to use? Choose database mode if your team can provide a read-only database connection — it is faster. Use REST mode if database access is not possible.

2 Run the Indexer

Open a terminal in the folder where this package is installed and run one of the commands below. The Indexer will load the DC→Cloud ID mapping table first, then read OSLC data from Jira DC, and finally write one Excel file per project into the output folder you specify.

Only projects that have already been migrated to Jira Cloud will be processed. Projects not yet migrated are always skipped, regardless of which flags you use (with a warning when they were named with --projects). Projects the Cloud account cannot administer are skipped with a warning too.
Database mode Recommended

Connects directly to the Jira DC database. More efficient, no pagination.

Requires: config/db.properties + --idmappings (REST properties file or CSV mapping file)

REST mode

Uses the Jira DC REST API. Useful when direct database access is not available. The same config/rest.properties file is used for both data access and the ID mapping service, unless --idmappings is provided with a CSV mapping file.

Requires: config/rest.properties only

Linux — make scripts executable first: Shell scripts shipped in a zip archive lose their execute permission. Before running any .sh file for the first time, grant the permission with:
chmod +x bin/index.sh bin/update.sh
Index all migrated projects — database mode

Windows:

bin\index.bat --db config\db.properties --idmappings config\rest.properties --cloud config\cloud.properties --all-projects --dir output\

Linux:

bin/index.sh --db config/db.properties --idmappings config/rest.properties --cloud config/cloud.properties --all-projects --dir output/
Index all migrated projects — database mode with CSV mapping file
bin\index.bat --db config\db.properties --idmappings path\to\mappings.csv --cloud config\cloud.properties --all-projects --dir output\
Index all migrated projects — REST mode
bin\index.bat --rest config\rest.properties --cloud config\cloud.properties --all-projects --dir output\
Index all migrated projects — REST mode with CSV mapping file
bin\index.bat --rest config\rest.properties --idmappings path\to\mappings.csv --cloud config\cloud.properties --all-projects --dir output\
Index specific projects only
bin\index.bat --db config\db.properties --idmappings config\rest.properties --cloud config\cloud.properties --projects PROJ1,PROJ2 --dir output\
All available options
OptionDescription
--cloud <file> Path to config/cloud.properties. Always required.
--db <file> Path to config/db.properties. Use for database mode. Cannot be combined with --rest.
--rest <file> Path to config/rest.properties. Use for REST mode. Cannot be combined with --db.
--idmappings <file> DC→Cloud ID mapping source: a REST properties file to fetch it from the Atlassian migration service, or a CSV mapping file. Required when using --db. When used with --rest, only CSV files are accepted since the REST configuration is already provided. A file is read as CSV when its first line starts with entityType,.
--all-projects Process every Jira DC project that has been migrated to Cloud. Cannot be combined with --projects.
--projects <keys> Comma-separated list of project keys to process, e.g. PROJ1,PROJ2. Cannot be combined with --all-projects.
--resource-types <types> Comma-separated list of resource types to index: remote_links, gc_versions, project_associations, linktype_deliverables. Defaults to all types. Values are case-sensitive; an unknown value is ignored.
--dir <path> Folder where Excel files are written. Defaults to the current directory.
Which projects are indexed

The projects of the migration files already in --dir are always indexed again, so that a re-run keeps them up to date. --projects adds projects to those: with --projects PROJ1 and an existing file for PROJ2, both are indexed. When --dir already holds migration files, neither --all-projects nor --projects is needed. To index a single project, use a --dir holding no file of other projects.

Exit codes

Both the Indexer and the Updater exit with 0 on success, 1 when the run fails, and 2 on invalid arguments.

Output

After the Indexer finishes, you will find one Excel file per project in the output folder. Projects with no migratable resources produce no file and are skipped and logged. Each file is named jira$<PROJECT-KEY>$<DC-PROJECT-ID>$migration.xlsx.

output/
  jira$PROJ1$10000$migration.xlsx
  jira$PROJ2$10001$migration.xlsx
  ...

Each file contains one worksheet per resource type: remote_links, gc_versions, project_associations, and linktype_deliverables.

Logging

The scripts are pre-configured to load config/logback.xml. By default that file sends log output to two destinations simultaneously:

You can customize config/logback.xml with a text editor at any time:

3 Review the Excel Files

Open the generated Excel files and review the results before running the Updater. Each row represents one resource and includes a status column that tells you the outcome of the indexing step.

Common status values after indexing
Status Meaning What to do
INDEXED Cloud ID found. This record is ready to be updated. Nothing — the Updater will process it automatically.
FAILED_INDEX An error occurred while reading from Jira DC or the mapping service. Check the status_detail column for the error message. Resolve the issue and re-run the Indexer.
CHANGED The resource properties or its Cloud ID changed since the last Indexer run. Nothing — the Updater will post it again.

→ Full list of all status values in the Appendix

Optional adjustments you can make

You can manually edit the status column of any row to control how the Updater handles it:

Do not edit any other columns (old_id, new_id, resource data columns) — those values are used by the Updater to construct the API calls and must remain intact.

4 Run the Updater

The Updater reads the Excel files produced by the Indexer and sends most indexed data to Jira Cloud and the OSLC Connect broker. If linktype_deliverables were indexed, there will be a .properties file generated in the --dir folder per indexed project; this file(s) must be deployed in the Tomcat server manually. See manual step below for details. The outcome of each row is written back into the same files, so you always have a full audit trail.
Note: depending on the project size, this may be a long operation. It's been observed to take up to 40 minutes when there are around 10K links to fix.

Linux — make scripts executable first: If you have not done so already, grant execute permission with:
chmod +x bin/index.sh bin/update.sh
Run the Updater — Windows (all projects)
bin\update.bat --cloud config\cloud.properties --all-projects --dir input\
Run the Updater — Linux (all projects)
bin/update.sh --cloud config/cloud.properties --all-projects --dir input/
Update specific projects only
bin/update.sh --cloud config/cloud.properties --projects PROJ,DEMO --dir input/
Verify without posting (dry run)

Use --verify to parse and validate all input files without sending any update. It also checks that the Cloud credentials can administer every project and that the remote applications the projects are associated with are registered as friends in the broker; projects failing a check are reported and skipped. Useful to check the state of the working directory before committing updates. Note that:

bin\update.bat --cloud config\cloud.properties --all-projects --dir input\ --verify
All available options
OptionDescription
--cloud <file> Path to config/cloud.properties. Always required.
--all-projects Process all migration files found in the --dir folder. Mutually exclusive with --projects. Either this or --projects is required.
--projects <KEYS> Comma-separated list of project keys to update (e.g. PROJ,DEMO). Only migration files matching the given keys are processed. Mutually exclusive with --all-projects.
--dir <path> Folder containing the Excel files produced by the Indexer. Defaults to the current directory.
--verify Dry-run mode: parses and validates all input files, checks administrator rights and friend registrations, without sending any update.
--idmappings <file> DC→Cloud ID mapping CSV file used by --verify to check administrator rights. Defaults to the latest id-mappings_*.csv file in --dir.

Safe to re-run: UPDATED, OMIT and FAILED_INDEX rows are always skipped, as are rows with an empty or unknown status (with a warning). FAILED_UPDATE rows are retried automatically with no data loss. No special flags are needed to resume after a partial failure.

5 Validate

After the Updater finishes, verify that the migration was successful:

The Updater can be safely re-run at any time. Rows already marked UPDATED are skipped; rows marked FAILED_UPDATE are retried automatically.

Appendix

A. Resource Types — Data Sources and Destinations

The tables below describe, for each resource type, exactly where the data is read from in Jira DC and where it is written to in Jira Cloud or the OSLC Connect broker.

Remote Links
Database modeREST mode
Source in Jira DC Table: remotelink
Scoped by: issueid IN (SELECT id FROM jiraissue WHERE project = :projectId)
GET /rest/api/2/search?jql=project=<id> (to list issues; when ScriptRunner is installed, the query only returns issues having OSLC remote links)
GET /rest/api/2/issue/<key>/remotelink (per issue)
Destination in Cloud PUT /rest/api/3/issue/<cloudIssueId>/remotelink/<cloudRemoteLinkId>
ID mappings used jira:remoteLink → Cloud remote link ID
jira:issue → Cloud issue ID (owner of the link)
GC Version Links
Database modeREST mode
Source in Jira DC Table: AO_E78B5C_GCVERSION_ASS_ENTITY
Scoped by: versionId IN (SELECT id FROM projectversion WHERE project = :projectId)
GET /rest/oslc/1.0/internal/linking/version?projectId=<id>
Destination in broker PUT <brokerBaseUrl>/process/project-area/<cloudProjectId>/gc/deliverable/<cloudVersionId>?saveLocallyOnly=true
Before the first version update, a separate PUT .../process/project-area/<cloudProjectId>/gc is sent to enable Configuration Management on the project area (once per updater instance).
ID mappings used jira/classic:project → Cloud project ID
jira:projectVersion → Cloud version ID
Project Associations
Database modeREST mode
Source in Jira DC JOIN of AO_E78B5C_ASSOCIATION_ENTITY and AO_E78B5C_RMT_PROJECT_ENTITY
Filtered by: PROJECT_ID = :projectId
GET /rest/oslc/1.0/internal/process/project-area/<projectId>/association
Destination in broker POST <brokerBaseUrl>/process/project-area/<cloudProjectId>/association
All the rows of a project are sent in a single POST, covering all link types for all remote projects.
ID mappings used jira/classic:project → Cloud project ID
Link Type Deliverables
Database modeREST mode
Source in Jira DC Table: AO_E78B5C_LINK_FLD_ASS_ENTITY
Filtered by: PROJECT = :projectId
GET /rest/oslc/1.0/internal/linking/version/fieldMapping?projectId=<id>
Output No REST call is made. Instead, the Updater writes a properties file to the --dir folder:
linkType_<cloudProjectId>_deliverables.properties
Each entry maps a link type name to a deliverable field identifier: FOUND_IN (affects-version) or PLANNED_FOR (fix-version).
ID mappings used jira/classic:project → Cloud project ID

B. Status Values

The status column in each Excel sheet can hold the following values:

ValueSet byMeaning
INDEXED Indexer DC ID successfully mapped to a Cloud ID. Ready for the Updater.
FAILED_INDEX Indexer The resource could not be indexed, most often because no Cloud mapping was found for its DC ID. Verify the correct id-mappings file was used or if the resource was created after the migration ran. See the status_detail column for the exact cause. The Updater skips rows with this status.
CHANGED Indexer The resource properties or its Cloud ID changed since the last Indexer run (e.g. after a Jira re-migration). The row will be re-posted on the next Updater run.
UPDATED Updater Successfully posted to Jira Cloud or the OSLC Connect broker.
FAILED_UPDATE Updater The post to Cloud or the broker failed. The row will be retried automatically on the next Updater run.
OMIT User Intentionally skipped. The Updater will not process this row.
REPROCESS User Force the Updater to re-post this row even if it was previously UPDATED.

C. Atlassian ID Mapping Service

Before any data is read from Jira DC, the Indexer loads the complete DC→Cloud ID mapping table. By default it is fetched in a single call to the Atlassian mapping service (part of the Atlassian Cloud Migration Assistant), but it can also be loaded from a pre-downloaded CSV file via --idmappings.

Important: When using a local CSV file, make sure it is up to date with the current state of the Jira DC instance. A stale mapping file may produce incorrect Cloud IDs or miss newly migrated resources.

Endpoint called:

GET <dcBaseUrl>/rest/migration/latest/report/id-mappings
    ?cloudSiteUrl=<cloudBaseUrl>&invalidateCache=false

The response is a CSV file with this format:

entityType,serverId,cloudId
jira:remoteLink,11001,10665
jira/classic:project,10100,10198
...

The following entity types are extracted and used by this tool. All others are silently ignored.

Entity type in CSVUsed for
jira/classic:project Identifies which DC projects have been migrated; provides the Cloud project ID used in GC version and association updates.
jira:issue Resolves Cloud issue IDs — needed to build the remote link update URL.
jira:remoteLink Resolves Cloud remote link IDs.
jira:projectVersion Resolves Cloud project version IDs for GC version link updates.

When fetched via REST and the mapping report is not yet ready, the call is retried up to 5 times with 10-second delays between attempts. HTTP or network errors are retried up to 3 times, with the same delay. If the report is still unavailable after all retries, the run aborts with a clear message and no files are written.

On success, the fetched CSV is saved to the output directory as id-mappings_<timestamp>.csv (e.g. id-mappings_20260612_143052.csv) for traceability and later reuse. The Updater's --verify reads the latest of these files to check administrator rights.