Skip to content

release: pyproc-worker 0.1.1 (PyPI) #290

release: pyproc-worker 0.1.1 (PyPI)

release: pyproc-worker 0.1.1 (PyPI) #290

Workflow file for this run

name: CI
on:
push:
branches: [ main, master ]
pull_request:
branches: [ "**" ]
permissions:
contents: write
jobs:
go:
name: Go ${{ matrix.task }}
runs-on: ubuntu-latest
strategy:
matrix:
task: [test, lint, build]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: true
# Test task
- name: Setup Python for tests
if: matrix.task == 'test'
uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: Install Python worker package
if: matrix.task == 'test'
run: |
cd worker/python
pip install -e .
cd ../..
- name: Test with coverage
if: matrix.task == 'test'
shell: bash
run: |
set -euo pipefail
pkgs=$(go list ./... | grep -v '/bench')
if [ -n "$pkgs" ]; then
go test -timeout 5m -v -race -coverprofile=coverage.out -covermode=atomic $pkgs
fi
- name: Check Go coverage is 100%
if: matrix.task == 'test'
continue-on-error: true
shell: bash
run: |
set -euo pipefail
if [ -f coverage.out ]; then
coverage=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | sed 's/%//')
echo "Total coverage: ${coverage}%"
if (( $(echo "$coverage < 100" | bc -l) )); then
echo "⚠️ Coverage ${coverage}% is below 100% (currently non-blocking)"
echo "Goal: Achieve 100% coverage before re-enabling strict enforcement"
else
echo "✅ Coverage is 100%"
fi
fi
- name: Upload coverage to Codecov
if: matrix.task == 'test' && github.event_name == 'push'
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage.out
fail_ci_if_error: false
- name: Update coverage report
if: matrix.task == 'test' && github.event_name == 'push'
uses: ncruces/go-coverage-report@v0
with:
report: true
chart: true
amend: true
continue-on-error: true
# Lint task
- name: Go fmt check
if: matrix.task == 'lint'
run: |
fmt_out=$(gofmt -l . || true)
if [ -n "$fmt_out" ]; then
echo "Run 'go fmt' on the following files:" >&2
echo "$fmt_out" >&2
exit 1
fi
- name: golangci-lint
if: matrix.task == 'lint'
uses: golangci/golangci-lint-action@v6
with:
version: latest
args: --timeout=5m
# Build task
- name: Go vet
if: matrix.task == 'build'
shell: bash
run: |
set -euo pipefail
pkgs=$(go list ./... | grep -v '/bench')
if [ -n "$pkgs" ]; then
echo "$pkgs" | xargs -r -n1 go vet
fi
- name: Build all packages
if: matrix.task == 'build'
shell: bash
run: |
set -euo pipefail
pkgs=$(go list ./... | grep -v '/bench')
if [ -n "$pkgs" ]; then
echo "$pkgs" | xargs -r -n1 go build
fi
- name: Build examples
if: matrix.task == 'build'
run: go build ./examples/basic
python:
name: Python lint and tests (uv)
runs-on: ubuntu-latest
defaults:
run:
working-directory: worker/python
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup uv and Python
uses: astral-sh/setup-uv@v4
- name: Sync dependencies
run: uv sync --all-extras --dev
- name: Ruff check
run: uv run ruff check .
- name: Ruff format check
run: uv run ruff format --check .
- name: ty check
run: uv run ty check .
- name: Pytest with coverage
run: uv run pytest -q --cov=pyproc_worker --cov-report=term-missing --cov-report=xml
- name: Check Python coverage is 100%
continue-on-error: true
run: |
coverage=$(uv run coverage report --precision=2 | grep TOTAL | awk '{print $4}' | sed 's/%//')
echo "Total coverage: ${coverage}%"
if (( $(echo "$coverage < 100" | bc -l) )); then
echo "⚠️ Coverage ${coverage}% is below 100% (currently non-blocking)"
echo "Goal: Achieve 100% coverage before re-enabling strict enforcement"
else
echo "✅ Coverage is 100%"
fi
benchmark:
name: Performance benchmarks and gates
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: true
- name: Setup Python with uv
uses: astral-sh/setup-uv@v4
- name: Install Python dependencies
run: |
cd worker/python
uv sync --all-extras
- name: Run benchmarks
run: |
cd bench
go test -bench=BenchmarkLatencyPercentiles -benchmem -benchtime=10s -timeout=5m | tee benchmark_results.txt || true
# Extract and check performance metrics
if grep -q "p50:" benchmark_results.txt; then
echo "=== Performance Results ==="
grep -E "p50:|p95:|p99:" benchmark_results.txt
# Extract p50 value (in microseconds)
p50=$(grep "p50:" benchmark_results.txt | sed -E 's/.*p50: ([0-9.]+).*/\1/')
p99=$(grep "p99:" benchmark_results.txt | sed -E 's/.*p99: ([0-9.]+).*/\1/')
echo ""
echo "Checking performance gates..."
# Check p50 < 100µs
if [ ! -z "$p50" ]; then
if (( $(echo "$p50 > 100" | bc -l) )); then
echo "⚠️ p50 latency ${p50}µs exceeds target of 100µs (non-blocking)"
else
echo "✅ p50 latency ${p50}µs meets target (<100µs)"
fi
fi
# Check p99 < 500µs
if [ ! -z "$p99" ]; then
if (( $(echo "$p99 > 500" | bc -l) )); then
echo "⚠️ p99 latency ${p99}µs exceeds target of 500µs (non-blocking)"
else
echo "✅ p99 latency ${p99}µs meets target (<500µs)"
fi
fi
else
echo "No latency metrics found in benchmark results"
fi
- name: Upload benchmark results
uses: actions/upload-artifact@v4
with:
name: benchmark-results
path: bench/benchmark_results.txt
pr-language:
name: PR language check (English)
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- name: Check PR title and body are in English
uses: actions/github-script@v7
with:
script: |
const title = context.payload.pull_request.title;
const body = context.payload.pull_request.body || '';
// Detect non-ASCII heavy content (CJK, Cyrillic, etc.)
const nonAsciiRatio = (str) => {
if (!str || str.length === 0) return 0;
const nonAscii = str.match(/[^\x00-\x7F]/g) || [];
return nonAscii.length / str.length;
};
const titleRatio = nonAsciiRatio(title);
const bodyRatio = nonAsciiRatio(body);
console.log(`Title non-ASCII ratio: ${(titleRatio * 100).toFixed(1)}%`);
console.log(`Body non-ASCII ratio: ${(bodyRatio * 100).toFixed(1)}%`);
const threshold = 0.3;
const issues = [];
if (titleRatio > threshold) {
issues.push(`PR title contains ${(titleRatio * 100).toFixed(0)}% non-ASCII characters. Please use English.`);
}
if (body.length > 0 && bodyRatio > threshold) {
issues.push(`PR body contains ${(bodyRatio * 100).toFixed(0)}% non-ASCII characters. Please use English.`);
}
if (issues.length > 0) {
core.setFailed(issues.join('\n'));
} else {
console.log('PR title and body are in English.');
}
links:
name: README and docs link check
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Link Checker
uses: lycheeverse/lychee-action@v2
with:
args: --config .lychee.toml README.md "docs/**/*.md"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
sbom:
name: SBOM generation
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install syft
uses: anchore/sbom-action/download-syft@v0
- name: Generate Go SBOM
run: syft dir:. --exclude ./worker/python -o cyclonedx-json=sbom-go.cdx.json
- name: Generate Python SBOM
run: syft dir:worker/python -o cyclonedx-json=sbom-python.cdx.json
- name: Upload SBOMs
uses: actions/upload-artifact@v4
with:
name: sbom
path: |
sbom-go.cdx.json
sbom-python.cdx.json
k8s-manifests:
name: K8s manifest validation
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Helm
uses: azure/setup-helm@v4
- name: Install kustomize
uses: imranismail/setup-kustomize@v2
- name: Helm lint
run: helm lint charts/pyproc/
- name: Helm template
run: helm template test charts/pyproc/
- name: Kustomize build - dev
run: kustomize build deploy/kustomize/overlays/dev
- name: Kustomize build - staging
run: kustomize build deploy/kustomize/overlays/staging
- name: Kustomize build - production
run: kustomize build deploy/kustomize/overlays/production