Skip to content

CI Pipeline

CI Pipeline #248

Workflow file for this run

name: CI Pipeline
on:
push:
branches: [master]
pull_request:
branches: [master]
types: [opened, reopened, synchronize, ready_for_review]
schedule:
- cron: '14 3 * * *' # Every day at 03:14 UTC
permissions: {}
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}-${{ github.event_name }}
cancel-in-progress: true
jobs:
test:
name: Test Workflow - Python ${{ matrix.python-version }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
python-version: [3.11, 3.12, 3.13]
permissions:
contents: read
steps:
- name: 🛡️ Harden runner
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
with:
egress-policy: audit
- name: 📥 Checkout the repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- name: 🐍 Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: ${{ matrix.python-version }}
- name: 🛠️ Setup UV
uses: astral-sh/setup-uv@557e51de59eb14aaaba2ed9621916900a91d50c6 # v6.6.1
with:
python-version: ${{ matrix.python-version }}
enable-cache: false
- name: 📦 Install dependencies
run: make install GROUP=test CI=true VERBOSE=true
- name: 📂 Create coverage directory
run: mkdir coverage
- name: 🏃 Run Tests
run: make coverage CI=true VERBOSE=true
env:
COVERAGE_FILE: coverage/.coverage_${{ matrix.os }}_python_${{ matrix.python-version }}
CONTEXT: ${{ matrix.os }}-python-${{ matrix.python-version }}-${{ hashFiles('pyproject.toml') }}
- name: 🫙 Store tests coverage
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
if: always() && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository)
with:
name: coverage_${{ matrix.os }}_python_${{ matrix.python-version }}
path: coverage
include-hidden-files: true
retention-days: 10
combine-coverage-reports:
name: Combine Coverage Reports Workflow
needs: [test]
if: always()
runs-on: ${{ matrix.os }}
timeout-minutes: 5
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
python-version: [3.13]
permissions:
contents: read
steps:
- name: 🛡️ Harden runner
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
with:
egress-policy: audit
- name: 📥 Checkout the repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- name: 🐍 Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: ${{ matrix.python-version }}
- name: 🛠️ Setup UV
uses: astral-sh/setup-uv@557e51de59eb14aaaba2ed9621916900a91d50c6 # v6.6.1
with:
python-version: ${{ matrix.python-version }}
enable-cache: false
- name: 📦 Install dependencies
run: make install GROUP=coverage CI=true VERBOSE=true
- name: 📥 Download coverage files
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
merge-multiple: true
pattern: coverage_*
path: coverage
- name: 🏃 Combine coverage files
run: coverage combine coverage/.coverage_*
- name: 📊 Generate coverage report
run: |
coverage report
coverage html --show-contexts --title "Coverage for ${{ github.sha }}"
- name: 🫙 Store coverage HTML report
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
with:
name: coverage-html
path: htmlcov
retention-days: 10
- name: 🫙 Store coverage data report
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
with:
name: coverage-data
path: .coverage
include-hidden-files: true
retention-days: 10
publish-coverage-report-commit:
name: Publish Coverage Report Commit Workflow
needs: [combine-coverage-reports]
if: needs.combine-coverage-reports.result == 'success' && github.event_name == 'push' && github.ref == 'refs/heads/master'
runs-on: ${{ matrix.os }}
timeout-minutes: 5
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
python-version: [3.13]
permissions:
contents: read
statuses: write
steps:
- name: 🛡️ Harden runner
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
with:
egress-policy: audit
- name: 📥 Checkout the repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- name: 🐍 Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: ${{ matrix.python-version }}
- name: 🛠️ Setup UV
uses: astral-sh/setup-uv@557e51de59eb14aaaba2ed9621916900a91d50c6 # v6.6.1
with:
python-version: ${{ matrix.python-version }}
enable-cache: false
- name: 📦 Install dependencies
run: make install GROUP=coverage CI=true VERBOSE=true
- name: 📥 Download coverage files
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
name: coverage-html
path: htmlcov
- name: 📊 Upload coverage report
run: smokeshow upload htmlcov
env:
SMOKESHOW_GITHUB_STATUS_DESCRIPTION: Coverage {coverage-percentage}
SMOKESHOW_GITHUB_COVERAGE_THRESHOLD: 100
SMOKESHOW_GITHUB_CONTEXT: coverage
SMOKESHOW_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SMOKESHOW_GITHUB_PR_HEAD_SHA: ${{ github.head_sha }}
SMOKESHOW_AUTH_KEY: ${{ secrets.SMOKESHOW_AUTH_KEY }}
publish-coverage-comment-pr:
name: Publish Coverage Report Pull Request Workflow
needs: [combine-coverage-reports]
if: needs.combine-coverage-reports.result == 'success' && github.event_name == 'pull_request' && github.base_ref == 'master'
runs-on: ${{ matrix.os }}
timeout-minutes: 5
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
python-version: [3.13]
permissions:
contents: write
actions: read
pull-requests: write
steps:
- name: 🛡️ Harden runner
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
with:
egress-policy: audit
- name: 📥 Checkout the repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
fetch-depth: 1000
persist-credentials: false
- name: 📥 Download coverage files
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
with:
name: coverage-data
- name: 📊 Generate coverage comment
id: coverage-comment
uses: py-cov-action/python-coverage-comment-action@0544a9c648672334d94ec5dd1add7410b4470ddc # v3.37
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
MINIMUM_GREEN: 100
COMMENT_ARTIFACT_NAME: coverage_comment
COMMENT_FILENAME: coverage_comment.txt
- name: 🫙 Store coverage comment
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
if: steps.coverage-comment.outputs.COMMENT_FILE_WRITTEN == 'true'
with:
name: coverage_comment
path: coverage_comment.txt
format:
name: Format Check Workflow - Python ${{ matrix.python-version }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
python-version: [3.13]
permissions:
contents: read
steps:
- name: 🛡️ Harden runner
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
with:
egress-policy: audit
- name: 📥 Checkout the repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- name: 🐍 Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: ${{ matrix.python-version }}
- name: 🛠️ Setup UV
uses: astral-sh/setup-uv@557e51de59eb14aaaba2ed9621916900a91d50c6 # v6.6.1
with:
python-version: ${{ matrix.python-version }}
enable-cache: false
- name: 📦 Install dependencies
run: make install GROUP=format CI=true VERBOSE=true
- name: 🏃 Run Formatter
run: make format CI=true VERBOSE=true
- name: 🧐 Verify no changes
run: |
CHANGES=$(git status --porcelain)
if [[ -n "${CHANGES}" ]]; then
echo "::error file=.github/workflows/ci.yaml,title=Format Check Workflow Failed::Code is not formatted correctly. Please run 'make format' locally and commit the changes."
exit 1
fi
lint:
name: Lint Workflow - Python ${{ matrix.python-version }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
python-version: [3.13]
permissions:
contents: read
steps:
- name: 🛡️ Harden runner
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
with:
egress-policy: audit
- name: 📥 Checkout the repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- name: 🐍 Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: ${{ matrix.python-version }}
- name: 🛠️ Setup UV
uses: astral-sh/setup-uv@557e51de59eb14aaaba2ed9621916900a91d50c6 # v6.6.1
with:
python-version: ${{ matrix.python-version }}
enable-cache: false
- name: 📦 Install dependencies
run: make install GROUP=lint CI=true VERBOSE=true
- name: 🏃 Run Linter
run: make lint CI=true VERBOSE=true
analyze:
name: Code Quality Workflow - ${{ matrix.language }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
language: [python]
build-mode: [none]
permissions:
contents: read
security-events: write
steps:
- name: 🛡️ Harden runner
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
with:
egress-policy: audit
- name: 📥 Checkout the repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- name: ▶️ CodeQL Initialization
uses: github/codeql-action/init@192325c86100d080feab897ff886c34abd4c83a3 # v3.29.5
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
queries: +security-extended,security-and-quality
- name: 🔬 CodeQL Analysis
uses: github/codeql-action/analyze@192325c86100d080feab897ff886c34abd4c83a3 # v3.29.5
with:
category: '/language:${{ matrix.language }}'
secrets:
name: Secrets Scan Workflow - Python ${{ matrix.python-version }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
python-version: [3.13]
permissions:
contents: read
security-events: write
pull-requests: write
steps:
- name: 🛡️ Harden runner
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
with:
egress-policy: audit
- name: 📥 Checkout the repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
fetch-depth: 0
persist-credentials: false
- name: 🐍 Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: ${{ matrix.python-version }}
- name: 🛠️ Setup UV
uses: astral-sh/setup-uv@557e51de59eb14aaaba2ed9621916900a91d50c6 # v6.6.1
with:
python-version: ${{ matrix.python-version }}
enable-cache: false
- name: 📦 Install dependencies
run: make install GROUP=develop CI=true VERBOSE=true
- name: 🏃 Run secrets scanner
run: make secrets CI=true VERBOSE=true
audit:
name: Audit Workflow - Python ${{ matrix.python-version }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
python-version: [3.13]
permissions:
contents: read
steps:
- name: 🛡️ Harden runner
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
with:
egress-policy: audit
- name: 📥 Checkout the repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
- name: 🐍 Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: ${{ matrix.python-version }}
- name: 🛠️ Setup UV
uses: astral-sh/setup-uv@557e51de59eb14aaaba2ed9621916900a91d50c6 # v6.6.1
with:
python-version: ${{ matrix.python-version }}
enable-cache: false
- name: 📦 Install dependencies
run: make install GROUP=audit CI=true VERBOSE=true
- name: 🏃 Run audit
run: make audit CI=true VERBOSE=true
check-all:
name: Check All Workflows Passed Workflow
needs: [test, format, lint, analyze, secrets, audit]
if: always()
runs-on: ${{ matrix.os }}
timeout-minutes: 5
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
steps:
- name: 🛡️ Harden runner
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
with:
egress-policy: audit
- name: ✅ All workflows passed
uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2
with:
jobs: ${{ toJSON(needs) }}
release:
name: Create Tag and GitHub Release Workflow
needs: [check-all]
if: needs.check-all.result == 'success' && github.event_name == 'push' && github.ref == 'refs/heads/master'
runs-on: ${{ matrix.os }}
timeout-minutes: 5
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
permissions:
contents: write
pull-requests: write
outputs:
released: ${{ steps.released.outputs.released }}
tag: ${{ steps.released.outputs.tag }}
steps:
- name: 🛡️ Harden runner
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
with:
egress-policy: audit
- name: 📥 Checkout the repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
fetch-depth: 0
- name: 🔖 Semantic Release
id: released
uses: python-semantic-release/python-semantic-release@6df5e876c8682fe0753ec2f8c81eb45547e52747 # v10.0.2
with:
build: false
push: true
changelog: true
commit: true
tag: true
vcs_release: true
config_file: pyproject.toml
git_committer_email: ${{ vars.GIT_COMMITTER_EMAIL }}
git_committer_name: ${{ vars.GIT_COMMITTER_NAME }}
github_token: ${{ secrets.GITHUB_TOKEN }}
ssh_public_signing_key: ${{ vars.SSH_PUBLIC_SIGNING_KEY }}
ssh_private_signing_key: ${{ secrets.SSH_PRIVATE_SIGNING_KEY }}
publish:
name: Publish Release to PyPI Workflow
needs: [release]
if: needs.release.result == 'success' && needs.release.outputs.released == 'true' && github.event_name == 'push' && github.ref == 'refs/heads/master'
runs-on: ${{ matrix.os }}
timeout-minutes: 5
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
python-version: [3.13]
permissions:
contents: read
id-token: write
environment:
name: pypi
url: https://pypi.org/p/criteria-pattern/
steps:
- name: 🛡️ Harden runner
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
with:
egress-policy: audit
- name: 📥 Checkout the repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
ref: refs/tags/${{ needs.release.outputs.tag }}
- name: 🐍 Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
with:
python-version: ${{ matrix.python-version }}
- name: 🛠️ Setup UV
uses: astral-sh/setup-uv@557e51de59eb14aaaba2ed9621916900a91d50c6 # v6.6.1
with:
python-version: ${{ matrix.python-version }}
enable-cache: false
- name: 📦 Install dependencies
run: make install GROUP=release CI=true VERBOSE=true
- name: 🏃🏻‍➡️ Build distribution
run: make build CI=true VERBOSE=true
- name: 🫙 Store distribution package
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
with:
name: python-package-distributions
path: dist/
retention-days: 10
- name: 🚀 Publish
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0