This document serves as a guide to the stages and jobs defined in the .gitlab-ci.yml file for Python projects. It also provides best practices for each stage to help you set up a robust, maintainable CI/CD pipeline.
A typical CI/CD pipeline for Python projects may include the following stages:
- Install – Prepares the environment by installing dependencies.
- Lint – Checks code style and quality.
- Test – Runs automated tests to verify functionality.
- Build – (Optional) Packages the code into a deployable artifact.
- Code Quality and Security Scanning – (Optional) Scans for vulnerabilities and potential issues.
- Staging/Pre-Deployment Testing – (Optional) Tests in an environment similar to production.
- Deployment – (Optional) Deploys the code to production.
- Notification and Reporting – Sends updates on build status and results.
Not all stages are necessary for every project. Choose the stages based on the project's complexity, team size, and requirements.
- Purpose: Sets up the environment by installing dependencies.
- Why Important: Ensures that the project can build and run successfully.
- Typical Jobs:
- Installing project dependencies using
pip install -r requirements.txt - Setting up virtual environments and caching for faster builds
- Installing project dependencies using
- Best Practices:
- Use a base image with the necessary tools and dependencies.
- Cache dependencies to speed up subsequent builds.
- Use virtual environments to isolate dependencies.
install_dependencies:
stage: install
image: python:3.12
script:
- python -m venv venv
- source venv/bin/activate
- pip install -r requirements.txt
cache:
paths:
- .cache/pip
artifacts:
paths:
- venv- Purpose: Checks code quality and adherence to style guidelines.
- Why Important: Helps catch errors early, enforces code consistency, and maintains readability.
- Typical Tools:
flake8for code quality and PEP 8 complianceblackin--checkmode to enforce code formatting without making changesmypyfor static type checking
- Best Practices:
- Run linters on every commit to catch issues early.
- Configure linters to match the project's style guide.
- Use pre-commit hooks to enforce linting before committing code.
lint:
stage: lint
image: python:3.12
script:
- source venv/bin/activate
- flake8 path/to/your/code
- black --check path/to/your/code
- mypy path/to/your/code- Purpose: Runs automated tests to verify that the code behaves as expected.
- Why Important: Ensures reliability and catches bugs before code reaches production.
- Typical Tools:
pytestfor unit and integration testsseleniumfor end-to-end tests
- Best Practices:
- Use
pytestto run tests with options for test reports and code coverage. - Run tests in parallel for multiple Python versions by leveraging GitLab’s
matrixfeature.
- Use
test:
stage: test
image: python:$PYTHON_VERSION
variables:
PYTHON_VERSION: $PYTHON_VERSIONS
parallel:
matrix:
- PYTHON_VERSION: ["3.10", "3.11", "3.12", "3.13"]
script:
- python -m venv venv
- source venv/bin/activate
- pip install -r requirements.txt
- pytest tests/ --junitxml=junit/test-report.xml --cov=path/to/your/code
artifacts:
reports:
junit: junit/test-report.xml
coverage_report:
coverage_format: cobertura
path: coverage.xml- Purpose: Packages the code into a deployable artifact.
- Why Important: Standardizes the packaging process, making deployments predictable.
- Typical Tools:
docker buildfor containerized applicationssetuptoolsfor Python packagespoetryfor Python packaging and dependency management
- Best Practices:
- Use a consistent build process across environments.
- Automate the build process to reduce manual errors.
build:
stage: build
image: python:3.12
script:
- echo "Building project artifacts..."
# Add build commands here, such as `docker build` or package creation- Purpose: Scans for vulnerabilities and potential issues in the code.
- Why Important: Identifies technical debt, improves maintainability, and protects against security risks.
- Typical Tools:
banditfor security scanningsafetyfor dependency security checkspylintfor code quality checkssonarqubefor comprehensive code analysis
- Best Practices:
- Integrate security scanning into the CI/CD pipeline to catch issues early.
- Use static code analysis tools to identify potential bugs and security vulnerabilities.
code_quality:
stage: code_quality
image: python:3.12
script:
- bandit -r path/to/your/code
- safety check
- pylint path/to/your/code- Purpose: Tests the application in an environment similar to production.
- Why Important: Reduces the risk of production issues by validating code in a staging environment.
- Typical Jobs:
- Deploying the application to a staging environment
- Running integration and UI tests on the staging environment
- Best Practices:
- Use a separate staging environment to mimic production as closely as possible.
- Automate the deployment and testing process to ensure consistency.
staging_deployment:
stage: staging
script:
- echo "Deploying to staging environment..."
# Add staging deployment commands- Purpose: Deploys the code to production or releases it to users.
- Why Important: Delivers features and updates to end-users in a controlled manner.
- Typical Jobs:
- Deploying the application to production servers
- Updating servers, pushing to app stores, or publishing packages
- Tagging the release in the version control system
- Best Practices:
- Use automated deployment scripts to reduce manual errors.
- Implement blue-green deployments or canary releases for zero-downtime deployments.
deploy:
stage: deploy
image: alpine:latest
script:
- echo "Deploying application..."
# Add deployment commands here
only:
- main # Only deploy from main branch- Purpose: Sends updates on build status and results.
- Why Important: Keeps the team informed about the progress and status of the CI/CD pipeline.
- Typical Tools:
- Email notifications
- Slack notifications
- GitLab pipeline status badges
- Best Practices:
- Notify team members of build failures or successes.
- Use status badges to display the build status in the project repository.
notify:
stage: notify
script:
- echo "Sending notification..."
# Add Slack or email notification commands- Use Version Pinning: Pin dependencies in requirements.txt to ensure reproducibility.
- Fail Fast: Place critical stages (e.g., install, lint) early in the pipeline so failures are detected quickly.
- Leverage Caching: Cache dependencies to speed up builds and minimize network usage.
- Parallelize Tests: Use parallel and matrix configurations to test across Python versions or run independent test suites concurrently.
- Store Artifacts: Save important artifacts (e.g., test results, coverage reports) to help with debugging and quality assurance.