Build a CI/CD Pipeline with GitHub Actions

Automate Python testing on every push with a GitHub Actions CI pipeline.

Introduction

30 Second Summary

Imagine pushing code to your team's project and finding out days later that it broke something. Bugs that slip through cost time, trust, and momentum.

In this project, you will build an automated CI/CD pipeline using GitHub Actions. Every time you push code, your pipeline runs your test suite and tells you right away if something is broken.

What You'll Build

A fully automated CI pipeline for a Python calculator app that runs your test suite on every push to GitHub.

By the end of this project, you'll have:

  • A Python calculator module with arithmetic functions and a pytest test suite.
  • A GitHub Actions workflow that automatically tests your code on every push.
  • A live status badge on your repository README showing your pipeline's current health.
  • Secret Mission: Add a pull request gate that blocks merging when tests fail.

Are there any prerequisites?

You just need basic comfort with the command line. No prior CI/CD or DevOps experience needed.

Create a GitHub Repository and Clone It Locally

A CI/CD pipeline needs somewhere to live. Your code, tests, and workflow configuration files all go into a single repository.

In this step, you'll create that repository on GitHub and clone it to your local machine. Once cloned, every local change you make can be pushed up to trigger your pipeline.

In this step, get ready to:
  • Create a public repository on GitHub called python-ci-demo.
  • Clone the repository to your local machine.
  • Open the project in VS Code and verify the setup.
Create a new public repository on GitHub
  • Open your browser and go to github.com. Sign in to your account.
  • Click the + icon in the top-right corner of the page.
  • Select New repository from the dropdown.
  • Enter python-ci-demo in the Repository name field.
  • Select Public for the repository visibility.
  • Check the Add a README file checkbox.
  • Click Create repository.

Why a public repository?

GitHub Actions provides unlimited free minutes for public repositories. This means your CI pipeline will run at no cost throughout the entire project.

GitHub redirects you to your new repository page. You should see python-ci-demo at the top and a README.md file listed in the file browser.

Clone the repository and open it in VS Code

Cloning creates a local copy of your remote repository on your computer. This lets you edit files locally and push changes back to GitHub using Git.

First, grab the clone URL from your repository page.

  • On your new repository page on GitHub, click the green Code button.
  • Make sure HTTPS is selected.
  • Click the clipboard icon to copy the URL.

Now open a terminal to run the clone command.

  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type Terminal (macOS) or PowerShell (Windows) and press Enter to open it.
  • Move to your Desktop and clone the repository by running these commands:
cd ~/Desktop
git clone [[REPO_URL="the HTTPS URL you copied"]]

What do these commands do?

  • cd ~/Desktop moves your terminal to the Desktop folder so the project lands somewhere easy to find.
  • git clone downloads a full copy of your GitHub repository to your computer, including all its Git history.
  • Confirm the folder was created by running:
ls

You should see python-ci-demo listed in the output.

Don't see python-ci-demo?

  • Double-check the URL you pasted. It should look like https://github.com/your-username/python-ci-demo.git.
  • Make sure you ran cd ~/Desktop first. If you cloned from a different directory, the folder is wherever your terminal was pointing.
  • If you see a "repository not found" error, make sure your repository on GitHub is set to Public and that your username in the URL is correct.

Why did my git clone command fail?

Now open the cloned project in VS Code.

  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type Visual Studio Code and press Enter to open it.
  • Click File in the top menu bar.
  • Click Open Folder.
  • Navigate to your Desktop, select the python-ci-demo folder, and click Open.

Trust the authors prompt

VS Code may ask if you trust the authors of the files in this folder. Click Yes, I trust the authors to continue.

Verify your setup

Two things confirm your setup is correct. The README.md file is visible in your editor, and Git reports a clean working directory.

  • In VS Code, look at the Explorer sidebar on the left. You should see README.md listed.
  • Open VS Code's built-in terminal by pressing Ctrl+` (this shortcut works on both macOS and Windows).
  • Check that Git sees no uncommitted changes by running this command:
git status

You should see a message that says On branch main and nothing to commit, working tree clean.

Seeing something different?

  • If git status says fatal: not a git repository, your terminal is not inside the python-ci-demo folder. Close and reopen the VS Code terminal, or run cd ~/Desktop/python-ci-demo and try again.
  • If you see modified or untracked files, make sure you have not accidentally edited or added anything to the folder yet.

Why is git status showing unexpected output?

Your repository is set up and connected. Next, you'll build a Python calculator module and write tests for it.

Build a Python Calculator Module and Test Suite

In Step 1, you set up your GitHub repository and cloned it to your local machine. Now it's time to write the code that your CI pipeline will eventually test.

You'll create a simple Python calculator module and a matching test suite using pytest. This gives your pipeline something meaningful to check every time you push code.

In this step, get ready to:
  • Create a Python calculator module with four arithmetic functions.
  • Write a pytest test suite that covers each function.
  • Run the tests locally to confirm everything passes.
Create the calculator module

The calculator module is the application code that your CI pipeline will test. It contains four simple arithmetic functions.

  • In VS Code's Explorer sidebar, hover over the python-ci-demo folder name at the top.
  • Click the New File icon (a page with a plus sign).
  • Type calculator.py and press Enter.
  • Copy the following code into the new file:
def add(a, b):
    return a + b


def subtract(a, b):
    return a - b


def multiply(a, b):
    return a * b


def divide(a, b):
    if b == 0:
        raise ValueError("Cannot divide by zero")
    return a / b

What does this code do?

This module defines four functions that each take two numbers (a and b) and return the result of an arithmetic operation.

The divide function is the most interesting one. It checks whether b is zero before dividing, and raises a ValueError if so. This is the kind of edge case that automated tests are great at catching.

  • Save calculator.py by pressing Cmd+S (macOS) or Ctrl+S (Windows).

You won't see any output yet. The test suite in the next substep will verify this code works correctly.

File not appearing in the sidebar?

Make sure you created the file directly inside the python-ci-demo folder, not inside a subfolder. You should see calculator.py at the same level as README.md in the Explorer sidebar.

Why isn't my calculator.py file showing up in VS Code?

Write a test suite with pytest

A test suite is a collection of checks that verify your code behaves the way you expect. Each test calls a function with specific inputs and confirms the output matches.

What is pytest?

pytest is the most popular testing framework for Python. It automatically discovers functions that start with test_ and runs them as test cases.

You write simple assert statements to check values. If an assertion fails, pytest reports exactly which test broke and why.

  • In the Explorer sidebar, hover over the python-ci-demo folder name again.
  • Click the New File icon.
  • Type test_calculator.py and press Enter.
  • Copy the following code into the new file:
import pytest
from calculator import add, subtract, multiply, divide


def test_add():
    assert add(2, 3) == 5
    assert add(-1, 1) == 0
    assert add(0, 0) == 0


def test_subtract():
    assert subtract(5, 3) == 2
    assert subtract(0, 5) == -5
    assert subtract(-1, -1) == 0


def test_multiply():
    assert multiply(3, 4) == 12
    assert multiply(-2, 3) == -6
    assert multiply(0, 100) == 0


def test_divide():
    assert divide(10, 2) == 5.0
    assert divide(-6, 3) == -2.0
    assert divide(7, 2) == 3.5


def test_divide_by_zero():
    with pytest.raises(ValueError, match="Cannot divide by zero"):
        divide(10, 0)

What does this code do?

The first two lines import pytest and the four functions from your calculator.py module. Each test_ function tests one calculator function with multiple inputs.

The last function, test_divide_by_zero, uses a special pattern: pytest.raises(ValueError). This tells pytest to expect an error. The test passes only if calling divide(10, 0) raises a ValueError with the message "Cannot divide by zero".

  • Save test_calculator.py by pressing Cmd+S (macOS) or Ctrl+S (Windows).

You won't see any output yet. The next substep runs these tests to verify everything works.

Red squiggly lines under the import?

VS Code might show a warning on the from calculator import line. This is just the editor trying to resolve the import before you've run the code. You can safely ignore it.

Make sure calculator.py and test_calculator.py are in the same folder. If they are in different folders, the import will fail when you run the tests.

Why is VS Code showing an import error for my calculator module?

Run the tests locally

Before your CI pipeline can run tests automatically, you should confirm they pass on your own machine first. This way you know the tests themselves are correct.

  • Open the terminal in VS Code by pressing Ctrl+` (backtick key, located above Tab on your keyboard).
  • Install pytest by running this command:
pip install pytest

What does this command do?

`pip` is Python's package manager. This command downloads and installs the pytest library so you can use it to run your test file. If pytest is already installed, the command finishes instantly.

Seeing 'pip not found'?

Try running pip3 install pytest instead. Some systems use pip3 as the command name for Python 3's package manager.

Help me fix my pip installation issue.

  • Run the test suite by running this command:
python -m pytest test_calculator.py -v

What does this command do?

`python -m pytest` runs pytest as a Python module. The -v flag stands for "verbose", which means pytest will print the name and result of every individual test instead of just a summary.

You should see output showing all 5 tests passing with green PASSED labels next to each test name.

✔️ All 5 tests passed

Your calculator module and test suite are working correctly. You're ready to move on.

ⓧ I see errors or failures

Here are the most common causes:

  • ModuleNotFoundError: No module named 'calculator' means calculator.py and test_calculator.py are not in the same folder. Move them so they sit side by side in the python-ci-demo folder.
  • SyntaxError means there is a typo in your code. Double check your files against the code blocks above. Pay close attention to colons, parentheses, and indentation.
  • Make sure your terminal is in the python-ci-demo folder. VS Code's integrated terminal usually opens here automatically, but you can confirm by running pwd (macOS/Linux) or cd (Windows).

Help me debug my failing pytest tests.

Your calculator module and test suite are ready. Next, you'll write a GitHub Actions workflow that runs these tests automatically every time you push code.

Write Your First GitHub Actions Workflow

In the last step, you built a calculator module and wrote tests that verify it works. Those tests ran on your machine, but right now nobody is testing code automatically when it gets pushed to GitHub.

GitHub Actions is GitHub's built-in automation platform. You write workflow files that tell GitHub exactly what commands to run when specific events happen in your repository.

In this step, get ready to:
  • Create the .github/workflows/ directory and ci.yml workflow file.
  • Write a YAML workflow that runs your test suite on every push.
  • Commit and push all your project files to GitHub.
Create the workflow directory and file

GitHub Actions looks for workflow files in a specific location. Every workflow file must live inside the .github/workflows/ directory at the top level of your repository.

  • Create the .github/workflows/ directory and an empty ci.yml file by running these commands:

macOS

mkdir -p .github/workflows
touch .github/workflows/ci.yml

Windows

mkdir .github/workflows
New-Item .github/workflows/ci.yml

PowerShell will print some file information after the New-Item command. That's normal.

  • Confirm the file was created by running:
ls .github/workflows/

You should see ci.yml in the output.

Not seeing ci.yml?

  • Make sure your terminal is inside the python-ci-demo folder. Run pwd (macOS) or cd (Windows) to check your current directory.
  • Check for typos in the directory name. The leading dot in .github is required.
  • Why can't I see my workflow directory?
Write the CI workflow

Your workflow file is written in YAML, a human-readable format that uses indentation and key-value pairs to define configuration. Each section of the file controls a different part of your automation.

  • Open ci.yml in VS Code by clicking on it in the Explorer sidebar (expand .github then workflows).
  • Paste the following code into ci.yml:
# Name that appears in the GitHub Actions tab
name: CI

# Run this workflow on every push to any branch
on: [push]

jobs:
  test:
    # Use a GitHub-hosted Linux server
    runs-on: ubuntu-latest

    steps:
      # Pull your repository code onto the runner
      - name: Checkout code
        uses: actions/checkout@v6

      # Install Python on the runner
      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.13"

      # Upgrade pip and install your testing framework
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install pytest

      # Run your tests with verbose output
      - name: Run tests
        run: python -m pytest test_calculator.py -v

What does this workflow do?

  • name: CI gives your workflow a label that appears in the Actions tab on GitHub. CI stands for Continuous Integration.
  • on: [push] tells GitHub to run this workflow every time anyone pushes code to the repository.
  • runs-on: ubuntu-latest runs your job on a fresh Linux virtual machine hosted by GitHub. You don't need to set up or pay for a server.
  • The four steps check out your code, install Python 3.13, install pytest, and run your test suite.
  • Save ci.yml by pressing Cmd+S (macOS) or Ctrl+S (Windows).

You won't see the workflow run yet. It triggers after you push the file to GitHub in the next substep.

Seeing red squiggles in your YAML?

  • YAML is indentation-sensitive. Make sure you use spaces (not tabs) and that each level is indented by exactly 2 spaces.
  • Check that the python-version value is wrapped in quotes: "3.13". Without quotes, YAML may interpret it as a number instead of a version string.
  • Why is my YAML file showing errors?

✔️ Awesome, I've got everything!

Make sure you've saved ci.yml before moving on.

ⓧ I'd like to double check the full code

Here is the complete ci.yml file. Make sure yours matches exactly, including indentation.

name: CI

on: [push]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.13"

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install pytest

      - name: Run tests
        run: python -m pytest test_calculator.py -v
Commit and push to GitHub

Your workflow file only takes effect once it's on GitHub. Let's commit all your project files and push them to your repository.

  • Stage, commit, and push all your files by running these commands:
git add .
git commit -m "Add calculator, tests, and CI workflow"
git push

What do these commands do?

  • git add . stages every file in your project folder for commit. This includes calculator.py, test_calculator.py, and the .github/workflows/ci.yml file.
  • git commit saves a snapshot of those staged files with a descriptive message.
  • git push uploads your commit to GitHub. This is the moment that triggers your workflow.
  • Open your python-ci-demo repository on GitHub in your browser.
  • You should see calculator.py, test_calculator.py, and a .github/workflows directory listed in the file browser.

Push failed or files not showing up?

  • If git push asks for credentials, GitHub no longer accepts passwords. You need a personal access token or SSH key. Follow the prompts or check GitHub's authentication docs.
  • If you see nothing to commit, working tree clean, your files may already be committed. Run git status to check.
  • Hard-refresh the GitHub page (Cmd+Shift+R on macOS or Ctrl+Shift+R on Windows) if the files don't appear right away.
  • Why is my git push failing?

Your workflow file is now live on GitHub. In the next step, you'll watch GitHub Actions pick it up and run your tests automatically.

Watch Your Pipeline Run and Read the Logs

Your code, tests, and workflow file are all on GitHub. The moment you pushed, GitHub Actions detected your ci.yml file and kicked off your first pipeline run automatically.

In this step, you'll open the Actions tab and read the logs from that run. You'll see exactly what happened on a cloud server when your pipeline executed.

In this step, get ready to:
  • Find your first workflow run in the Actions tab.
  • Read the logs for each pipeline step.
  • Confirm every step passes with green checkmarks.
Navigate to the Actions tab
  • Open your python-ci-demo repository on GitHub in your browser.
  • Click the Actions tab near the top of the repository page.

You should see a workflow run listed under the CI workflow name. The run is labeled with your most recent commit message.

What am I looking at?

The Actions tab shows every workflow run triggered in your repository. Each row represents one run, with the commit message, branch name, and a status icon.

A yellow spinning circle means the run is still in progress. A green checkmark means it passed successfully.

Don't see any workflow runs?

  • Make sure you pushed your code in the previous step. Run git log --oneline -1 in your terminal to confirm your latest commit, then run git push if needed.
  • Check that your ci.yml file is inside the .github/workflows/ folder. GitHub Actions only detects workflows stored in that exact path.

Why isn't my GitHub Actions workflow showing up in the Actions tab?

Explore the job logs

Each workflow run contains one or more jobs. Your ci.yml defines a single job called test. Clicking into it reveals step-by-step logs showing everything that happened on the cloud server.

  • Click on the workflow run (the row with your commit message) to open it.
  • Click on the test job in the left sidebar.

You should see a list of steps with expandable log sections. Four of these steps match what you defined in your workflow file.

  • Click on the Checkout code step to expand its logs.

You should see log output showing GitHub downloading your repository's code onto the runner.

  • Click on the Set up Python step to expand its logs.

This log shows the runner installing Python 3.13 from its tools cache.

  • Click on the Install dependencies step to expand its logs.

You should see pip upgrading itself and then installing pytest.

  • Click on the Run tests step to expand its logs.

This is the most important step. You should see the same test output you saw when you ran pytest locally, with all five tests passing.

What is a GitHub-hosted runner?

A GitHub-hosted runner is a virtual machine in the cloud that GitHub spins up to execute your workflow. Your ci.yml specifies ubuntu-latest, which gives you a Linux server with 2 CPUs and 8 GB of RAM.

GitHub creates a fresh runner for every workflow run, so each run starts from a completely clean slate. Nothing lingers from a previous run.

Verify all steps pass with green checkmarks
  • Scroll through the job steps and confirm that every step has a green checkmark next to it.
  • Click the back arrow or the CI breadcrumb at the top to return to the workflow run summary.

The workflow run summary should display a green checkmark with a success status. This confirms your entire pipeline completed without errors.

What do the checkmarks mean?

Each green checkmark represents one step in your workflow that completed successfully. If any step fails, it gets a red X and all subsequent steps are skipped.

This is how CI catches problems early. A failure in "Install dependencies" would stop the pipeline before "Run tests" even starts.

Seeing a red X on any step?

  • Click on the failed step to read the error message. The log output tells you exactly what went wrong.
  • If Run tests failed, double check that your test_calculator.py passes locally by running python -m pytest test_calculator.py -v on your machine.
  • If Set up Python failed, check that your ci.yml has python-version: "3.13" with quotes around the version number.

My GitHub Actions workflow run is showing a red X. How do I debug it?

Your pipeline is running and all green. Next up, you'll intentionally break something to see how the pipeline catches bugs in real time.

Break Something and Watch the Pipeline Catch It

In the last step, you watched your first pipeline run and explored the logs for each step. Every check passed with green checkmarks.

A pipeline that always shows green doesn't prove it's catching anything. In this step, you'll intentionally break your code and watch your CI pipeline flag the failure.

In this step, get ready to:
  • Introduce a deliberate bug in the add function.
  • Watch the pipeline catch the bug and display a red X.
  • Fix the bug and confirm the pipeline turns green again.
Introduce a bug in the add function

The fastest way to understand what a CI failure looks like is to cause one yourself. You'll make a small change to the add function that causes the tests to fail.

  • In calculator.py, find the add function at the top of your file.
  • Find this line:
    return a + b
  • Change the + to -, so the line looks like this:
    return a - b
  • Save calculator.py.

Why break things on purpose?

In real projects, bugs slip in by accident. By introducing one deliberately, you get to see exactly what a CI failure looks like in a safe, controlled environment.

This red-to-green cycle is how teams use CI every day. Code gets pushed, the pipeline tests it, and failures get caught before they reach users.

Push the broken code and watch it fail
  • Commit and push your broken code to GitHub by running these commands:
git add calculator.py
git commit -m "Break add function to test CI"
git push

What do these commands do?

  • git add calculator.py stages your changed file for the next commit.
  • git commit saves a snapshot of your changes with a descriptive message.
  • git push sends the commit to GitHub, which automatically triggers your GitHub Actions workflow.

Push failed?

Make sure you're inside the python-ci-demo folder and that your Git credentials are set up. If you recently created your GitHub account, you may need to configure a personal access token.

Help me fix a git push error for my GitHub repository.

  • Open your python-ci-demo repository on GitHub.
  • Click the Actions tab.

You should see a new workflow run with an orange dot (still running) or a red X (finished failing).

  • Wait for the run to finish if it shows an orange dot.
  • Click on the failed workflow run to open it.
  • Click on the test job.
  • Expand the Run tests step to read the full test output.

What should I see in the logs?

The output shows pytest running all five test functions. Four pass, but test_add fails.

The error tells you that add(2, 3) returned -1 instead of 5. That's because you changed + to -. This is exactly the kind of specific feedback that makes automated testing valuable.

Fix the bug and confirm the pipeline recovers

You've seen the pipeline catch a bug. Now revert the change and watch the pipeline recover.

  • In calculator.py, find the add function at the top of your file.
  • Find this line:
    return a - b
  • Change the - back to +, so the line looks like this:
    return a + b
  • Save calculator.py.
  • Commit and push the fix by running these commands:
git add calculator.py
git commit -m "Fix add function"
git push
  • Go back to the Actions tab on GitHub.
  • Wait for the latest workflow run to finish.

You should see green checkmarks on every step. Your pipeline is healthy again.

Still seeing a red X?

Double check that you changed return a - b back to return a + b in the add function. Make sure you saved calculator.py before committing.

My pipeline is still failing after I fixed the add function.

✔️ Awesome, I've got everything!

Great. Make sure calculator.py is saved with return a + b in the add function.

ⓧ I'd like to double check the full code

def add(a, b):
    return a + b


def subtract(a, b):
    return a - b


def multiply(a, b):
    return a * b


def divide(a, b):
    if b == 0:
        raise ValueError("Cannot divide by zero")
    return a / b

You've experienced a complete red-to-green debugging cycle. Next up, you'll add a live status badge to your README so anyone visiting your repository can see your pipeline's health at a glance.

Add a Status Badge to Your README

In the previous step, you watched your pipeline catch a real bug and confirmed the fix by pushing clean code. Your CI/CD pipeline is now running reliably on every push.

The final piece is making your pipeline's health visible to anyone who visits your repository. A status badge is a small image embedded in your README.md that shows whether your latest tests passed or failed. It updates automatically every time your workflow runs.

In this step, get ready to:
  • Copy the status badge Markdown from GitHub Actions.
  • Update your README.md with a project title, description, and the live badge.
  • Push the changes and verify the badge appears on GitHub.
Copy the status badge Markdown from GitHub

GitHub Actions can generate a Markdown snippet that renders as a live badge image. This badge automatically reflects the latest workflow result. You need to copy this snippet from the Actions tab.

  • Open your python-ci-demo repository on GitHub.
  • Click the Actions tab at the top of the repository.
  • In the left sidebar, click on the workflow name CI.
  • Click the ... (three dots) button near the top right of the workflow page.
  • Click Create status badge.
  • In the dialog that appears, click Copy status badge Markdown.

What is a status badge?

A status badge is a tiny image that GitHub generates from your workflow results. It displays "passing" in green when your latest run succeeded or "failing" in red when it did not.

The Markdown you just copied contains an image link pointing to a special GitHub URL. Every time someone views your README, GitHub serves a fresh badge reflecting the most recent workflow status.

Don't see the ... menu?

Make sure you clicked the workflow name CI in the left sidebar first. The three-dot menu only appears on the workflow summary page, not on an individual run page.

Help me find the status badge option in GitHub Actions.

Update your README with the badge

Right now, your README.md only has the default content GitHub generated when you created the repository. You will replace it with a proper project description that includes the badge.

  • In VS Code, open README.md from the Explorer sidebar on the left.
  • Select all the existing content with Cmd+A (macOS) or Ctrl+A (Windows), then delete it.
  • Replace the file contents with the following:
# Python CI Demo

![CI](https://github.com/[[GH_USERNAME="your GitHub username"]]/python-ci-demo/actions/workflows/ci.yml/badge.svg)

A simple Python calculator project with automated CI testing using GitHub Actions.

## How to run tests locally

```bash
pip install pytest
python -m pytest test_calculator.py -v
```

What does this file do?

The # Python CI Demo line is the project title that renders as a large heading on GitHub.

The ![CI](...) line is Markdown image syntax. It fetches the badge image from GitHub's badge URL and displays it inline. This is the badge Markdown you copied in the previous substep. Your pasted version already contains your actual GitHub username.

The rest of the file gives visitors a quick description of the project and instructions for running the tests locally.

Use the badge you already copied

The badge line in the code above uses a placeholder for your username. You can paste the badge Markdown you copied from GitHub directly onto line 3 instead. It already contains your real username.

  • Save README.md.

You will not see the badge render locally. Markdown files only render as formatted pages on GitHub. The next substep pushes this file so you can see it live.

Commit and push your updated README
  • Commit and push the updated README by running these commands in your terminal:
git add .
git commit -m "Add status badge to README"
git push

What do these commands do?

  • git add . stages all changed files for commit.
  • git commit -m "..." saves the staged changes with a descriptive message.
  • git push sends the commit to GitHub, which also triggers your CI workflow.
  • Open your python-ci-demo repository on GitHub.
  • Scroll down to the README section below the file list.

You should see your project title, a green "passing" badge, the project description, and the local test instructions. The badge may take a few seconds to appear while the new workflow run completes.

Badge showing "no status" or not appearing?

If the badge shows "no status", your workflow may still be running. Click the Actions tab and wait for the latest run to finish, then refresh the repository page.

If the badge does not appear at all, check that the ![CI](...) line in your README.md contains your actual GitHub username (not YOUR-USERNAME). The URL must point to your real repository.

My README badge isn't displaying correctly on GitHub.

✔️ Awesome, I've got everything!

Great. Double check you have saved README.md and pushed your changes to GitHub.

ⓧ I'd like to double check the full code

Here is the complete README.md file. Compare it to yours and make sure everything matches.

# Python CI Demo

![CI](https://github.com/[[GH_USERNAME="your GitHub username"]]/python-ci-demo/actions/workflows/ci.yml/badge.svg)

A simple Python calculator project with automated CI testing using GitHub Actions.

## How to run tests locally

```bash
pip install pytest
python -m pytest test_calculator.py -v
```

Secret mission

Add a Pull Request Gate

Your pipeline runs on every push, but real teams need to catch bugs before code reaches the main branch. Your mission: add pull request triggers and branch protection rules so broken code can never be merged.

Before you go

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project uses a free public GitHub repository and GitHub Actions, so there are no ongoing costs.

Resources you used:

  • GitHub repository python-ci-demo (public, with GitHub Actions workflow).
  • Local project folder containing calculator.py, test_calculator.py, .github/workflows/ci.yml, and README.md.
  • GitHub Actions CI workflow (triggers on every push).

Keep everything running

No action needed. Choose this if you are still actively building on this project or plan to use it as a reference.

  • Your GitHub repository stays live and your workflow continues to run on every push.
  • GitHub Actions is free and unlimited for public repositories, so there is nothing to worry about.

Pause - I'll come back to this later

Disable your workflow so it stops running on every push, but keep all your files and repository intact.

  • Go to your python-ci-demo repository on GitHub.
  • Click the Actions tab.
  • Click CI in the left sidebar to select your workflow.
  • Click the ... menu and select Disable workflow.
  • Your workflow will no longer run on push events. You can re-enable it from the same menu when you come back.

Delete - I don't want to use this again

Remove all project resources and start fresh. This deletes your repository and local files permanently.

  • Delete the GitHub repository: go to your python-ci-demo repository on GitHub.
  • Click Settings in the top navigation bar.
  • Scroll to the bottom of the page to the Danger Zone section.
  • Click Delete this repository and follow the confirmation prompts.
  • Delete the local project folder: open your Desktop and delete the python-ci-demo folder.

Mission accomplished

That's a Wrap!

Nice work! You just built your first CI/CD pipeline from scratch using GitHub Actions. Every time you push code, your pipeline automatically tests it and tells you whether anything broke.

You've learned how to:

  • Written a GitHub Actions workflow in YAML that automatically runs your pytest test suite on every push to GitHub.
  • Watched a pipeline catch a real bug and learned to read workflow logs to pinpoint exactly which test failed and why.
  • Added a live status badge to your repository README so anyone can see your pipeline's health at a glance.
  • Secret Mission: Gated your main branch with pull request checks so broken code can never be merged.

Ready to quiz yourself?