> ## 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 Convert Jenkins Job to GitHub Actions Workflow

> Migrating a Jenkins freestyle job to a manually triggered GitHub Actions workflow that reproduces shell steps and installs required packages.

In this lesson we'll migrate a simple Jenkins freestyle job into a GitHub Actions workflow. The goal is to replicate the Jenkins job behavior (a sequence of shell steps run on a single node) by creating a single-job workflow that can be manually triggered from the Actions UI.

Below are the original Jenkins job and its build steps, followed by a concise GitHub Actions workflow that reproduces the same execution flow on `ubuntu-latest`.

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/mG-4fV495woj9hgT/images/Migrating-Jenkins-Pipelines-to-GitHub-Actions/Manual-Migration-From-Jenkins-to-GitHub-Actions/Demo-Convert-Jenkins-Job-to-GitHub-Actions-Workflow/jenkins-dark-ci-pipeline-jobs.jpg?fit=max&auto=format&n=mG-4fV495woj9hgT&q=85&s=435339ad400f34fd76b7f5df7e84f593" alt="A dark-themed Jenkins dashboard screenshot showing a list of CI pipeline jobs (ci-pipeline-poll-scm, Generate ASCII Artwork, scripted-pipeline, solar-system-ci-pipeline) with columns for last success, failure, and duration. The left sidebar shows navigation items like New Item, Build History, Manage Jenkins and a Build Queue panel." width="1920" height="1080" data-path="images/Migrating-Jenkins-Pipelines-to-GitHub-Actions/Manual-Migration-From-Jenkins-to-GitHub-Actions/Demo-Convert-Jenkins-Job-to-GitHub-Actions-Workflow/jenkins-dark-ci-pipeline-jobs.jpg" />
</Frame>

This migration focuses on the "Generate ASCII Artwork" freestyle job. Open its configuration to inspect the build steps and options.

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/mG-4fV495woj9hgT/images/Migrating-Jenkins-Pipelines-to-GitHub-Actions/Manual-Migration-From-Jenkins-to-GitHub-Actions/Demo-Convert-Jenkins-Job-to-GitHub-Actions-Workflow/jenkins-configure-generate-ascii-job.jpg?fit=max&auto=format&n=mG-4fV495woj9hgT&q=85&s=1f3b029ccd4fdc9c8c8f3aeec6bbd0eb" alt="A screenshot of the Jenkins web UI showing the &#x22;Configure&#x22; page for a job (Generate ASCII Artwork) with the General settings panel, description field, and several option checkboxes. The sidebar lists other sections (Source Code Management, Triggers, Environment, Build Steps) and Save/Apply buttons are visible at the bottom." width="1920" height="1080" data-path="images/Migrating-Jenkins-Pipelines-to-GitHub-Actions/Manual-Migration-From-Jenkins-to-GitHub-Actions/Demo-Convert-Jenkins-Job-to-GitHub-Actions-Workflow/jenkins-configure-generate-ascii-job.jpg" />
</Frame>

Key characteristics of this Jenkins job:

* No source control is configured (it was run manually in Jenkins).
* No automated triggers (built manually).
* No environment variables defined.
* Several shell build steps that run sequentially on one build node.

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/mG-4fV495woj9hgT/images/Migrating-Jenkins-Pipelines-to-GitHub-Actions/Manual-Migration-From-Jenkins-to-GitHub-Actions/Demo-Convert-Jenkins-Job-to-GitHub-Actions-Workflow/jenkins-config-triggers-environment-checkboxes.jpg?fit=max&auto=format&n=mG-4fV495woj9hgT&q=85&s=2444cd608f678c4ec4dc6f50e9880cf3" alt="A dark-themed Jenkins &#x22;Configure&#x22; settings screen showing the Triggers and Environment sections with multiple checkboxes (e.g., Poll SCM, Build periodically). The left sidebar lists job configuration tabs like General, Source Code Management, Triggers, and Build Steps." width="1920" height="1080" data-path="images/Migrating-Jenkins-Pipelines-to-GitHub-Actions/Manual-Migration-From-Jenkins-to-GitHub-Actions/Demo-Convert-Jenkins-Job-to-GitHub-Actions-Workflow/jenkins-config-triggers-environment-checkboxes.jpg" />
</Frame>

Below is the core shell script the Jenkins job ran. It:

* Calls the adviceslip API to fetch a piece of advice.
* Validates the advice contains more than five words.
* Installs `cowsay` and prints the advice as ASCII art.

```bash theme={null}
# Build a message by invoking the adviceslip API
curl -s https://api.adviceslip.com/advice > advice.json
cat advice.json

# Extract the advice text and validate it has more than 5 words
jq -r .slip.advice < advice.json > advice.message
if [ "$(wc -w < advice.message)" -gt 5 ]; then
  echo "Advice has more than 5 words"
else
  echo "Advice - $(cat advice.message) has 5 words or less"
  exit 1
fi

# Install cowsay and display the advice as ASCII artwork
sudo apt-get update
sudo apt-get install -y cowsay jq
echo "$PATH"
export PATH="$PATH:/usr/games:/usr/local/games"
cat advice.message | cowsay -f "$(ls /usr/share/cowsay/cows | shuf -n 1)"
```

Migration approach summary:

* Jenkins freestyle -> GitHub Actions single job.
* Keep the same shell flow, but place it in one multi-line `run` step.
* Use `workflow_dispatch` to allow manual triggering from the Actions UI.
* Install required packages (`jq`, `cowsay`) on the runner before use.

Below is an example multi-job workflow (for reference) illustrating jobs, dependencies, environment variables, and artifacts in GitHub Actions:

```yaml theme={null}
name: Demo-2

on:
  workflow_dispatch:

env:
  GREETING: "Hello"

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Create a text file
        run: echo "${{ env.GREETING }}, ${{ secrets.WORLD }}!" > hello.txt
      - uses: actions/upload-artifact@v4
        with:
          name: hello-file
          path: hello.txt

  test:
    runs-on: ubuntu-latest
    needs: build
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: hello-file
      - name: List files
        run: ls
      - name: Test file
        run: grep -i "Hello, world!" hello.txt
```

For our single-job migration, create a file at `.github/workflows/generate-ascii.yaml` with `workflow_dispatch` so it can be triggered manually. Here is a concise, robust workflow that reproduces the Jenkins behavior:

```yaml theme={null}
name: Generate ASCII Artwork

on:
  workflow_dispatch:

jobs:
  build-ascii:
    runs-on: ubuntu-latest
    steps:
      - name: Generate advice and show ASCII art
        run: |-
          # Install jq (used below) and cowsay so the runner has required tools
          sudo apt-get update
          sudo apt-get install -y jq cowsay

          # Build a message by invoking the adviceslip API
          curl -s https://api.adviceslip.com/advice > advice.json
          cat advice.json

          # Extract the advice text and validate it has more than 5 words
          jq -r .slip.advice < advice.json > advice.message
          if [ "$(wc -w < advice.message)" -gt 5 ]; then
            echo "Advice has more than 5 words"
          else
            echo "Advice - $(cat advice.message) has 5 words or less"
            exit 1
          fi

          # Display the advice as ASCII artwork
          echo "$PATH"
          export PATH="$PATH:/usr/games:/usr/local/games"
          cat advice.message | cowsay -f "$(ls /usr/share/cowsay/cows | shuf -n 1)"
```

<Callout icon="lightbulb" color="#1CB2FE">
  Best practice: Put package installation at the top of your step so required tools are available before they are referenced. If you need persistent environment variables or secrets, declare them at the workflow or job level using `env:` or GitHub Secrets.
</Callout>

Quick mapping: Jenkins freestyle fields to GitHub Actions equivalents

| Jenkins concept                        | GitHub Actions equivalent                               | Example                            |                          |
| -------------------------------------- | ------------------------------------------------------- | ---------------------------------- | ------------------------ |
| Manual job run                         | `workflow_dispatch` trigger                             | `on: workflow_dispatch:`           |                          |
| Shell build steps (sequential)         | Single job with a multi-line `run` step                 | Use \`run:                         | -\` and paste the script |
| Environment variables at job level     | `env:` on workflow/job                                  | `env: GREETING: "Hello"`           |                          |
| Artifacts uploaded for downstream jobs | `actions/upload-artifact` / `actions/download-artifact` | `uses: actions/upload-artifact@v4` |                          |

Open the Actions tab in your repository and trigger the workflow manually. The job log will show output for each command just like Jenkins.

<Frame>
  <img src="https://mintcdn.com/kodekloud-c4ac6d9a/mG-4fV495woj9hgT/images/Migrating-Jenkins-Pipelines-to-GitHub-Actions/Manual-Migration-From-Jenkins-to-GitHub-Actions/Demo-Convert-Jenkins-Job-to-GitHub-Actions-Workflow/github-actions-demo-2-workflows-sidebar.jpg?fit=max&auto=format&n=mG-4fV495woj9hgT&q=85&s=b6803c2bb3b412ca655cf9393dd85f2d" alt="A dark-theme GitHub Actions page showing a repository's workflows and sidebar (including a &#x22;Generate ASCII Artwork&#x22; entry). The main panel lists recent workflow runs (several &#x22;Demo-2&#x22; entries) with success/failure icons, branch tags and timestamps." width="1920" height="1080" data-path="images/Migrating-Jenkins-Pipelines-to-GitHub-Actions/Manual-Migration-From-Jenkins-to-GitHub-Actions/Demo-Convert-Jenkins-Job-to-GitHub-Actions-Workflow/github-actions-demo-2-workflows-sidebar.jpg" />
</Frame>

Example log snippets you’ll see:

* The adviceslip JSON and the validation success message:

```bash theme={null}
{"slip":{"id":162,"advice":"Stop using the term \"busy\" as an excuse."}}
Advice has more than 5 words
```

* Installation output and the generated ASCII artwork:

```text theme={null}
Reading package lists...
Building dependency tree...
Reading state information...
The following NEW packages will be installed:
  cowsay
0 upgraded, 1 newly installed, 0 to remove and 13 not upgraded.
Fetched 18.6 kB in 0s (156 kB/s)
Selecting previously unselected package cowsay.
(Reading database ...)
Unpacking cowsay (3.03+dfsg2-8) ...
Setting up cowsay (3.03+dfsg2-8) ...
/ Stop using the term "busy" as an \
\ excuse. /
-------------------------------
\
 \
/@   ~-.
/\  _-- |
 // // @
```

If the advice has five words or fewer, the step prints the advice and exits with code 1, causing the job to fail. Example failure output:

```bash theme={null}
{"slip":{"id":6,"advice":"Never cut your own fringe."}}
Advice - Never cut your own fringe. has 5 words or less
Error: Process completed with exit code 1.
```

<Callout icon="warning" color="#FF6B6B">
  Note: When a script exits with a non-zero status, GitHub Actions marks the step and job as failed. Design your exit codes intentionally if you rely on failure vs. success conditions for downstream steps or notifications.
</Callout>

References and useful links:

* GitHub Actions documentation: [https://docs.github.com/actions](https://docs.github.com/actions)
* Upload artifact action: [https://github.com/actions/upload-artifact](https://github.com/actions/upload-artifact)
* Download artifact action: [https://github.com/actions/download-artifact](https://github.com/actions/download-artifact)
* adviceslip API: [https://api.adviceslip.com/](https://api.adviceslip.com/)

Next steps:

* If you need to preserve job-level environment variables, add `env:` at the workflow or job level.
* To split work into stages, convert sequential shell steps into separate jobs and use `needs:` to express dependencies.
* A follow-up lesson will cover converting a multi-stage Jenkins pipeline into a multi-job GitHub Actions workflow.

<CardGroup>
  <Card title="Watch Video" icon="video" cta="Learn more" href="https://learn.kodekloud.com/user/courses/migrating-jenkins-pipelines-to-github-actions/module/f63e67f3-f04a-474f-87b9-ae17930e9e67/lesson/4ba668de-f1a8-4b73-826d-416dd231e069" />
</CardGroup>
