|

Jenkins CI/CD (2/11): Create the Minimal Repo and Prove Local Tests Run

← Previous Jenkins CI/CD (2/11) Next →

Summary: Build a minimal Python package with a greet() function, a CLI entry point, and eight unit tests. By the end you will have a working src-layout project, a green pytest run, and a git repo ready for Jenkins to pick up.

Example Values Used in This Tutorial

KeyValue
Package namehelloci
Source rootsrc/helloci
Python version3.12
Working directory~/projects/helloci
Virtual environment~/projects/helloci/.venv
Test frameworkpytest
CLI commandhelloci greet Alice

0. Prerequisites

  • Python 3.12 or later installed and available as python3
  • pip and venv modules working (run python3 -m venv --help to confirm)
  • Git installed (git --version)
  • A terminal open in your home directory

Note: This is Part 2 of an 11-part series. Part 1 covered the mental model and prerequisites checklist. If you already have Python 3.12, pip, and Git you are ready to go.


1. Create the Project Directory

Create the project root and move into it.

mkdir -p ~/projects/helloci
cd ~/projects/hellociCode language: Shell Session (shell)

The src layout keeps your package source separate from tests, config files, and tooling scripts. Here is the target structure you will build in this tutorial:

helloci/
├── src/
│   └── helloci/
│       ├── __init__.py
│       └── cli.py
├── tests/
│   ├── __init__.py
│   └── test_greet.py
├── pyproject.toml
└── README.mdCode language: Shell Session (shell)

Create all the directories and empty files now.

mkdir -p src/helloci tests
touch src/helloci/__init__.py src/helloci/cli.py
touch tests/__init__.py tests/test_greet.py
touch pyproject.toml README.mdCode language: Shell Session (shell)

2. Write the greet Function

Open src/helloci/__init__.py and add the greet function. This is the entire public API of the package.

"""helloci — a tiny package that greets people."""


def greet(name: str) -> str:
    """Return a greeting string for *name*."""
    return f"Hello, {name}!"Code language: Python (python)

Three lines of real code. That is deliberate. The goal is a package small enough that nothing distracts from the CI pipeline you will build around it. If greet() works locally, Jenkins has something to test. If it breaks, the failure is obvious.


3. Write the CLI Entry Point

Open src/helloci/cli.py. This file gives you a helloci command that calls greet() from the terminal.

"""Command-line interface for helloci."""

import argparse

from helloci import greet


def main() -> None:
    """Parse arguments and print a greeting."""
    parser = argparse.ArgumentParser(
        description="Greet someone from the command line.",
    )
    parser.add_argument("name", help="Name of the person to greet")
    args = parser.parse_args()
    print(greet(args.name))


if __name__ == "__main__":
    main()Code language: Python (python)

The main() function reads one positional argument and prints the greeting. You will wire this up as a console script in the next step.


4. Create pyproject.toml

Open pyproject.toml and paste the full contents below.

[build-system]
requires = ["setuptools>=68.0", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "helloci"
version = "0.1.0"
description = "A tiny greeting package used to learn Jenkins CI/CD."
requires-python = ">=3.12"

[project.optional-dependencies]
test = ["pytest>=7.0"]

[project.scripts]
helloci = "helloci.cli:main"

[tool.setuptools.packages.find]
where = ["src"]Code language: TOML, also INI (ini)

Key points in this file:

  • [project.scripts] registers the helloci console command so you can run helloci Alice after installing.
  • [project.optional-dependencies] declares pytest as a test dependency. Installing with pip install -e ".[test]" pulls it in automatically.
  • [tool.setuptools.packages.find] tells setuptools to look inside the src/ directory for packages.

5. Add a README

Open README.md and add a minimal description. The file should contain a project title, a one-line summary, and a quick-start snippet showing how to create a venv, install, and run tests.

# helloci

A tiny Python package used to learn Jenkins CI/CD.

## Quick startCode language: Shell Session (shell)

python -m venv .venv source .venv/bin/activate pip install -e “.[test]” pytest

Code language: Shell Session (shell)

The README is not strictly required for CI, but every repo should have one. Keep it short.


6. Write the Tests

Open tests/test_greet.py and add all eight tests.

"""Unit tests for the helloci package."""

import subprocess
import sys

from helloci import greet


def test_greet_basic():
    """greet returns the expected greeting string."""
    assert greet("Alice") == "Hello, Alice!"


def test_greet_empty_string():
    """greet handles an empty string without crashing."""
    assert greet("") == "Hello, !"


def test_greet_name_with_spaces():
    """greet handles a name that contains spaces."""
    assert greet("Bob Smith") == "Hello, Bob Smith!"


def test_greet_special_characters():
    """greet handles special characters in the name."""
    assert greet("O'Reilly") == "Hello, O'Reilly!"


def test_greet_long_name():
    """greet handles an unusually long name."""
    long_name = "A" * 500
    result = greet(long_name)
    assert result == f"Hello, {long_name}!"
    assert len(result) == 508  # "Hello, " (7) + 500 + "!" (1)


def test_greet_unicode():
    """greet handles Unicode characters."""
    assert greet("\u00e9milie") == "Hello, \u00e9milie!"


def test_cli_entry_point():
    """The helloci CLI command runs and prints the greeting."""
    result = subprocess.run(
        [sys.executable, "-m", "helloci.cli", "World"],
        capture_output=True,
        text=True,
    )
    assert result.returncode == 0
    assert result.stdout.strip() == "Hello, World!"


def test_greet_multiple_calls():
    """Calling greet multiple times returns independent results."""
    first = greet("Alice")
    second = greet("Bob")
    assert first == "Hello, Alice!"
    assert second == "Hello, Bob!"
    assert first != secondCode language: Python (python)

These eight tests cover the basics: correct output, edge cases (empty string, spaces, special characters, long input, Unicode), the CLI subprocess, and multiple calls. That is more than enough for Jenkins to exercise.

Tip: Keep your first test suite simple. The goal is to prove that the pipeline runs tests end-to-end. You can add coverage, property-based tests, and integration tests later in the series.


7. Set Up the Virtual Environment and Install

Create a virtual environment, activate it, and install the package in editable mode with test dependencies.

cd ~/projects/helloci
python3 -m venv .venv
source .venv/bin/activateCode language: Shell Session (shell)
pip install -e ".[test]"Code language: Shell Session (shell)

Editable mode (-e) means changes to your source files take effect immediately without reinstalling. The [test] extra pulls in pytest.

Verify the installation.

pip show hellociCode language: Shell Session (shell)
Name: helloci
Version: 0.1.0
Location: /home/user/projects/helloci/srcCode language: Shell Session (shell)

Confirm the CLI command works.

helloci WorldCode language: Shell Session (shell)
Hello, World!Code language: Shell Session (shell)

8. Run pytest Locally

Run the full test suite.

pytest -vCode language: Shell Session (shell)
========================= test session starts ==========================
collected 8 items

tests/test_greet.py::test_greet_basic PASSED                     [ 12%]
tests/test_greet.py::test_greet_empty_string PASSED               [ 25%]
tests/test_greet.py::test_greet_name_with_spaces PASSED           [ 37%]
tests/test_greet.py::test_greet_special_characters PASSED         [ 50%]
tests/test_greet.py::test_greet_long_name PASSED                  [ 62%]
tests/test_greet.py::test_greet_unicode PASSED                    [ 75%]
tests/test_greet.py::test_cli_entry_point PASSED                  [ 87%]
tests/test_greet.py::test_greet_multiple_calls PASSED             [100%]

========================== 8 passed in 0.42s ===========================Code language: Shell Session (shell)

All eight tests pass. This is the exact result Jenkins will need to reproduce.

Warning: If any test fails here, fix it before continuing. CI is just running your commands in a clean-ish environment. If something is awkward locally, it will be worse in Jenkins.


9. Initialize the Git Repo

Initialize a git repository and make the first commit.

cd ~/projects/helloci
git initCode language: Shell Session (shell)

Create a .gitignore to keep build artifacts and the virtual environment out of version control.

cat > .gitignore << 'EOF'
__pycache__/
*.pyc
*.egg-info/
.venv/
dist/
build/
results/
.pytest_cache/
EOFCode language: Shell Session (shell)

Stage everything and commit.

git add .
git commit -m "Initial commit: minimal helloci package with 8 tests"Code language: Shell Session (shell)
[main (root-commit) a1b2c3d] Initial commit: minimal helloci package with 8 tests
 8 files changed, 120 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 README.md
 create mode 100644 pyproject.toml
 create mode 100644 src/helloci/__init__.py
 create mode 100644 src/helloci/cli.py
 create mode 100644 tests/__init__.py
 create mode 100644 tests/test_greet.pyCode language: Shell Session (shell)

Verify the state.

git log --onelineCode language: Shell Session (shell)
a1b2c3d Initial commit: minimal helloci package with 8 testsCode language: Shell Session (shell)

Your repo is clean, committed, and ready for Jenkins to clone.


Summary

You built a minimal Python package from scratch and proved it works locally.

  • src/helloci/__init__.py contains the greet() function
  • src/helloci/cli.py provides a helloci CLI command via argparse
  • pyproject.toml declares metadata, the console script, and test dependencies
  • tests/test_greet.py contains eight unit tests covering basic output, edge cases, the CLI, and multiple calls
  • pytest passes all eight tests with a single pytest -v command
  • The git repo has one clean commit with a proper .gitignore

The key takeaway: CI is just running your commands in a clean-ish environment. If the local workflow is pip install -e ".[test]" followed by pytest, then that is exactly what Jenkins will do. Get it working here first. In Part 3 you will create a Jenkins pipeline that clones this repo and runs these same tests automatically.

Similar Posts

Leave a Reply