Files
kubeflow/.gitea/workflows/compile-upload.yaml

207 lines
7.2 KiB
YAML

name: Compile and Upload Pipelines
on:
push:
branches: [main]
paths:
- "**/*_pipeline.py"
- "**/*pipeline*.py"
workflow_dispatch:
env:
NTFY_URL: http://ntfy.observability.svc.cluster.local:80
KUBEFLOW_HOST: http://ml-pipeline.kubeflow.svc.cluster.local:8888
jobs:
compile-and-upload:
name: Compile & Upload
runs-on: ubuntu-latest
outputs:
compiled: ${{ steps.compile.outputs.compiled }}
failed: ${{ steps.compile.outputs.failed }}
uploaded: ${{ steps.upload.outputs.uploaded }}
upload_failed: ${{ steps.upload.outputs.failed }}
version: ${{ steps.upload.outputs.version }}
uploaded_names: ${{ steps.upload.outputs.uploaded_names }}
failed_names: ${{ steps.upload.outputs.failed_names }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.13"
- name: Install KFP
run: pip install kfp==2.12.1
- name: Compile pipelines
id: compile
run: |
COMPILED=0
FAILED=0
COMPILED_LIST=""
FAILED_LIST=""
find . -maxdepth 1 -name '*_pipeline.py' | sort | while read -r py_file; do
name=$(basename "$py_file" .py)
echo "::group::Compiling $name"
if python "$py_file"; then
yaml_file="${name}.yaml"
if [ -f "$yaml_file" ]; then
echo "✓ Compiled $name → $yaml_file"
COMPILED=$((COMPILED + 1))
COMPILED_LIST="${COMPILED_LIST}${name}\n"
else
echo "✗ $name produced no YAML output"
FAILED=$((FAILED + 1))
FAILED_LIST="${FAILED_LIST}${name}\n"
fi
else
echo "✗ Failed to compile $name"
FAILED=$((FAILED + 1))
FAILED_LIST="${FAILED_LIST}${name}\n"
fi
echo "::endgroup::"
done
# Re-count from produced files (pipe subshell loses vars)
COMPILED=$(find . -maxdepth 1 -name '*_pipeline.yaml' | wc -l)
TOTAL=$(find . -maxdepth 1 -name '*_pipeline.py' | wc -l)
FAILED=$((TOTAL - COMPILED))
echo "compiled=$COMPILED" >> $GITHUB_OUTPUT
echo "failed=$FAILED" >> $GITHUB_OUTPUT
echo ""
echo "=== Summary ==="
echo "Compiled: $COMPILED / $TOTAL"
if [ "$FAILED" -gt 0 ]; then
echo "::warning::$FAILED pipeline(s) failed to compile"
fi
- name: Upload pipelines to Kubeflow
id: upload
run: |
python3 << 'UPLOAD_SCRIPT'
import os
import sys
from pathlib import Path
from datetime import datetime
from kfp import Client
host = os.environ["KUBEFLOW_HOST"]
print(f"Connecting to Kubeflow at {host}")
try:
client = Client(host=host)
client.list_pipelines(page_size=1)
print("Connected to Kubeflow Pipelines")
except Exception as e:
print(f"ERROR: Cannot connect to Kubeflow: {e}")
sys.exit(1)
# Get all compiled YAML files
yaml_files = sorted(Path(".").glob("*_pipeline.yaml"))
if not yaml_files:
yaml_files = sorted(Path(".").glob("*pipeline*.yaml"))
uploaded = 0
failed = 0
uploaded_names = []
failed_names = []
version_tag = f"v{datetime.now().strftime('%Y%m%d-%H%M%S')}"
for yaml_path in yaml_files:
pipeline_name = yaml_path.stem.replace("_", "-")
print(f"\n--- {pipeline_name} ---")
try:
# Check if pipeline already exists
existing = None
all_pipelines = client.list_pipelines(page_size=200)
if all_pipelines.pipelines:
for p in all_pipelines.pipelines:
if p.display_name == pipeline_name:
existing = p
break
if existing:
print(f" Updating: {pipeline_name} ({existing.pipeline_id})")
client.upload_pipeline_version(
pipeline_package_path=str(yaml_path),
pipeline_version_name=version_tag,
pipeline_id=existing.pipeline_id,
)
else:
print(f" Creating: {pipeline_name}")
client.upload_pipeline(
pipeline_package_path=str(yaml_path),
pipeline_name=pipeline_name,
)
uploaded += 1
uploaded_names.append(pipeline_name)
print(f" ✓ Done")
except Exception as e:
failed += 1
failed_names.append(pipeline_name)
print(f" ✗ Error: {e}")
# Write outputs
with open(os.environ["GITHUB_OUTPUT"], "a") as f:
f.write(f"uploaded={uploaded}\n")
f.write(f"failed={failed}\n")
f.write(f"version={version_tag}\n")
f.write(f"uploaded_names={', '.join(uploaded_names)}\n")
f.write(f"failed_names={', '.join(failed_names)}\n")
print(f"\n=== Upload Summary ===")
print(f"Uploaded: {uploaded}")
print(f"Failed: {failed}")
if failed > 0:
sys.exit(1)
UPLOAD_SCRIPT
notify:
name: Notify
runs-on: ubuntu-latest
needs: [compile-and-upload]
if: always()
steps:
- name: Notify on success
if: needs.compile-and-upload.result == 'success'
run: |
curl -s \
-H "Title: ✅ Pipelines uploaded to Kubeflow" \
-H "Priority: default" \
-H "Tags: white_check_mark,rocket" \
-H "Click: ${{ gitea.server_url }}/${{ gitea.repository }}/actions/runs/${{ gitea.run_id }}" \
-d "Branch: ${{ gitea.ref_name }}
Commit: ${{ gitea.event.head_commit.message || gitea.sha }}
Compiled: ${{ needs.compile-and-upload.outputs.compiled || '?' }} pipeline(s)
Uploaded: ${{ needs.compile-and-upload.outputs.uploaded || '?' }} pipeline(s)
Version: ${{ needs.compile-and-upload.outputs.version || 'n/a' }}" \
${{ env.NTFY_URL }}/gitea-ci
- name: Notify on failure
if: needs.compile-and-upload.result == 'failure'
run: |
curl -s \
-H "Title: ❌ Pipeline upload failed" \
-H "Priority: high" \
-H "Tags: x,rocket" \
-H "Click: ${{ gitea.server_url }}/${{ gitea.repository }}/actions/runs/${{ gitea.run_id }}" \
-d "Branch: ${{ gitea.ref_name }}
Commit: ${{ gitea.event.head_commit.message || gitea.sha }}
Compiled: ${{ needs.compile-and-upload.outputs.compiled || '?' }}, Failed compile: ${{ needs.compile-and-upload.outputs.failed || '?' }}
Upload failures: ${{ needs.compile-and-upload.outputs.failed_names || 'unknown' }}
Check logs for details." \
${{ env.NTFY_URL }}/gitea-ci