Skip to main content
In this lesson we build a custom transformer to convert a Jenkins catchError wrapper used in a Code Coverage stage into equivalent GitHub Actions steps. Jenkins’s catchError lets a failing step continue the pipeline while setting a specific build or stage result. When migrating to GitHub Actions we want the workflow to run the same coverage command, continue on error so downstream jobs still run, and preserve HTML artifacts for later inspection. This article walks through the original Jenkins stage, the parsed AST-like representation the importer prints in dry-run, the Ruby transformer implementation, the importer dry-run invocation and output, the generated GitHub Actions job snippet, and the run results.

Jenkinsfile snippet (Code Coverage stage — original)

What the importer sees (AST-like JSON)

Run the importer in dry-run mode to print parsed identifiers and their arguments. In this case the importer detected a catchError node whose child is a sh invocation of the coverage command. Sample parsed representation for catchError (converted to valid JSON for clarity):

Approach — desired mapping to GitHub Actions

Goal: mirror Jenkins behavior so coverage failures do not block the pipeline, but HTML reports are still produced and uploaded. Steps:
  • Extract the inner coverage command from item.dig("children", 0, "arguments", 0, "value", "value").
  • Fall back to npm run coverage if the command is not found.
  • Emit two GitHub Actions steps:
    1. Install dependencies: npm install --no-audit.
    2. Run coverage: set continue-on-error: true so the workflow continues even if the command exits non‑zero.
  • Let the existing importer conversion handle publishHTMLactions/upload-artifact@v4 (artifact upload of the coverage HTML).

Transformer implementation (helper-transformer.rb)

The transformer below is added to the importer’s custom transformers so that catchError nodes are converted into a lightweight sequence of GitHub Actions steps.

Running the importer dry-run

Use the gh actions-importer tool in dry-run mode to test extraction and transformation without writing the final workflows.
Example (abridged) dry-run output showing the parsed catchError and the output file produced:

Resulting GitHub Actions job (excerpt)

The generated Code Coverage job includes checkout, dependency installation, the coverage step with continue-on-error: true, and artifact upload for the HTML report.

Pull request diff (abridged)

The transformer replaced the untranslated catchError block in the PR diff with two explicit steps that install dependencies and run the coverage command with continue-on-error.

What happened when the workflow ran

  • A new workflow run was triggered after merging the PR.
  • The Code Coverage job executed the two transformed steps:
    • The npm install --no-audit step completed.
    • The npm run coverage step failed the coverage threshold (exit code non-zero).
  • Because continue-on-error: true was set, the job continued and downstream jobs also ran.
  • The coverage HTML report was uploaded as an artifact and is available for download from the run.
A screenshot of a GitHub Actions workflow run showing the pipeline summary on the left, a visualization of jobs at the top, and an Annotations panel listing errors (Code Coverage failed and two canceled runs). Below is an Artifacts list with reports like "Code Coverage HTML Report" and "Dependency Check HTML Report."
You can download the artifact (Code Coverage HTML Report) and inspect it locally:
A dark‑theme Windows File Explorer window showing the contents of a "Code Coverage HTML Report.zip" with a list of HTML, CSS, JS and PNG files (e.g., app.js.html, base.css, index.html). The left navigation pane shows drives and folders and the right preview area says "Select a file to preview."

Code coverage failure (abridged)

This is an example of the coverage output that caused the coverage command to exit non-zero:
Using continue-on-error: true in the converted step mirrors Jenkins catchError semantics: it allows the workflow to continue and still upload artifacts even when the coverage command fails. Note that GitHub Actions will mark that step as successful for continuation, so consider also surfacing the failure via annotations, test result upload, or a PR comment if you want to preserve visibility of the failure state.

Mapping summary

Example of a JSON-like transformer output is represented in the helper-transformer.rb implementation above.

References

Summary

  • We added a custom transformer that:
    • Detects a catchError node and extracts the inner shell command (defaults to npm run coverage).
    • Emits two GitHub Actions steps: an installation step and a coverage step with continue-on-error: true.
  • The importer still converts publishHTML to actions/upload-artifact automatically, preserving HTML reports as artifacts.
  • This keeps the pipeline behavior consistent: coverage failures do not block downstream jobs while reports remain available for inspection.

Watch Video