Skip to main content
In this lesson you will learn how to use a custom transformer to translate source CI/CD runner labels into equivalent GitHub Actions runners and to centralize environment variable mappings. This is useful when migrating pipelines (for example, from Jenkins) that reference self-hosted agents or custom labels so they run on GitHub-hosted runners like ubuntu-latest.
A blue-to-teal gradient presentation slide with the title "Custom Transformer — runner variables" centered. A small "© Copyright KodeKloud" appears in the bottom-left.
What the transformer provides
  • A runner helper to map a source runner label to one or more GitHub Actions runner labels.
  • env helpers to centralize environment variables or map them to repository secrets.
Common runner mapping examples
Source labelGitHub Actions label(s)Notes
linuxubuntu-latestSingle-label mapping (string)
big-agent["self-hosted", "xl", "linux"]Multiple labels (array) for self-hosted runners
Example mappings (Ruby syntax):
runner "linux", "ubuntu-latest"

runner "big-agent", ["self-hosted", "xl", "linux"]
  • First parameter: source CI/CD runner label (string).
  • Second parameter: GitHub Actions label(s), either a string or an array of strings.
Dry-run the importer to preview generated workflows Run a one-time dry-run of the importer to produce the converted workflow files (trimmed output shown):
gh actions-importer dry-run jenkins \
  --source-url http://139.84.149.83:8080/job/ci-pipeline-poll-scm/ \
  --output-dir tmp/dry-run \
  --custom-transformers ss-pipeline-transformer.rb

# Example output (trimmed)
[2025-05-22 13:00:39] Logs: 'tmp/dry-run/log/valet-20250522-130039.log'
[2025-05-22 13:00:40] Output file(s):
    tmp/dry-run/ci-pipeline-poll-scm/.github/workflows/ci-pipeline-poll-scm.yml
Original converted workflow (example) Some jobs in the converted workflow may still reference self-hosted runner labels and agent-specific labels, for example:
on:
  push:
    branches:
      - main
  schedule:
    - cron: '00 00 * * *'
env:
  MONGO_URI: mongodb+srv://supercluster.d83jj.mongodb.net/superData
  MONGO_USERNAME: superuser
  MONGO_PASSWORD: "${{ secrets.mongo_db_password }}"
jobs:
  Installing_Dependencies:
    name: Installing Dependencies
    runs-on:
      - self-hosted
      - us-west-1-ubuntu-22
    container:
      image: node:24
Update the transformer to map runners and envs To replace source labels with GitHub-hosted runners and to centralize environment variables, add mappings at the top of your transformer file (for example ss-pipeline-transformer.rb). Example transformer mappings:
# Map environment variables (set literal or map to secrets)
env "MONGO_USERNAME", "superuser"
env "MONGO_PASSWORD", secret("mongo_db_password")
env "MONGO_DB_CREDS", nil

# Map Jenkins/JB agent label to GitHub Actions runner
runner "us-west-1-ubuntu-22", "ubuntu-latest"
When writing the mapping lines, ensure correct Ruby syntax (commas between parameters). For instance: runner "us-west-1-ubuntu-22", "ubuntu-latest".
Re-run the dry-run with your custom transformer After saving the transformer, run the dry-run again to regenerate the workflow with the mapped runners and centralized env entries:
gh actions-importer dry-run jenkins \
  --source-url http://139.84.149.83:8080/job/ci-pipeline-poll-scm/ \
  --output-dir tmp/dry-run \
  --custom-transformers ss-pipeline-transformer.rb
Resulting workflow (example) The importer will now emit workflows using the mapped runners and the transformed environment variable entries:
name: ci-pipeline-poll-scm
on:
  push:
    branches:
      - main
  schedule:
    - cron: 00 00 * * *
env:
  MONGO_URI: mongodb+srv://supercluster.d83jj.mongodb.net/superData
  MONGO_USERNAME: superuser
  MONGO_PASSWORD: "${{ secrets.mongo_db_password }}"
jobs:
  Installing_Dependencies:
    name: Installing Dependencies
    runs-on:
      - ubuntu-latest
    container:
      image: node:24
Next steps and references
  • Review all runner mappings in your transformer to ensure coverage for every agent label used in source pipelines.
  • Use env to centralize common variables and secret("...") to map values to repository secrets.
Links and references

Watch Video