Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
354 changes: 354 additions & 0 deletions .github/workflows/ci-monorepo.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,354 @@
name: Monorepo CI Base

on:
workflow_call:
inputs:
package:
description: 'Package to test (async-cassandra or async-cassandra-bulk)'
required: true
type: string
run-integration-tests:
description: 'Run integration tests'
required: false
type: boolean
default: false
run-full-suite:
description: 'Run full test suite'
required: false
type: boolean
default: false

env:
PACKAGE_DIR: libs/${{ inputs.package }}

jobs:
lint:
runs-on: ubuntu-latest
name: Lint ${{ inputs.package }}

steps:
- uses: actions/checkout@v4

- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install dependencies
run: |
cd ${{ env.PACKAGE_DIR }}
python -m pip install --upgrade pip
pip install -e ".[dev]"

- name: Run linting checks
run: |
cd ${{ env.PACKAGE_DIR }}
echo "=== Running ruff ==="
ruff check src/ tests/
echo "=== Running black ==="
black --check src/ tests/
echo "=== Running isort ==="
isort --check-only src/ tests/
echo "=== Running mypy ==="
mypy src/

security:
runs-on: ubuntu-latest
needs: lint
name: Security ${{ inputs.package }}

steps:
- uses: actions/checkout@v4

- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install security tools
run: |
python -m pip install --upgrade pip
pip install bandit[toml] safety pip-audit

- name: Run Bandit security scan
run: |
cd ${{ env.PACKAGE_DIR }}
echo "=== Running Bandit security scan ==="
# Run bandit with config file and capture exit code
bandit -c ../../.bandit -r src/ -f json -o bandit-report.json || BANDIT_EXIT=$?
# Show the detailed issues found
echo "=== Bandit Detailed Results ==="
bandit -c ../../.bandit -r src/ -v || true
# For low severity issues, we'll just warn but not fail
if [ "${BANDIT_EXIT:-0}" -eq 1 ]; then
echo "⚠️ Bandit found low-severity issues (see above)"
# Check if there are medium or high severity issues
if bandit -c ../../.bandit -r src/ -lll &>/dev/null; then
echo "✅ No medium or high severity issues found - continuing"
exit 0
else
echo "❌ Medium or high severity issues found - failing"
exit 1
fi
fi
exit ${BANDIT_EXIT:-0}

- name: Check dependencies with Safety
run: |
cd ${{ env.PACKAGE_DIR }}
echo "=== Checking dependencies with Safety ==="
pip install -e ".[dev,test]"
# Using the new 'scan' command as 'check' is deprecated
safety scan --json || SAFETY_EXIT=$?
# Safety scan exits with 64 if vulnerabilities found
if [ "${SAFETY_EXIT:-0}" -eq 64 ]; then
echo "❌ Vulnerabilities found in dependencies"
exit 1
fi

- name: Run pip-audit
run: |
cd ${{ env.PACKAGE_DIR }}
echo "=== Running pip-audit ==="
# Skip the local package as it's not on PyPI yet
pip-audit --skip-editable

- name: Upload security reports
uses: actions/upload-artifact@v4
if: always()
with:
name: security-reports-${{ inputs.package }}
path: |
${{ env.PACKAGE_DIR }}/bandit-report.json

unit-tests:
runs-on: ubuntu-latest
needs: lint
name: Unit Tests ${{ inputs.package }}

steps:
- uses: actions/checkout@v4

- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install dependencies
run: |
cd ${{ env.PACKAGE_DIR }}
python -m pip install --upgrade pip
pip install -e ".[test]"

- name: Run unit tests with coverage
run: |
cd ${{ env.PACKAGE_DIR }}
pytest tests/unit/ -v --cov=${{ inputs.package == 'async-cassandra' && 'async_cassandra' || 'async_cassandra_bulk' }} --cov-report=html --cov-report=xml || echo "No unit tests found (expected for new packages)"

build:
runs-on: ubuntu-latest
needs: [lint, security, unit-tests]
name: Build ${{ inputs.package }}

steps:
- uses: actions/checkout@v4

- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install build dependencies
run: |
python -m pip install --upgrade pip
pip install build twine

- name: Build package
run: |
cd ${{ env.PACKAGE_DIR }}
echo "=== Building package ==="
python -m build
echo "=== Package contents ==="
ls -la dist/

- name: Check package with twine
run: |
cd ${{ env.PACKAGE_DIR }}
echo "=== Checking package metadata ==="
twine check dist/*

- name: Display package info
run: |
cd ${{ env.PACKAGE_DIR }}
echo "=== Wheel contents ==="
python -m zipfile -l dist/*.whl | head -20
echo "=== Package metadata ==="
pip show --verbose ${{ inputs.package }} || true

- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: python-package-distributions-${{ inputs.package }}
path: ${{ env.PACKAGE_DIR }}/dist/
retention-days: 7

integration-tests:
runs-on: ubuntu-latest
needs: [lint, security, unit-tests]
if: ${{ inputs.package == 'async-cassandra' && (inputs.run-integration-tests || inputs.run-full-suite) }}
name: Integration Tests ${{ inputs.package }}

strategy:
fail-fast: false
matrix:
test-suite:
- name: "Integration Tests"
command: "pytest tests/integration -v -m 'not stress'"
- name: "FastAPI Integration"
command: "pytest tests/fastapi_integration -v"
- name: "BDD Tests"
command: "pytest tests/bdd -v"
- name: "Example App"
command: "cd ../../examples/fastapi_app && pytest tests/ -v"

services:
cassandra:
image: cassandra:5
ports:
- 9042:9042
options: >-
--health-cmd "nodetool status"
--health-interval 30s
--health-timeout 10s
--health-retries 10
--memory=4g
--memory-reservation=4g
env:
CASSANDRA_CLUSTER_NAME: TestCluster
CASSANDRA_DC: datacenter1
CASSANDRA_ENDPOINT_SNITCH: GossipingPropertyFileSnitch
HEAP_NEWSIZE: 512M
MAX_HEAP_SIZE: 3G
JVM_OPTS: "-XX:+UseG1GC -XX:G1RSetUpdatingPauseTimePercent=5 -XX:MaxGCPauseMillis=300"

steps:
- uses: actions/checkout@v4

- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install dependencies
run: |
cd ${{ env.PACKAGE_DIR }}
python -m pip install --upgrade pip
pip install -e ".[test,dev]"

- name: Verify Cassandra is ready
run: |
echo "Installing cqlsh to verify Cassandra..."
pip install cqlsh
echo "Testing Cassandra connection..."
cqlsh localhost 9042 -e "DESC CLUSTER" | head -10
echo "✅ Cassandra is ready and responding to CQL"

- name: Run ${{ matrix.test-suite.name }}
env:
CASSANDRA_HOST: localhost
CASSANDRA_PORT: 9042
run: |
cd ${{ env.PACKAGE_DIR }}
echo "=== Running ${{ matrix.test-suite.name }} ==="
${{ matrix.test-suite.command }}

stress-tests:
runs-on: ubuntu-latest
needs: [lint, security, unit-tests]
if: ${{ inputs.package == 'async-cassandra' && inputs.run-full-suite }}
name: Stress Tests ${{ inputs.package }}

strategy:
fail-fast: false
matrix:
test-suite:
- name: "Stress Tests"
command: "pytest tests/integration -v -m stress"

services:
cassandra:
image: cassandra:5
ports:
- 9042:9042
options: >-
--health-cmd "nodetool status"
--health-interval 30s
--health-timeout 10s
--health-retries 10
--memory=4g
--memory-reservation=4g
env:
CASSANDRA_CLUSTER_NAME: TestCluster
CASSANDRA_DC: datacenter1
CASSANDRA_ENDPOINT_SNITCH: GossipingPropertyFileSnitch
HEAP_NEWSIZE: 512M
MAX_HEAP_SIZE: 3G
JVM_OPTS: "-XX:+UseG1GC -XX:G1RSetUpdatingPauseTimePercent=5 -XX:MaxGCPauseMillis=300"

steps:
- uses: actions/checkout@v4

- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install dependencies
run: |
cd ${{ env.PACKAGE_DIR }}
python -m pip install --upgrade pip
pip install -e ".[test,dev]"

- name: Verify Cassandra is ready
run: |
echo "Installing cqlsh to verify Cassandra..."
pip install cqlsh
echo "Testing Cassandra connection..."
cqlsh localhost 9042 -e "DESC CLUSTER" | head -10
echo "✅ Cassandra is ready and responding to CQL"

- name: Run ${{ matrix.test-suite.name }}
env:
CASSANDRA_HOST: localhost
CASSANDRA_PORT: 9042
run: |
cd ${{ env.PACKAGE_DIR }}
echo "=== Running ${{ matrix.test-suite.name }} ==="
${{ matrix.test-suite.command }}

test-summary:
name: Test Summary ${{ inputs.package }}
runs-on: ubuntu-latest
needs: [lint, security, unit-tests, build]
if: always()
steps:
- name: Summary
run: |
echo "## Test Results Summary for ${{ inputs.package }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Core Tests" >> $GITHUB_STEP_SUMMARY
echo "- Lint: ${{ needs.lint.result }}" >> $GITHUB_STEP_SUMMARY
echo "- Security: ${{ needs.security.result }}" >> $GITHUB_STEP_SUMMARY
echo "- Unit Tests: ${{ needs.unit-tests.result }}" >> $GITHUB_STEP_SUMMARY
echo "- Build: ${{ needs.build.result }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY

if [ "${{ needs.lint.result }}" != "success" ] || \
[ "${{ needs.security.result }}" != "success" ] || \
[ "${{ needs.unit-tests.result }}" != "success" ] || \
[ "${{ needs.build.result }}" != "success" ]; then
echo "❌ Some tests failed" >> $GITHUB_STEP_SUMMARY
exit 1
else
echo "✅ All tests passed" >> $GITHUB_STEP_SUMMARY
fi
31 changes: 31 additions & 0 deletions .github/workflows/full-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Full Test Suite

on:
workflow_dispatch:
inputs:
package:
description: 'Package to test (async-cassandra, async-cassandra-bulk, or both)'
required: true
default: 'both'
type: choice
options:
- async-cassandra
- async-cassandra-bulk
- both

jobs:
async-cassandra:
if: ${{ github.event.inputs.package == 'async-cassandra' || github.event.inputs.package == 'both' }}
uses: ./.github/workflows/ci-monorepo.yml
with:
package: async-cassandra
run-integration-tests: true
run-full-suite: true

async-cassandra-bulk:
if: ${{ github.event.inputs.package == 'async-cassandra-bulk' || github.event.inputs.package == 'both' }}
uses: ./.github/workflows/ci-monorepo.yml
with:
package: async-cassandra-bulk
run-integration-tests: false
run-full-suite: false
Loading
Loading