CodeCargo logo

Migration

Importing Data

Import Overview

The first phase of any migration is getting your legacy CI/CD data into Migration Assistant. There are two ways to import from each source system:

  • Run the importer - A containerized importer connects to your live Jenkins instance, Azure DevOps organization, or GitLab instance and extracts data directly through its API. This is the standard path.
  • Upload a JSON export - If you already have a pre-exported JSON file (for example, produced by an earlier importer run or shared by another team), upload it under Migrate → Pipelines → Import → JSON and continue straight to the mapping wizard.

Every importer starts from the Import button on the Pipelines dashboard (Migrate → Pipelines in the organization sidebar), which lists one card per source system plus the JSON upload.

The Import Migration Data page with four cards: Import from Jenkins, Import from Azure DevOps, and Import from GitLab, each with a Start Import button, and Import from JSON with an Upload JSON button.

In both cases, only metadata and configuration are imported. Sensitive credential values are never extracted or stored — credentials are imported as definitions only, and you recreate their values as GitHub Secrets during mapping.

Setting Up the Importer

The Jenkins and Azure DevOps importers run as a Docker container on your machine (or any host with network access to your source system) and connect back to CodeCargo using a downloaded credentials file. Setup follows three steps, designed so that sensitive tokens never appear in your shell history:

  1. Log in to the registry - Authenticate with the CodeCargo container registry using your generated token
  2. Configure and download the credentials file - Configure the connection in the CodeCargo UI, then download the generated .env file
  3. Run the importer - Execute the Docker container using the credentials file
Where the importer runs. The importer container runs on your machine, or any host in your network, with the downloaded .env credentials file. It reads the source system's API (Jenkins, Azure DevOps, or GitLab) inside your network and sends metadata and configuration to CodeCargo over HTTPS. The source token you fill into the .env file stays on your machine, and credential values are never extracted.Your networkYour machineCredentials file (.env)CodeCargo API credentialsSource token, filled inlocally, never uploadedImporter containerdocker run withthe .env fileSourcesystemJenkins, ADO,or GitLabAPICodeCargoJobs, plugins,credential names— never valuesHTTPS
The importer runs inside your network. Only metadata and configuration reach CodeCargo.

Configuring the Connection

You configure the importer in the CodeCargo UI before downloading the credentials file, rather than hand-editing the .env file afterwards:

  • Jenkins - Provide your Jenkins controller URL. localhost is rejected, since inside the importer's container localhost refers to the container itself rather than your host machine; use http://host.docker.internal:8080 for a Jenkins instance running locally.
  • Azure DevOps - Provide your organization name (a full URL is rejected here) and choose an import scope: specific repositories via a CSV list, specific project names, or everything in the organization.
  • On-premises Azure DevOps Server - Toggle On-Premises Server under the organization field to switch to a full server URL. The scope CSV template is automatically stamped with the URL's collection segment, which the importer matches against.

Once your configuration is complete, the page shows a summary of what will be downloaded — organization or server, scope, and import mode. Click View file contents if you want to inspect the raw .env file before downloading. The Download button stays disabled until your configuration is complete, and if you change settings after downloading, a warning lets you know the downloaded file is stale.

The Download the credentials file card for Azure DevOps: an Import mode selector set to Merge - keep items not in this import (default), and a summary with Organization acme, Scope Projects: Commerce, Analytics, Infrastructure, Mobile, To fill in yourself Azure DevOps PAT, and the import mode, with View file contents, Copy, and Download.

Environment-Aware URLs

The importer setup page automatically displays the correct controller and registry URLs for your environment (development, staging, production). Local development mode pre-populates the Jenkins URL as http://host.docker.internal:8080 for convenience.

For GitLab, provide a full http:// or https:// instance URL (prefilled https://gitlab.com) and a Group when the host is gitlab.com. Loopback addresses (localhost, 127.0.0.1, and similar) are rejected, since inside the container they refer to the container itself; use http://host.docker.internal:... for GitLab running on your machine. Don't paste a gitlab.com group page as the URL — the host must be the instance host. On a self-managed instance, leave Group empty to import every group.

The Credentials File

The downloaded .env file includes:

  • Pre-filled CodeCargo API credentials
  • Template entries for your source-system authentication — Jenkins URL, username, and API token, or your Azure DevOps Personal Access Token
  • Import mode configuration (if not using the default merge-keep mode)

Fill in the source-system authentication entries locally in your editor — these secrets stay on your machine and are never sent to or stored by CodeCargo. After the import completes, delete the credentials file to remove sensitive tokens from your local filesystem.

Sources Behind a Proxy

If Jenkins, Azure DevOps, or GitLab sits behind an identity-aware proxy — such as Cloudflare Access, an API gateway, or a corporate reverse proxy — the importer also sends the headers that proxy issued. The downloaded credentials file includes a commented example next to the source token. Uncomment the line for your source and replace the placeholders with the values from the proxy:

Shell
JENKINS_EXTRA_HEADERS={"CF-Access-Client-Id":"<client-id>","CF-Access-Client-Secret":"<client-secret>"}

Azure DevOps uses ADO_EXTRA_HEADERS and GitLab uses GITLAB_EXTRA_HEADERS. The value is a single line of JSON mapping each header name to its value. Leave the line commented when no proxy sits in front of the source; an untouched file sends no extra headers.

The values are proxy credentials. They stay in the file on your machine, and a run logs only the header names. Don't set a header the importer already sends, such as Authorization or PRIVATE-TOKEN — put source credentials in the importer's own token variable. A Cookie header is the exception: it is combined with any session cookie the source requires. A value that is not valid JSON, or that names a header the importer already sets, stops the run at startup and names the variable to fix.

Watching an Import

When you run the Jenkins, Azure DevOps, or GitLab importer, entities are applied as they arrive. The import page shows a live banner for the run in progress — including a Stop import button — and an Import runs card with recent runs.

A live banner reading An import from Azure DevOps is running, naming jlee on build-agent-07, when it started and its last activity, with a Stop import button; below it the Import runs card lists the running run with 2 of 4 units and 611 of 1,057 items applied, and two completed runs with their driver, duration, created, updated, and deleted counts, and Post-import steps done.

If the importer is interrupted, run the same Docker command with the same credentials file. It continues from where it left off; nothing already imported is rolled back.

While an import is running for an instance, you cannot change that instance's entities, add them to batches or waves, or run discovery and planning against them. Wait for the import to finish, or click Stop import on the import page. Only one import can run at a time for each source (Jenkins, Azure DevOps, or GitLab).

An instance page banner: An import is running, dev.azure.com/acme, started by jlee on build-agent-07. Entity edits, mappings, batches and waves for this instance are locked until it finishes.

Jenkins Import

Start a Jenkins import under Migrate → Pipelines → Import → Jenkins. The importer extracts data directly from your Jenkins API.

What Gets Imported

  • Jobs and Pipelines - All job configurations and pipeline definitions
  • Plugins - Installed plugins and their configurations
  • Credentials - Credential definitions (values are not imported for security)
  • Shared Libraries - Global pipeline libraries
  • System Configuration - Relevant Jenkins system settings

Organization Folders

Jenkins organization folders scan a GitHub organization, Gitea or Bitbucket owner, or GitLab group and generate a multibranch pipeline for each matching repository. The importer treats the organization folder as a folder and each generated pipeline as a child job.

For those jobs, and for any other multibranch project that uses a GitHub, Gitea, Bitbucket, or GitLab branch source, the importer fills in the repository name and clone URL from the branch source. Use that link when you map jobs to repositories.

Folder-Scoped Shared Libraries

In addition to global pipeline libraries, the importer reads libraries defined on a folder, an organization folder, or a multibranch project. Each library appears under the folder that defines it. Two folders can define a library with the same name and keep them separate.

Discovery resolves a job's library by name from the job's folder upward, and the nearest definition wins — including over a global library of the same name. An implicit library, which the folder loads for its jobs without an explicit load, applies only to jobs under that folder. A job outside the folder does not pick it up.

Azure DevOps Import

Start an Azure DevOps import under Migrate → Pipelines → Import → Azure DevOps. The importer extracts data directly from the Azure DevOps REST API.

Importing pipeline definitions is separate from connecting Azure DevOps for repository migration. A connection inventories repositories and pipeline counts; the importer CLI is still what brings pipeline definitions themselves into Migration Assistant, and the connection page links to it.

What Gets Imported

  • YAML Pipelines - Modern Azure Pipelines definitions from azure-pipelines.yml files
  • Classic Build Definitions - Legacy build configurations (flagged as anti-patterns)
  • Classic Release Pipelines - Release definitions and deployment stages
  • Tasks and Templates - Referenced tasks and reusable template dependencies
  • Service Connections - External service integrations
  • Variable Groups - Shared variables and secret references
  • Secure Files - Certificate and key file references
  • Agent Pools - Build agent configurations
  • Environments - Deployment target environments

Pipeline Types

Azure DevOps pipelines are handled differently based on their type:

YAML Pipelines

  • The pipeline source file (e.g. azure-pipelines.yml) lives in its repository. When you launch a migration workspace, the file is attached as a read-only linked file so the AI agent can read it directly from disk — the content is not copied onto the entity record.
  • Template and task references are tracked for dependency mapping.

Classic Pipelines

  • Build and Release definitions are imported as JSON because no in-repository file exists; the imported definition is the source of truth.
  • Can be viewed through the "View Pipeline Definition (JSON)" option.

Repository Linking

For YAML pipelines to appear correctly in the migration workspace, ensure the source repository is linked and active in your CodeCargo organization. See GitHub Integration for how repositories are connected.

When importing Azure DevOps pipelines, Migration Assistant resolves each pipeline's repository link using two facts, in order:

  1. Relocation map — if the source repository was migrated to GitHub with GitHub Enterprise Importer, the pipeline links to its migrated repository. Migrations run from Migrating Repositories record this relocation directly; migrations run with gh ado2gh outside CodeCargo are traced from their Migration Log issue.
  2. Repository name match — for pipelines whose repository has no relocation record yet (it was never migrated, or an external migration hasn't been traced yet), Migration Assistant falls back to matching against your CodeCargo repository names.

A pipeline's existing repository link is never cleared by an import that can't resolve a reference — a link is only ever replaced by a positive match, so re-importing after editing your source data can't accidentally undo a manual mapping.

Migrated Repositories

If your pipeline's repository was migrated with GitHub Enterprise Importer — from inside CodeCargo or with gh ado2gh — you don't need to manually map it. Migration Assistant links it automatically from the relocation record, even if the initial import couldn't resolve it by name.

Anti-Pattern Detection

The Azure DevOps importer automatically identifies legacy patterns that should be modernized:

  • Classic Build/Release pipelines - Flagged for conversion to YAML
  • Deprecated tasks - Tasks that have newer alternatives
  • Security anti-patterns - Configurations that don't follow current best practices

These anti-patterns are highlighted during the mapping process to help prioritize modernization efforts.

GitLab Import

Start a GitLab import under Migrate → Pipelines → Import → GitLab. The importer connects to the GitLab API for gitlab.com or your self-managed instance.

On gitlab.com (and its subdomains) a Group path is required before you can download the credentials file — a pasted group URL is rejected, and surrounding slashes are stripped. On a self-managed instance, leave Group empty to import every group. After downloading, set GITLAB_TOKEN in the file (read_api scope; a Reporter or Maintainer role on the group is sufficient) and run the docker run command shown on the page.

Importing pipeline definitions is separate from connecting GitLab for repository migration. A connection inventories groups and projects on GitLab.com; this importer is still what brings pipeline definitions into Migration Assistant.

Post-Import Discovery

After an import completes, Migration Assistant automatically analyzes your source data to map reusable-code dependencies. Discovery results surface in the dashboard and detail panels to help you plan migration order.

Jenkins Shared-Library Discovery

Migration Assistant runs post-import discovery for Jenkins shared libraries, building a comprehensive inventory of library dependencies:

  • Library Surface Scanning - Inventories all shared-library entrypoints and available functions
  • Usage Resolution - Associates each imported job with the library elements it uses
  • Dependency Mapping - Creates intra-library reference edges and job entrypoint relationships
  • Inline Script Analysis - Analyzes jobs with inline pipeline scripts without requiring repository mapping

Discovery parses the Groovy source of your Jenkins pipelines and shared libraries to extract structural facts, providing detailed insights into library usage patterns across your organization.

Automatic Discovery

Shared-library discovery runs automatically after Jenkins import and can analyze both repository-backed jobs and jobs with inline pipeline scripts.

Azure DevOps Pipeline Template Discovery

Migration Assistant analyzes imported Azure DevOps pipelines to identify reusable template references and track their availability:

  • Resolves template chains - Follows extends and template references to build the complete dependency graph
  • Cross-repository resolution - Identifies templates in other repositories within your workspace
  • File status tracking - Verifies whether referenced template files actually exist
  • Dependency mapping - Creates a persistent graph of template relationships

Pipeline entities display status badges in the dashboard and detail panels:

BadgeStatusDescription
Source missingRedThe pipeline's source file cannot be found
Pending scanYellowTemplate references an unprovisioned but known repository
Unknown repoGrayTemplate references a repository not in CodeCargo
The Azure DevOps instance table filtered to pipelines: sms-sdk-ci carries a red Source missing badge, tax-proxy-deploy-prod a yellow Pending scan badge, and feature-flags-ui-pr-check a gray Unknown repo badge with no repository.

Discovery runs automatically after import, but you can trigger it manually from Migration Assistant → Dev Tools → Run Discovery, selecting the organization or a specific instance and monitoring progress in the job logs.

Discovery Scope

Discovery resolves same-repository template chains completely and performs one hop of cross-repository resolution. Templates in unprovisioned repositories are flagged for future processing when those repositories are added to CodeCargo.

Entity Dependencies and Impact Analysis

After discovery runs, Migration Assistant builds a persistent dependency graph that powers the Dependencies and Used by sections in every entity detail panel.

Dependencies (what a job relies on)

When you open a job's detail panel or in-editor view, the Dependencies section lists every entity that job relies on — reusable pipeline elements (templates, shared-library functions) and task plugins discovered from the pipeline source. Each entry shows the dependency's name, type, and migration status so you can assess readiness at a glance. Container-level entries (e.g., a shared library) are collapsed when a more specific element from that library is already listed, keeping the list focused.

Used by (what relies on a plugin)

Plugin entities (Azure DevOps tasks, Jenkins plugins) display a Used by section listing every job and template that references them. This lets you understand the blast radius of a plugin before you migrate or deprecate it.

Plugins are context, not migration units

Plugin entities are tracked in the dependency graph for impact analysis but are not migration units themselves. They never appear in the batch dependency advisory and cannot be added to a migration batch — only jobs and reusable pipeline elements are batch members.

Troubleshooting Imports

Connection failures

  • Verify the source URL and authentication credentials in your credentials file
  • Check network connectivity and firewall rules between the importer container and your source system
  • For Jenkins, ensure the Jenkins API is enabled and accessible; remember that localhost inside the container is not your host machine

Incomplete data import

  • Review the source-system permissions of the importing user — the importer can only see what that account can see
  • For Jenkins, check for plugin compatibility issues and verify Jenkins version compatibility

Next Step

With your data imported and discovery complete, continue to Mapping to configure how it translates to GitHub Actions.