> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Demo Custom Transformer environment variable

> Explains using a custom Ruby transformer to map, convert to secrets, or remove Jenkins environment variables when migrating pipelines to GitHub Actions

In this lesson we demonstrate how to use a custom transformer to add, map, or remove environment variables while converting Jenkins pipelines into GitHub Actions workflows. The transformer lets you:

* Map Jenkins env vars to GitHub Actions env vars
* Convert Jenkins variables into GitHub Actions secrets
* Remove variables from the generated workflow

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/iRlNGmU-DLlt2Ghu/images/Migrating-Jenkins-Pipelines-to-GitHub-Actions/Automate-Migration-From-Jenkins-to-GitHub-Actions/Demo-Custom-Transformer-environment-variable/custom-transformer-environment-variables-slide.jpg?fit=max&auto=format&n=iRlNGmU-DLlt2Ghu&q=85&s=bd63a719927a9a6e0b4f1a6c07b27f7d" alt="A presentation slide with the title &#x22;Custom Transformer — environment variables&#x22; centered on a blue-green gradient background. A small &#x22;© Copyright KodeKloud&#x22; appears in the bottom-left corner." width="1920" height="1080" data-path="images/Migrating-Jenkins-Pipelines-to-GitHub-Actions/Automate-Migration-From-Jenkins-to-GitHub-Actions/Demo-Custom-Transformer-environment-variable/custom-transformer-environment-variables-slide.jpg" />
</Frame>

Overview

* The custom transformer runs during the import/dry-run and modifies the resulting workflow's `env` section.
* You author rules in a small Ruby DSL file that the importer evaluates to translate or remove variables.
* This process is especially useful for mapping credential references to GitHub Actions secrets.

Transformer syntax examples
Below are common transformer directives used in the Ruby DSL. You can place these in a transformer file (e.g., `ss-pipeline-transformer.rb`).

```ruby theme={null}
env "OCTO", "CAT"                 # map OCTO -> CAT (literal)
env "MONA_LISA", nil              # remove MONA_LISA from output
env "MONALISA", secret("OCTOCAT") # map MONALISA -> secret named OCTOCAT
```

You can match multiple variables using regular expressions:

```ruby theme={null}
env /.*/, nil                     # remove all environment variables
```

Quick reference

| Transformer directive       | Purpose                       | Example                                             |
| --------------------------- | ----------------------------- | --------------------------------------------------- |
| `env "NAME", "value"`       | Map a literal value           | `env "MONGO_USERNAME", "superuser"`                 |
| `env "NAME", secret("KEY")` | Use a GitHub Actions secret   | `env "MONGO_PASSWORD", secret("mongo_db_password")` |
| `env "NAME", nil`           | Remove a variable from output | `env "MONGO_DB_CREDS", nil`                         |

Jenkins pipeline example
This is the Jenkinsfile we will convert — a simple two-stage pipeline triggered by poll SCM:

```groovy theme={null}
stages {
  stage('First Stage') {
    steps {
      echo 'Starting the first stage...'
      sleep 5
      echo 'First stage completed.'
    }
  }

  stage('Second Stage') {
    steps {
      echo 'Starting the second stage...'
      sleep 20
      echo 'Second stage completed.'
    }
  }
}
```

Dry-run conversion (initial)
First, run a dry-run conversion without any custom transformer to inspect the base output and see which environment variables remain unresolved:

```bash theme={null}
gh actions-importer dry-run jenkins \
  --source-url http://139.84.149.83:8080/job/ci-pipeline-poll-scm/ \
  --output-dir tmp/dry-run
```

Example dry-run output (summarized):

```console theme={null}
[2025-05-22 12:54:02] Logs: 'tmp/dry-run/log/valet-20250522-125402.log'
[2025-05-22 12:54:06] Output file(s):
    tmp/dry-run/ci-pipeline-poll-scm/.github/workflows/ci-pipeline-poll-scm.yml
```

Generated workflow (excerpt)
The importer generates a workflow that often requires manual tuning. Here are representative excerpts to show where env vars appear and how some items may be left as commented placeholders when the importer doesn't have a mapping.

Example job (Trivy scan):

```yaml theme={null}
Trivy Vulnerability Scanner:
  name: Trivy Vulnerability Scanner
  runs-on:
    - self-hosted
    - us-west-1-ubuntu-22
  needs: Build_Publish_Image
  steps:
    - name: checkout
      uses: actions/checkout@v4.1.0
    - name: sh
      shell: bash
      run: trivy image siddharth67/solar-system:$GIT_COMMIT --severity CRITICAL --exit-code 1 --quiet --format json -o trivy-image-CR
    - name: sh
      shell: bash
      run: trivy convert --format template --template "@/usr/local/share/trivy/templates/html.tpl" --output trivy-image-CRITICAL-resu
    - name: Upload Artifacts
      uses: actions/upload-artifact@v4.1.0
      with:
        if-no-files-found: ignore
        name: Trivy Image Critical Vul Report
        path: "."
```

Workflow header, triggers and environment (note the converted cron and partially converted env vars):

```yaml theme={null}
name: ci-pipeline-poll-scm
on:
  push:
    branches:
      - main
  schedule:
    - cron: "0 0 * * *"
env:
  MONGO_URI: mongodb+srv://supercluster.d83jj.mongodb.net/superData
#  # This item has no matching transformer
# MONGO_DB_CREDS:
#  # This item has no matching transformer
# MONGO_USERNAME:
#  # This item has no matching transformer
# MONGO_PASSWORD:
jobs:
  Installing_Dependencies:
    name: Installing Dependencies
    runs-on:
      - self-hosted
      - us-west-1-ubuntu-22
    container:
      image: node:24
    steps:
      - name: checkout
        uses: actions/checkout@v4.1.0
      - name: sh
        shell: bash
        run: npm install --no-audit
```

Why some env vars were not transformed

* The importer converts SCM polling to a GitHub Actions cron schedule automatically.
* Credential references stored in Jenkins credential stores are typically not transformed by default. Those appear as commented placeholders with the message `# This item has no matching transformer`.
* Use a custom transformer to explicitly map these variables to literals or `secrets`.

Creating a custom transformer to handle environment variables
Create a transformer file (for example `ss-pipeline-transformer.rb`) and use `env` directives to add mappings, mark values as secrets, or remove variables.

Example transformer (Ruby DSL):

```ruby theme={null}
# ss-pipeline-transformer.rb
env "MONGO_USERNAME", "superuser"
env "MONGO_PASSWORD", secret("mongo_db_password")
env "MONGO_DB_CREDS", nil
```

* `secret("mongo_db_password")` indicates the importer should reference the GitHub Actions secret named `mongo_db_password`.
* Setting a variable to `nil` removes it from the generated workflow.

Run dry-run with the custom transformer
Re-run the importer specifying the transformer file:

```bash theme={null}
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
```

<Callout icon="warning" color="#FF6B6B">
  If you see a message such as:

  ```bash theme={null}
  [2025-05-22 12:58:53] No custom transformers found at path: /data/ss-pipeline-transformer.rb
  ```

  it usually means the transformer path is incorrect relative to your current working directory. Verify the file exists (for example `ls ss-pipeline-transformer.rb`) and either run the command from that directory or supply an absolute path to `--custom-transformers`.
</Callout>

Resulting transformed workflow (excerpt)
After applying the custom transformer, the `env` section reflects the mappings and secrets:

```yaml theme={null}
name: ci-pipeline-poll-scm
on:
  push:
    branches:
      - main
  schedule:
    - cron: "0 0 * * *"
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:14
    ...
```

Best practices and tips

<Callout icon="lightbulb" color="#1CB2FE">
  * Keep transformer files in your project repository and reference them with a relative or absolute path to avoid "not found" errors.
  * Prefer mapping credentials to GitHub Actions secrets rather than hard-coding sensitive values.
  * Use regular expressions cautiously to avoid accidentally removing environment variables you need.
</Callout>

Summary

* Use `env "NAME", "value"` to map literals, `env "NAME", secret("KEY")` to map to GitHub Actions secrets, and `env "NAME", nil` to remove variables from the generated workflow.
* If the importer cannot find your custom transformer, verify the path and working directory or use an absolute path.
* This article focuses on env var transformation; other Jenkins-specific constructs (e.g., complex credential bindings or specialized plugins) may require additional custom handling and are covered separately.

Links and references

* [GitHub Actions: Secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets)
* [gh actions-importer — CLI repository / documentation](/)

<CardGroup>
  <Card title="Watch Video" icon="video" cta="Learn more" href="https://learn.kodekloud.com/user/courses/migrating-jenkins-pipelines-to-github-actions/module/3b5e500f-482a-4860-9f2c-d5f9fbc95159/lesson/d9e086da-5595-4bd8-9f86-767774b8eb56" />
</CardGroup>
