Some checks failed
CI / Code Quality & Linting (push) Failing after 1m3s
CI / Unit Tests (push) Successful in 1m12s
CI / Dependency Scan (push) Successful in 3m1s
CI / SAST — Semgrep (push) Successful in 2m10s
CI / Build Docker Image (push) Has been skipped
CI / Trivy Scan (push) Has been skipped
CI / Push to Registry (push) Has been skipped
CI / Notify Mattermost (push) Failing after 13s
153 lines
5.1 KiB
YAML
153 lines
5.1 KiB
YAML
# Universal CI Pipeline — penpot-mcp
|
|
# Plan: https://outline.themosers.club/doc/universal-test-coverage-plan-nHgsMTqBgk
|
|
|
|
name: CI
|
|
|
|
on:
|
|
push:
|
|
branches-ignore: []
|
|
pull_request:
|
|
branches: [main, test]
|
|
|
|
env:
|
|
REGISTRY: ${{ secrets.REGISTRY_URL }}
|
|
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
|
|
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
|
|
IMAGE_PREFIX: penpot-mcp
|
|
PYTHON_VERSION: '3.11'
|
|
|
|
jobs:
|
|
code-quality:
|
|
name: Code Quality & Linting
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: actions/setup-python@v5
|
|
with:
|
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
- run: |
|
|
pip install ruff mypy
|
|
ruff check src/ || ruff check src/
|
|
mypy src/ --ignore-missing-imports || true
|
|
|
|
unit-tests:
|
|
name: Unit Tests
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: actions/setup-python@v5
|
|
with:
|
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
- run: |
|
|
pip install -r requirements.txt pytest pytest-cov pytest-asyncio
|
|
pytest --cov=src --cov-fail-under=70 --junitxml=test-results/junit.xml -v || echo "No tests yet"
|
|
|
|
dependency-scan:
|
|
name: Dependency Scan
|
|
runs-on: ubuntu-latest
|
|
if: github.ref == 'refs/heads/test' || github.ref == 'refs/heads/main'
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: actions/setup-python@v5
|
|
with:
|
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
- run: pip install pip-audit && pip-audit -r requirements.txt || true
|
|
|
|
sast:
|
|
name: SAST — Semgrep
|
|
runs-on: ubuntu-latest
|
|
if: github.ref == 'refs/heads/test' || github.ref == 'refs/heads/main'
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: semgrep/semgrep-action@v1
|
|
with:
|
|
config: "p/python p/docker p/secrets"
|
|
env:
|
|
SEMGREP_APP_TOKEN: ''
|
|
|
|
build-image:
|
|
name: Build Docker Image
|
|
runs-on: ubuntu-latest
|
|
needs: [code-quality, unit-tests]
|
|
if: github.ref == 'refs/heads/test' || github.ref == 'refs/heads/main'
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: docker/setup-buildx-action@v3
|
|
- name: Generate tags
|
|
id: meta
|
|
run: |
|
|
echo "short_sha=$(echo ${{ github.sha }} | cut -c1-7)" >> $GITHUB_OUTPUT
|
|
echo "branch=$(echo ${GITHUB_REF#refs/heads/} | sed 's/\//-/g')" >> $GITHUB_OUTPUT
|
|
- uses: docker/build-push-action@v5
|
|
with:
|
|
context: .
|
|
push: false
|
|
tags: |
|
|
${{ env.IMAGE_PREFIX }}/server:${{ steps.meta.outputs.short_sha }}
|
|
${{ env.IMAGE_PREFIX }}/server:latest
|
|
outputs: type=docker,dest=/tmp/penpot-mcp.tar
|
|
- uses: actions/upload-artifact@v4
|
|
with:
|
|
name: docker-image
|
|
path: /tmp/penpot-mcp.tar
|
|
retention-days: 1
|
|
|
|
container-scan:
|
|
name: Trivy Scan
|
|
runs-on: ubuntu-latest
|
|
needs: build-image
|
|
if: github.ref == 'refs/heads/test' || github.ref == 'refs/heads/main'
|
|
steps:
|
|
- uses: actions/download-artifact@v4
|
|
with:
|
|
name: docker-image
|
|
path: /tmp
|
|
- run: docker load --input /tmp/penpot-mcp.tar
|
|
- uses: aquasecurity/trivy-action@master
|
|
with:
|
|
image-ref: ${{ env.IMAGE_PREFIX }}/server:latest
|
|
format: json
|
|
output: trivy.json
|
|
severity: CRITICAL,HIGH
|
|
exit-code: '1'
|
|
- uses: actions/upload-artifact@v4
|
|
if: always()
|
|
with:
|
|
name: trivy-results
|
|
path: trivy.json
|
|
retention-days: 30
|
|
|
|
push-image:
|
|
name: Push to Registry
|
|
runs-on: ubuntu-latest
|
|
needs: container-scan
|
|
if: github.ref == 'refs/heads/main'
|
|
steps:
|
|
- uses: actions/download-artifact@v4
|
|
with:
|
|
name: docker-image
|
|
path: /tmp
|
|
- run: docker load --input /tmp/penpot-mcp.tar
|
|
- run: echo "${{ env.REGISTRY_PASSWORD }}" | docker login ${{ env.REGISTRY }} -u ${{ env.REGISTRY_USERNAME }} --password-stdin
|
|
- run: |
|
|
SHORT_SHA=$(echo ${{ github.sha }} | cut -c1-7)
|
|
docker tag ${{ env.IMAGE_PREFIX }}/server:latest ${{ env.REGISTRY }}/${{ env.IMAGE_PREFIX }}/server:latest
|
|
docker tag ${{ env.IMAGE_PREFIX }}/server:latest ${{ env.REGISTRY }}/${{ env.IMAGE_PREFIX }}/server:$SHORT_SHA
|
|
docker push ${{ env.REGISTRY }}/${{ env.IMAGE_PREFIX }}/server:latest
|
|
docker push ${{ env.REGISTRY }}/${{ env.IMAGE_PREFIX }}/server:$SHORT_SHA
|
|
|
|
report:
|
|
name: Notify Mattermost
|
|
runs-on: ubuntu-latest
|
|
needs: [code-quality, unit-tests, container-scan]
|
|
if: always()
|
|
steps:
|
|
- run: |
|
|
OVERALL="success"
|
|
for s in "${{ needs.unit-tests.result }}" "${{ needs.container-scan.result }}"; do
|
|
[ "$s" = "failure" ] && OVERALL="failure" && break
|
|
done
|
|
COLOR="good"; EMOJI="✅"; [ "$OVERALL" = "failure" ] && COLOR="danger" && EMOJI="❌"
|
|
curl -s -X POST "${{ secrets.MATTERMOST_WEBHOOK_URL }}" -H "Content-Type: application/json" \
|
|
-d "{\"attachments\":[{\"color\":\"$COLOR\",\"title\":\"$EMOJI penpot-mcp CI — $(echo ${{ github.sha }} | cut -c1-7)\",\"text\":\"Branch: ${{ github.ref_name }}\"}]}"
|