Skip to content
Latchkey LogoLatchkey home

GitHub Actions Importer: what it converts and what it leaves for you

GitHub Actions Importer is a GitHub CLI extension, gh actions-importer, that runs in Docker and converts pipelines from Azure DevOps, Bamboo, Bitbucket Pipelines, CircleCI, GitLab, Jenkins and Travis CI into GitHub Actions workflows. Its audit, forecast, dry-run and migrate commands inventory a CI server, estimate Actions usage, convert one pipeline to local files and open a pull request, while secrets, runners and unknown plugins or orbs remain manual.

You have more pipelines than you want to convert by hand, and you want to know which ones will convert cleanly before you promise a date. That is the job the Importer does best: it reads the CI server, converts every pipeline it can, and writes a report that sorts them by how much is left to do.

It is not a finished migration. GitHub's documentation sets the goal at 80% conversion per workflow and says every converted workflow should be inspected before it runs production work. This page covers each command, the files they write, the per-platform manual work, and the mapping details that change behavior.

Importer subcommands in order: configure, audit, forecast, dry-run, migrate, with their outputs
The five subcommands in the order to run them, with what each reads and writes. Only migrate opens a pull request.

Install it and configure credentials

The Importer is a container image plus a gh extension that drives it, so it needs Docker running and the GitHub CLI installed. It does not have to run on the CI server; it talks to it over the API.

configure prompts for a GitHub personal access token (classic) with the repo and workflow scopes, which migrate uses to open pull requests, plus the URL and token for your CI system, and writes them to .env.local. update pulls the latest image. The extension itself last tagged a release, v1.3.6, in October 2023; the converter ships in the image, so run update before each session.

Terminal
gh extension install github/gh-actions-importer
gh actions-importer update
gh actions-importer configure
gh actions-importer version

Which platforms, and how each names a pipeline

All seven platforms support all four planning and conversion commands. What differs is the subcommand and the flag that identifies one pipeline for dry-run and migrate.

PlatformSubcommandNames one pipeline with
Jenkinsjenkins--source-url (the job URL)
GitLab, cloud or self-managedgitlab--namespace and --project
CircleCIcircle-ci--circle-ci-project
Azure DevOpsazure-devops pipeline or release--pipeline-id
Bamboobamboo build or deployment--plan-slug or --deployment-project-id
Bitbucket Pipelinesbitbucket--workspace and --repository
Travis CItravis-ci--travis-ci-repository

Audit, then forecast

audit fetches every project on the server, converts each one and writes audit_summary.md beside the converted files. Pipelines land in four buckets: successful (everything converted), partially successful (the structure converted, some items did not), unsupported, and failed, which usually means the original was invalid or the token could not read it. Build steps are counted as known, unknown or unsupported, and a Manual tasks section lists the secrets and self-hosted runner labels you have to create. workflow_usage.csv lists the actions, secrets and runners each pipeline uses, which is the list a security review wants.

forecast reads completed runs, the previous seven days by default, and reports job count, execution time, queue time and concurrent jobs. Execution time is your minutes estimate and concurrent jobs is your runner count. On Jenkins it needs the paginated-builds plugin installed first.

Terminal
gh actions-importer audit jenkins --output-dir tmp/audit
gh actions-importer audit gitlab --output-dir tmp/audit --namespace my-group
gh actions-importer audit circle-ci --output-dir tmp/audit --include-from repositories.txt
gh actions-importer forecast jenkins --output-dir tmp/forecast

What it converts, and what it leaves for you

Each platform guide on docs.github.com publishes a supported-syntax table and a list of constructs you must migrate manually. The manual lists are short and worth reading before the audit, because they predict most of the Manual steps section in every pull request.

PlatformConvertsLeft for you
JenkinsDeclarative stage, docker; partially agent, environment, steps, triggers, when. Not matrix, options, parameters or inputScripted pipelines, secrets, self-hosted runners, unknown plugins, mandatory build tools
GitLabscript, needs, stages, tags, variables, image, resource_group, schedule; partially rules, only/except, include, services, parallel, environmentMasked project or group variable values, artifact reports; no caching between jobs of different workflows
CircleCIJobs, steps, executors to runs-on, matrix, when/unless, cron; partially orbs, container and servicesContexts, project-level environment variables, unknown job properties, unknown orbs; self-hosted executors unsupported

Dry run with custom transformers

dry-run converts one pipeline and writes the workflow to disk. This is where you shape the output before anything reaches a repository. Custom transformers are Ruby files passed with --custom-transformers: runner maps a source label to an Actions label, env rewrites or removes a variable or points it at a secret, and transform replaces an unknown build step, such as a Jenkins shared library call, with steps you define.

Map runners first. The documentation states that a label the Importer cannot map becomes ubuntu-latest, and runner :default changes that fallback.

transformers.rb
# transformers.rb
runner "linux", "ubuntu-latest"
runner "big-agent", ["self-hosted", "xl", "linux"]
runner :default, "ubuntu-latest"

env "REGISTRY_PASSWORD", secret("REGISTRY_PASSWORD")

transform "deployService" do |item|
  { name: "deploy", run: "./scripts/deploy.sh" }
end

# then:
# gh actions-importer dry-run jenkins --source-url https://jenkins.example.com/job/app \
#   --output-dir tmp/dry-run --custom-transformers transformers.rb

Migrate, and the mappings to check by hand

migrate runs the same conversion and opens a pull request against --target-url. Its description carries a Manual steps section, usually the secrets to create. Merge only after the first run on a branch is green.

Read the environment variable mappings before you trust a converted condition. The Importer maps Jenkins BUILD_NUMBER to github.run_id, a large unique id, not the per-workflow counter github.run_number, so image tags change shape. It maps GitLab CI_COMMIT_BRANCH and CircleCI CIRCLE_BRANCH to github.ref, which is refs/heads/main, so a comparison against main silently goes false. GitHub's sample list-features output also shows actions/cache and reusable-workflows disabled; check yours and turn them on with --enable-features if your target supports them.

Terminal
gh actions-importer list-features
gh actions-importer migrate jenkins \
  --source-url https://jenkins.example.com/job/app \
  --target-url https://github.com/my-org/app \
  --output-dir tmp/migrate \
  --custom-transformers transformers.rb \
  --enable-features actions/cache

Key takeaways

  • Run audit across the server first; its four buckets are your migration order.
  • forecast turns past runs into minutes and concurrency, the two numbers a runner choice needs.
  • Secrets, runner labels, contexts and unknown plugins or orbs are always manual.
  • Check converted conditions: branch variables map to the full github.ref, and BUILD_NUMBER maps to github.run_id.

Frequently asked questions

Which CI platforms does GitHub Actions Importer support?
Azure DevOps, Bamboo, Bitbucket Pipelines, CircleCI, GitLab (cloud and self-managed), Jenkins and Travis CI. Each has its own subcommand and its own guide on docs.github.com listing supported syntax and manual tasks.
Does GitHub Actions Importer migrate secrets?
No. The audit and the migration pull request list the secrets the converted workflows reference, and you create them in GitHub yourself. For GitLab, masked variable values are explicitly a manual task, and for CircleCI so are contexts and project-level environment variables.
Can GitHub Actions Importer convert scripted Jenkins pipelines?
No. GitHub lists scripted pipelines among the Jenkins constructs you must migrate manually. Declarative Jenkinsfiles and Freestyle jobs convert, fully or partially, and the audit tells you which.
Does the Importer need to run on my CI server?
No. It needs Docker and the GitHub CLI on any Linux-container-capable machine, plus API access to the CI server with a token that can read every job you want to audit. For Jenkins, folders that do not inherit permissions need explicit access for that token.

References

Every converted job gets a runs-on label. Latchkey is one transformer line away. Start free → 30-day trial · No credit card