← All case studies Jenkins → GitHub Actions

Slack used GitHub's importer plus an intern tool on 242 Jenkins pipelines

Emmanuel Zerefa's December 2024 intern post covers 242 pipelines on three Jenkins instances. The importer fully converted about half. The 1,300 hours saved is a model, not a finished measurement.

Emmanuel Zerefa wrote this on 16 December 2024, after a summer internship at Slack. Slack’s own engineering blog published it.

Developers were tired of Jenkins. He names security issues, downtime, and a poor day-to-day experience. Internal pressure pushed a majority of Slack’s CI jobs toward GitHub Actions. His project was a converter, so developers would spend less time rewriting pipelines by hand.

At the start they had 242 Jenkins pipelines, hosted on three Jenkins instances. A pipeline here means one or more ordered Jenkins jobs. A workflow is the GitHub Actions version.

The Jenkins → GitHub Actions playbook is the generic checklist. This post is about the audit, the repair tool, and a time model. It is not a report that all 242 pipelines were deleted from Jenkins.

What the importer did

They used GitHub’s Actions Importer. You install it with the GitHub CLI, configure it, and audit an instance:

gh actions-importer audit jenkins --output-dir <output-dir>

The audit writes a workflow file per pipeline, plus a summary of full conversions, partial conversions, and failures.

About half the pipelines converted with no importer error. About 5% failed completely. The rest were partial. A partial run still wrote YAML, and left the file incomplete.

Hundreds of pipelines missed a full conversion. Eight unsupported Jenkins build steps and environments explained more than 90% of those misses. That shrunk the research job from dozens of odd steps down to eight. For each one they asked whether GitHub Actions had an equivalent, and whether a script could patch the importer’s YAML.

Four repairs, and where the model sat

They still read the “fully converted” files. Trusting the importer’s own label was not enough. After several dozen YAML files, they sorted the fixes into four kinds.

Marketplace actions were calling github.com and hitting rate limits. Slack replaced those with internal mirrors on their GitHub Enterprise instance, where the limits are higher.

Some steps used an action Slack did not want. The importer often picked rtCamp/action-slack-notify for Slack messages. They wanted an internal slack/message-action instead. The field names do not line up, so string replace was a poor fit. This is the slice they gave to a language model.

Secrets were the manual leftover. The generated YAML assumed secrets lived on GitHub. Slack does not store secrets there, and moving them would break policy. The tool could only leave a comment telling the owner to read secrets from the real store, and which Slack channel had the docs.

Partial conversions also left comments of the form “this Jenkins item was unsupported.” A lot of those items were already implied by Actions, or were unnecessary. Deleting the comment was a declutter, with a small payoff.

The repair tool reads a directory of workflow files, applies the string edits, then the model edits, and writes each file back in place. Building it took about three weeks. The model was one of the four categories. The rest was Python replace.

They checked about two dozen model outputs on the action-swap task and saw the requested edits land each time. That check is their sample, on one prompt, for one action pair. It is not a claim about every pipeline.

The hour model

A manual conversion, as he breaks it down, is write the workflow, debug it, document it, then delete the Jenkins pipeline. The tool is meant to skip the writing and shorten the debugging.

He prices the human time like this. Someone strong in both tools: 2 hours. Strong in Jenkins only: 5 hours. New to both: 10 hours. He assumes a mix of 10%, 40%, and 50%. That lands near 1,700 hours for all 242 pipelines.

With the tool, he assumes half the pipelines need no edits, because half fully converted, and the other half takes about 3 hours to debug. That is about 360 hours. The difference is a bit over 1,300 hours, which he calls about 80% of the manual total.

The opening summary says the tool is expected to cut migration time in half. The hour table says 80%. Both numbers are projections. He had not measured a finished org-wide migration.

Two weeks after the YAML was published, feedback was arriving. People found the files useful, and they also found errors. He kept a Slack Canvas of each miss and the fix. The post stops there. It does not say Jenkins was turned off.

What I would copy

Run the importer audit before you staff a rewrite. Slack’s useful surprise was that eight step types caused most of the incomplete files. Fix those eight, then look at the long tail.

Read the files the audit marks as complete. A full conversion in the summary can still point at the wrong Slack action, or at secrets you will not put on GitHub.

If you publish a saved-hours number, label the mix of people and the hours you assumed. Slack did that in the post. A later reader can still mistake 1,300 hours for time already saved. It was a spreadsheet.

Keep secrets where your policy already keeps them. The generated secrets context was the line they refused to automate.

The Jenkins → GitHub Actions playbook covers the cutover Slack had not finished in public. Use this post for the 50% audit rate and for the habit of patching the importer’s YAML before a developer sees it.