No results for

TutorialsLast Updated Apr 28, 202510 min read

Setting up continuous integration with GitHub and CircleCI

Stanley Ndagi

Fullstack Developer and Tech Author

Developer D sits at a desk working on a beginning-level project.

Continuous integration (CI) involves the test automation of feature branches before they are merged to the main Git branch in a project. This ensures that a codebase does not get updated with changes that could break something. Continuous delivery (CD), on the other hand, builds upon CI by automating releases of these branches or the main branch. This allows small incremental updates that reach your users faster, in line with Agile software development methodology.

In this article, I will take you through the process of setting up a CI pipeline with GitHub and CircleCI. We will use a basic Python application to demonstrate the process, but you can follow along using your own personal project as well.

Here are the steps:

  1. Create a simple Python application (with Flask)
  2. Create tests for this app
  3. Add the config.yml file
  4. Push to GitHub
  5. Configure CircleCI
  6. Update your README with a badge
  7. Create a PR and see CircleCI in action

Prerequisites

To follow along with the tutorial, a few things are required:

  1. Python installed on your local system
  2. A CircleCI account
  3. A GitHub account

Creating and building a simple Python app

For simplicity, you will create a Flask application. Flask is a micro-framework for Python. Don’t worry if you’ve never used Flask before — we’ll be building the basic hello world application found in the Flask documentation.

First, create a project directory (folder) and cd into it. Type this into your terminal:

mkdir python_app && cd $_/
Copy to clipboard

Next, open your favorite editor and create a hello.py file. Then, copy these lines into that file:

from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello_world():
    return "<p>Hello, World!</p>"
Copy to clipboard

Virtual environments in Python

When working in Python, it is strongly advised that you use a virtual environment. This allows you to install Python packages in an abstracted environment that is not your entire local machine.

Some common ways to do this are to use virtualenv or, even better, virtualenvwrapper. We will use the module venv that comes as a part of Python3. Here is how:

  • Create the virtual environment:
python -m venv .venv
Copy to clipboard

You can use other names for your virtual environment, like in the next example.

python -m venv Env
Copy to clipboard
  • Activate this environment:
source .venv/bin/activate
Copy to clipboard

If you used another name for the environment, replace .venv with that name. You will notice the environment name just before the shell prompt, which tells you that the virtual environment is active. Any Python package that is installed will be installed within this environment. To deactivate this environment simply run:

Running the app

Now it’s time to create a requirements.txt file in your editor. Add this content:

This file is used to specify the packages that your application depends on. You can install these packages using pip, which is the package manager for Python.

Then, within the virtual environment, install the package by running:

pip install -r requirements.txt
Copy to clipboard

Note: If you deactivated your virtual environment prior to this step, you will first need to run source .venv/bin/activate.

The final command to run this application is:

flask --app hello run
Copy to clipboard

The application is running on your browser at http://localhost:5000/.

Creating tests for your application

Software testing is an important skill for any developer, ensuring that your application works as intended and helping to catch bugs early. Writing tests can save you time and headaches down the line.

In your editor, create a test_hello.py file and paste these lines into it:

from hello import app

def test_home_route():
    with app.test_client() as c:
        response = c.get("/")
        assert response.data == b"<p>Hello, World!</p>"
        assert response.status_code == 200
Copy to clipboard

This test verifies that your Flask application’s home route returns the correct HTML content and status code.

Learn more about testing Flask with Pytest.

Now you can run your test. Open Terminal and run:

python -m pytest
Copy to clipboard

This command will execute the test file you just created. If everything is set up correctly, you should see output similar to this:

============================================= test session starts =============================================
platform darwin -- Python 3.13.2, pytest-8.3.5, pluggy-1.5.0
collected 1 item

test_hello.py .                                                                                         [100%]

============================================== 1 passed in 0.10s ==============================================
Copy to clipboard

This output indicates that the test passed successfully. The dot (.) represents a passing test, while an F would indicate a failure.

Creating a CircleCI config file

To automate your testing process, you’ll need to set up a CircleCI configuration file. This configuration will define how your tests are run and how your application is built and tested.

Create a .circleci folder and inside of that create a config.yml file. Then, copy these lines into it:

version: 2.1
orbs:
  python: circleci/python@3.0.0
jobs:
  build_and_test: # this can be any name you choose
    executor: python/default # use the default executor defined within the orb
    steps:
      - checkout # checkout source code
      - python/install-packages:
          pkg-manager: pip
          pip-dependency-file: requirements.txt
      - run:
          name: Run tests
          command: python -m pytest
workflows:
  build_test_deploy:
    jobs:
      - build_and_test
Copy to clipboard

This file configures CircleCI to use the Python orb, which simplifies setting up the Python environment and running your tests. The build_and_test job checks out your source code, installs the necessary packages, and runs your tests using pytest. The workflows section defines a workflow called build_test_deploy that runs the build_and_test job.

Learn more about this config file.

Pushing to GitHub

Following the DevOps you would typically initialize Git at the beginning of your project and make frequent, small commits. However, since this tutorial focuses on integrating CircleCI with GitHub, I intentionally delayed this step until now.

This is the current code structure:

.
├── .circleci
│   └── config.yml
├── hello.py
├── requirements.txt
└── tests.py
Copy to clipboard

Open your editor and create a .gitignore file in the working directory. You will use this file to state the files and folders that you do not want to commit to Git. Copy these lines into that file:

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]

# Environments
.env
.venv
env/
venv/
ENV/

Copy to clipboard

Initialize Git and Commit your code by running:

git init

git add .

git commit -m "initial commit"
Copy to clipboard

If you do not already have a GitHub account, go to GitHub’s homepage and create one. If you are new to GitHub, you may want to read our tutorial on pushing a project to GitHub.

Next, create a repository by navigating to github.com/new.

Use the name python_app. Leave the rest of the default settings as-is and click Create repository.

2025-04-04-github-create-repo

After creating your new repository, you will be prompted about your repo.

2025-04-04-github-created-repo

Run this command to add the remote repository and push your code to GitHub:

git branch -M main
git remote add origin https://github.com/CIRCLECI-GWP/python_app.git
git push -u origin main
Copy to clipboard

Configuring CircleCI

Now that the repo is on GitHub, you can finalize the CI pipeline by configuring CircleCI. Head on over to the CircleCI signup page. Click Sign up to create a CircleCI account and connect it to your GitHub account.

2025-04-04-circleci

Enter your email and password. Click Continue to proceed.

Email and password

You will get an email to verify your account. Click the link in the email to verify your account.

Email verified

On the next screen, fill in a few onboarding questions by selecting options. I’ve gone with generic ones for now.

A bit about you

Click Let’s Go to continue.

Next, start a new organization.

2025-04-04-start-new-org

Enter the name of your organization. This is the name that will be used to identify your CircleCI account. Click Let’s Go to continue.

This will create a new organization for you on CircleCI. Next, you will be redirected to your organization’s dashboard. Go ahead and Create a project

2025-04-04-create-project

Give your project a descriptive name and follow the prompts to select a version control system (VCS), for the purpose of this tutorial, we will select GitHub.

Select VCS

For GitHub, you’ll install the CircleCI GitHub app. Select the GitHub organization you want to install it to.

2025-04-04-select-organisation

You can specify exactly which repositories CircleCI can access, or opt to give CircleCI access to all repositories in your GitHub organization.

2025-04-04-all-or-single-repo

Click Install & Authorize.

If you have selected a single repo, CircleCI will detect your configuration file or guide you to create one. Our project already has the .circleci/config.yml file.

Once you have your config, select Next: set up your triggers.

2025-04-04-set-up-triggers

As shown in the image, we configure our pipeline to be triggered on every push.

Review and finish your setup.

In this last step, name your project. Notice the text underneath the field confirming presence of the .circleci/config.yml file.

With that, your project on CircleCI is ready.

CircleCI setup without config.yml

In the case where your project doesn’t have the .circleci/config.yml file or it’s not being recognized, you will get a screen where CircleCI will analyze the project with the intention of generating a config file you can commit to your project

Without config

Click Prepare config file. This will generate a config file for you. You can choose to edit it or leave it as is.

2025-04-04-prepare-config

After that, you will be redirected to review the config and then setup your triggers.

Next you can review everything you have just set up, then select Commit config and run. If you already have a config file in your repo, click Finish setup instead.

Once your project is created you will land on your pipelines page. CircleCI uses the specified .circleci/config.yml file to run your pipeline.

You can see the output on the pipelines page. Within no time, the build passes. Success!

2025-04-04-cci-pass

Now that your project is set up, it’s worth getting familiar with the optional settings available to you. Let’s look at a relevant example.

For this project, click Project Settings (button with a cog icon).

Project settings button

Then click Advanced on the left.

Advance settings page

Find the Only build pull requests card (scroll down if you have to). This option is turned off by default. This means that every push to GitHub will run on CircleCI, including PRs. Feel free to toggle this if necessary. Sometimes, in a large team setting, this setting can help moderate use of build minutes.

Adding a CI status badge to GitHub

A status badge is a great way to show the build status of your project right on your GitHub repository. It provides a visual indicator of whether your latest build passed or failed, which is helpful for both you and your collaborators.

On your local machine, check out to another Git branch by running:

git checkout -b add_readme
Copy to clipboard

Open your editor and create a README.md file. Copy and paste these lines into this file:

# PYTHON APPLICATION

This Python application repo was created to showcase the integration between GitHub and CircleCI.
[https://circleci.com/gh/CIRCLECI-GWP/python_app.svg?style=svg](https://circleci.com/gh/CIRCLECI-GWP/python_app){: target="_blank"}
Copy to clipboard

This adds a title, a description and a status badge.

Now, run these commands:

git add .
git commit -m "Add README"
git push -u origin add_readme
Copy to clipboard

Your https://github.com/<< username >>/python_app repo has a new branch: add_readme. Click Compare and pull request.

2025-04-04-github-branch

Triggering a build via a pull request

After adding the status badge, the next step is to create a pull request (PR) to merge your changes into the main branch. This will allow us to trigger a build and ensure everything is set up correctly.

Here is how I set up my PR. The PR’s title is autogenerated as the commit message. This is optional.

#### What does this PR do?

Adds README.md file and a CircleCI badge in it.
Copy to clipboard

Click Create pull request and in no time, you have a successful build!

2025-04-04-github-pr

Note that I clicked on the chevron arrow down icon to reveal the successful check is from CirlceCI. Even the browser’s tab favicon shows a green tick for the successful run.

If you click ci/circleci: build_and_test, this will redirect you to the build on CircleCI:

2025-04-04-circleci-pr

Note that the favicon here is green, showing that the build is successful.

Go ahead and merge the PR. You can also delete the branch if you want to.

This will trigger the pipeline to run again, but this time on the main branch. You can see this in the CircleCI dashboard.

2025-04-04-circleci-builds

Conclusion

There you have it! You have integrated GitHub with CircleCI.

In summary, you set up a Python application and created tests for it. You then created a CircleCI config file and pushed the codebase to GitHub. Finally, you connected the GitHub repository you created to CircleCI.

By adding continuous integration to your workflow, you benefit from automated testing, ensuring that your code is always in a deployable state. This helps catch bugs early, improves code quality, and allows for faster, more reliable updates.

If you followed through successfully, you can now set up your own project in GitHub and configure CI builds on CircleCI. As a next step, consider adding automated deployments for your Flask application to complete your CI/CD pipeline and fully automate your development workflow.

Copy to clipboard