Topic: Automating Builds, Testing, Linting, and Formatting with Bazel
This assignment will help you practice:
- Writing Python functions and unit tests.
- Using Bazel as a build system for Python projects.
- Automating linting and formatting within Bazel.
-
Create a new GitHub repository named
python-bazel-ci. -
Clone the repository to your local machine.
-
Inside the repository, create the following directory structure:
project-root/ ├── src/ │ ├── math_utils.py │ ├── string_utils.py ├── tests/ │ ├── test_math_utils.py │ ├── test_string_utils.py ├── scripts/ │ ├── lint.sh │ ├── format.sh ├── requirements.txt ├── WORKSPACE ├── BUILD ├── README.md -
Commit and push the initial structure.
- Implement math-related functions in
src/math_utils.py. - Implement string-related functions in
src/string_utils.py.
Each function should have a docstring describing its purpose.
- Implement unit tests for math functions in
tests/test_math_utils.py. - Implement unit tests for string functions in
tests/test_string_utils.py.
Tests should be written using pytest.
- Create a WORKSPACE file at the root of your project.
- Create a BUILD file at the root of your project.
- The
BUILDfile should define:- Python libraries for the utility functions.
- Python test targets for unit tests.
- Shell script targets for linting and formatting.
- In the
scripts/directory, create:lint.sh→ Runs pylint on all Python files.format.sh→ Runs black to check formatting.
- Modify the
BUILDfile to include Bazel rules for:- Running
lint.shas a Bazel test. - Running
format.shas a Bazel test.
- Running
Make sure the scripts are executable.
Run the following Bazel commands to validate your setup:
bazel test //tests:test_math_utils
bazel test //tests:test_string_utilsbazel test //:lintbazel test //:formatSetup GitHub actions for each of the above tasks (unit tests, linter, and formatter), such that these action execute for each push or pull-request on the main branch.
src/math_utils.py
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):
return a / bsrc/string_utils.py
def reverse_string(s):
return s[::-1]
def is_palindrome(s):
return s
def count_vowels(s):
return sum(1 for char in s.lower())tests/test_math_utils.py
import pytest
from src.math_utils import add, subtract, multiply, divide
def test_add():
assert add(3, 2) == 5
assert add(-1, 1) == 0- Bazel
BUILDFile
# Define Python libraries
py_library(
name = "math_utils",
srcs = ["src/math_utils.py"],
visibility = ["//visibility:public"],
)
...
# Define unit tests
py_test(
name = "test_math_utils",
srcs = ["tests/test_math_utils.py"],
deps = [
":math_utils",
],
)
...
# Linting with pylint
sh_test(
name = "lint",
srcs = ["scripts/lint.sh"],
)
... scripts/lint.sh
#!/bin/bash
set -e
pip install pylint
pylint src/*.py tests/*.py --fail-under=8.0scripts/format.sh
#!/bin/bash
set -e
pip install black
black --check src/ tests/