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.
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:
- Log in to the registry - Authenticate with the CodeCargo container registry using your generated token
- Configure and download the credentials file - Configure the connection in the CodeCargo UI, then download the generated
.envfile - Run the importer - Execute the Docker container using the credentials file
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.
localhostis rejected, since inside the importer's containerlocalhostrefers to the container itself rather than your host machine; usehttp://host.docker.internal:8080for 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.
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:
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.
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).
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.ymlfiles - 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.
Repository Link Resolution
When importing Azure DevOps pipelines, Migration Assistant resolves each pipeline's repository link using two facts, in order:
- 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 ado2ghoutside CodeCargo are traced from their Migration Log issue. - 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
extendsandtemplatereferences 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:
| Badge | Status | Description |
|---|---|---|
| Source missing | Red | The pipeline's source file cannot be found |
| Pending scan | Yellow | Template references an unprovisioned but known repository |
| Unknown repo | Gray | Template references a repository not in CodeCargo |
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
localhostinside 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.
