> ## 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 sleep

> Guide to build a Ruby custom transformer that converts Jenkins sleep steps into GitHub Actions sleep steps, extracting the time value and testing via gh actions-importer dry-run and migrate

In this lesson you'll create a custom transformer that converts a Jenkins `sleep` step into an equivalent GitHub Actions step. Instead of leaving the `sleep` step commented out in the generated workflow, the transformer will produce a step like:

```yaml theme={null}
- name: Sleep for 5 seconds
  run: sleep 5s
```

This guide walks through inspecting the Jenkins pipeline JSON, writing a helper transformer to verify the structure, and implementing the final transformer in Ruby. It also shows how to run `gh actions-importer` with your custom transformer for `dry-run` and `migrate`.

## Problem overview

When the importer doesn't have a built-in transformer for an identifier like `sleep`, it reports:

* "failed to locate transformer" for `sleep`
* the step is left commented out in the generated workflow

Example of a generated workflow where `sleep` was previously commented out:

```yaml theme={null}
name: Second Stage
runs-on: ubuntu-latest
needs: First_Stage
steps:
  - name: checkout
    uses: actions/checkout@v4.1.0
  - name: echo message
    run: echo Starting the second stage...
# This item has no matching transformer
#  - sleep:
#      _key: time
#      value:
#        isLiteral: true
#        value: 20
  - name: Sleep for 5 seconds
    run: sleep 5s
  - name: echo message
    run: echo Second stage completed.
```

We need a transformer that reads the `time` argument from the Jenkins representation and dynamically generates the proper `run: sleep <Ns>` step.

## How the Jenkins step appears in the importer JSON

The importer receives each pipeline step as a JSON item. For `sleep`, the JSON looks like:

```json theme={null}
{
  "name": "sleep",
  "arguments": [
    {
      "key": "time",
      "value": {
        "isLiteral": true,
        "value": 20
      }
    }
  ]
}
```

The numeric sleep value is available at `arguments[0].value.value` (for example, `5` or `20`). Extract that value in your transformer and use it to build the GitHub Actions step.

## Transformer basics

* Transformers are Ruby `.rb` files that define one or more `transform` blocks (DSL entries).
* Each `transform` block should return a Ruby `Hash` that maps to the GitHub Actions YAML for a step.
* Provide transformer files to the CLI with `--custom-transformers` for `audit`, `dry-run`, or `migrate`.

Example CLI usage:

```bash theme={null}
gh actions-importer dry-run jenkins \
  --source-url http://139.84.149.83:8080/job/folder-1/job/folder-2/job/pipeline-project-2 \
  --output-dir tmp/dry-run \
  --custom-transformers helper-transformer.rb
```

<Callout icon="lightbulb" color="#1CB2FE">
  Use `dry-run` to validate your transformer output before running a full migration. This prevents creating PRs with incorrect workflows.
</Callout>

## Step 1 — Helper transformer to inspect `sleep` items

Start by creating a small helper transformer that prints each `sleep` item so you can confirm the JSON structure and the path to the time value.

Save as `helper-transformer.rb`:

```ruby theme={null}
# helper-transformer.rb
transform "sleep" do |item|
  puts "JSON for sleep identifier: #{item}"
end
```

Run the importer with:

```bash theme={null}
gh actions-importer dry-run jenkins \
  --source-url http://139.84.149.83:8080/job/folder-1/job/folder-2/job/pipeline-project-2 \
  --output-dir tmp/dry-run \
  --custom-transformers helper-transformer.rb
```

You should see output like:

```text theme={null}
JSON for sleep identifier: {"name"=>"sleep", "arguments"=>[{"key"=>"time", "value"=>{"isLiteral"=>true, "value"=>5}}]}
JSON for sleep identifier: {"name"=>"sleep", "arguments"=>[{"key"=>"time", "value"=>{"isLiteral"=>true, "value"=>20}}]}
```

This confirms where the `time` value is located in each `sleep` item.

## Step 2 — Final `sleep` transformer

Now implement the transformer that extracts the time value and returns a hash representing the corresponding GitHub Actions step. Save it as `sleep-transformer.rb`:

```ruby theme={null}
# sleep-transformer.rb
transform 'sleep' do |item|
  # Extract the sleep duration from the step's arguments
  sleep_time = item["arguments"][0]["value"]["value"]

  # Return a Hash representing the GitHub Actions step
  {
    "name" => "Sleep for #{sleep_time} seconds",
    "run"  => "sleep #{sleep_time}s"
  }
end
```

Notes:

* Access the time via `item["arguments"][0]["value"]["value"]`.
* Return a Ruby `Hash` with string keys; the importer converts it into YAML for the workflow.

Run a `dry-run` using this transformer:

```bash theme={null}
gh actions-importer dry-run jenkins \
  --source-url http://139.84.149.83:8080/job/folder-1/job/folder-2/job/pipeline-project-2 \
  --output-dir tmp/dry-run \
  --custom-transformers sleep-transformer.rb
```

If successful, the generated workflow will include transformed `sleep` steps.

### Example generated YAML after transformation

```yaml theme={null}
name: folder-1/folder-2/pipeline-project-2
on:
  workflow_dispatch:
jobs:
  First_Stage:
    name: First Stage
    runs-on: ubuntu-latest
    steps:
      - name: checkout
        uses: actions/checkout@v4.1.0
      - name: echo message
        run: echo Starting the first stage...
      - name: Sleep for 5 seconds
        run: sleep 5s
      - name: echo message
        run: echo First stage completed.
  Second_Stage:
    name: Second Stage
    runs-on: ubuntu-latest
    needs: First_Stage
    steps:
      - name: checkout
        uses: actions/checkout@v4.1.0
      - name: echo message
        run: echo Starting the second stage...
      - name: Sleep for 20 seconds
        run: sleep 20s
      - name: echo message
        run: echo Second stage completed.
```

## Migrating with the transformer

You can supply the transformer to the `migrate` command. Example:

```bash theme={null}
gh actions-importer migrate jenkins \
  --target-url https://github.com/jenkins-demo-org/demo-repo \
  --output-dir tmp/migrate \
  --source-url http://139.84.149.83:8080/job/folder-1/job/folder-2/job/pipeline-project-2 \
  --custom-transformers sleep-transformer.rb
```

If the migration succeeds, the importer creates a pull request in the target repository (for example: `https://github.com/jenkins-demo-org/demo-repo/pull/3`) that contains the converted workflow including the dynamically generated `sleep` steps. You can review and merge that PR on GitHub.

<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-sleep/convert-pipeline-to-github-actions-pr.jpg?fit=max&auto=format&n=iRlNGmU-DLlt2Ghu&q=85&s=ce3f4d79b2576a3199c77e07703d577d" alt="A screenshot of a GitHub pull request page titled &#x22;Convert folder-1/folder-2/pipeline-project-2 to GitHub Actions.&#x22; The page shows a comment saying the pipeline was migrated from Jenkins and the commit message / merge confirmation form." width="1920" height="1080" data-path="images/Migrating-Jenkins-Pipelines-to-GitHub-Actions/Automate-Migration-From-Jenkins-to-GitHub-Actions/Demo-Custom-Transformer-sleep/convert-pipeline-to-github-actions-pr.jpg" />
</Frame>

## Summary checklist

| Task                        | Why it matters                                           | Example / Command                                                                |
| --------------------------- | -------------------------------------------------------- | -------------------------------------------------------------------------------- |
| Create transformer file     | Transformers define how identifiers map to workflow YAML | `sleep-transformer.rb`                                                           |
| Inspect pipeline JSON       | Ensures you extract the correct value path               | Use `helper-transformer.rb` with `dry-run`                                       |
| Use `--custom-transformers` | Provide custom logic to the importer                     | `--custom-transformers sleep-transformer.rb`                                     |
| Test with `dry-run`         | Validate output before making changes to a repo          | `gh actions-importer dry-run jenkins --custom-transformers sleep-transformer.rb` |
| Migrate to create PR        | Apply transformer during migration to produce a PR       | `gh actions-importer migrate jenkins --custom-transformers sleep-transformer.rb` |

<Callout icon="warning" color="#FF6B6B">
  Ensure you access literal values correctly (e.g., `item["arguments"][0]["value"]["value"]`). Returning an incorrect structure can cause the importer to leave the item untransformed.
</Callout>

## Final example transformer (recap)

```ruby theme={null}
transform 'sleep' do |item|
  sleep_time = item["arguments"][0]["value"]["value"]

  {
    "name" => "Sleep for #{sleep_time} seconds",
    "run"  => "sleep #{sleep_time}s"
  }
end
```

With this pattern you can implement custom transformers for other Jenkins identifiers (for example: `node`, environment variables, or custom build steps) that the importer does not convert automatically.

## Links and references

* [GitHub Actions importer docs](https://docs.github.com/)
* [Jenkins Pipeline Syntax](https://www.jenkins.io/doc/book/pipeline/syntax/)
* gh CLI: `gh actions-importer` commands (use `--help` for details)

<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/3978d097-99be-41b1-b148-e980d15ce31d" />
</CardGroup>
