ci: migrate GitHub actions to Gitea actions
Deploy CV Site (andreknie.de) / deploy (push) Canceled after 0s

This commit is contained in:
2026-07-22 15:42:06 +02:00
parent e1cf49b0a2
commit b46de6dc7d
649 changed files with 127224 additions and 2786 deletions
-21
View File
@@ -1,21 +0,0 @@
name: Deploy to VPS
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy to VPS via SSH
uses: appleboy/ssh-action@v1
with:
host: 217.160.174.2
username: root
key: ${{ secrets.VPS_SSH_KEY }}
script: |
cd /opt/AI-Orchestrator
git pull origin main
docker compose up -d --build
echo "Deploy complete"
-32
View File
@@ -1,32 +0,0 @@
name: PAT Lifecycle Check
on:
schedule:
- cron: '0 6 * * 1' # Every Monday at 06:00 UTC
workflow_dispatch: {}
jobs:
check-pats:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: pip install -r scripts/pat_manager/requirements.txt
- name: Run PAT Manager
env:
GITLAB_PAT: ${{ secrets.GITLAB_PAT }}
GITLAB_URL: https://gitlab.com
JIRA_PAT: ${{ secrets.JIRA_PAT }}
JIRA_URL: https://jira.atlassian.net
CONFLUENCE_PAT: ${{ secrets.CONFLUENCE_PAT }}
CONFLUENCE_URL: https://confluence.atlassian.net
ORGMYLIFE_API_KEY: ${{ secrets.ORGMYLIFE_API_SECRET }}
ORGMYLIFE_URL: https://orgmylife.app
ORGMYLIFE_USER: ${{ secrets.ORGMYLIFE_USER }}
ORGMYLIFE_PASS: ${{ secrets.ORGMYLIFE_PASS }}
GH_TOKEN: ${{ secrets.PAT_MANAGER_TOKEN }}
ALERT_CHANNEL: orgmylife
run: python -m scripts.pat_manager
@@ -1,38 +0,0 @@
name: Sync Tasks to OrgMyLife
on:
push:
paths: ['PLAN.md', 'TASKS.md', 'SETUP_TODO.md']
workflow_dispatch: {}
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Parse open tasks and sync to OrgMyLife
run: |
REPO_NAME="AI-Orchestrator"
TASKS="[]"
for file in SETUP_TODO.md PLAN.md TASKS.md; do
if [ -f "$file" ]; then
ITEMS=$(grep -E '^\s*- \[ \]' "$file" | sed 's/.*- \[ \] //' | head -50)
if [ -n "$ITEMS" ]; then
TASKS=$(echo "$ITEMS" | jq -R -s 'split("\n") | map(select(length > 0)) | map({"title": ., "status": "backlog"})')
break
fi
fi
done
echo "Found tasks: $TASKS"
PAYLOAD=$(jq -n --arg repo "$REPO_NAME" --argjson tasks "$TASKS" '{"repo": $repo, "tasks": $tasks}')
curl -s -X POST \
-u "${{ secrets.ORGMYLIFE_USER }}:${{ secrets.ORGMYLIFE_PASS }}" \
-H "X-API-Key: ${{ secrets.ORGMYLIFE_API_SECRET }}" \
-H "Content-Type: application/json" \
-d "$PAYLOAD" \
"https://api.andreknie.de/api/projects/sync"
+2
View File
@@ -15,6 +15,8 @@ authors = [
dependencies = [
"pyyaml>=6.0",
"pypdf>=4.0",
"python-docx>=1.1.0",
]
[project.optional-dependencies]
@@ -127,11 +127,13 @@ def register_default_strategies() -> None:
from monorepo.knowledge.sources.jira import JiraSource
from monorepo.knowledge.sources.markdown import MarkdownSource
from monorepo.knowledge.sources.pdf import PDFSource
from monorepo.knowledge.sources.docx import DocxSource
from monorepo.knowledge.sources.wissensdatenbank import WissensdatenbankSource
defaults: dict[str, type[SourceStrategy]] = {
"markdown": MarkdownSource,
"pdf": PDFSource,
"docx": DocxSource,
"confluence": ConfluenceSource,
"jira": JiraSource,
"email": EmailSource,
@@ -0,0 +1,151 @@
"""DOCX-Quellstrategie für die ETL-Pipeline.
Implementiert die Extraktion von Text aus DOCX-Dateien.
"""
from __future__ import annotations
import logging
from datetime import date, datetime
from pathlib import Path
from monorepo.knowledge.artifact import Artifact, ArtifactMetadata, compute_content_hash
from monorepo.knowledge.sources.base import (
ExtractionResult,
SourceConfig,
SourceError,
SourceStrategy,
)
logger = logging.getLogger(__name__)
DOCX_EXTENSIONS = {".docx"}
def _extract_docx_text(file_path: Path) -> str:
try:
import docx # type: ignore[import-untyped]
except ImportError:
raise ImportError(
"Keine DOCX-Bibliothek verfügbar. "
"Installiere 'python-docx': pip install python-docx"
)
doc = docx.Document(str(file_path))
full_text = []
for para in doc.paragraphs:
full_text.append(para.text)
return "\n\n".join(full_text)
class DocxSource(SourceStrategy):
"""Quellstrategie für DOCX-Dateien."""
def extract(self, config: SourceConfig, context: str) -> ExtractionResult:
result = ExtractionResult()
source_path = self._resolve_source_path(config)
if source_path is None:
result.errors.append(
SourceError(
source_name=config.name,
error_type="parse",
message="Kein gültiger Pfad in config.params['path'] oder config.params['directory']",
timestamp=datetime.now().isoformat(),
retry=False,
)
)
return result
files = self._collect_files(source_path)
if not files:
logger.info("Keine DOCX-Dateien gefunden in: %s", source_path)
return result
for file_path in files:
try:
artifact = self._process_file(file_path, config, context)
if artifact is not None:
result.artifacts.append(artifact)
except Exception as e:
logger.error("Fehler bei der Verarbeitung von %s: %s", file_path, e)
result.errors.append(
SourceError(
source_name=config.name,
error_type="parse",
message=f"Fehler bei {file_path.name}: {e}",
timestamp=datetime.now().isoformat(),
retry=True,
artifact_path=str(file_path),
)
)
return result
def supports_incremental(self) -> bool:
return True
def _resolve_source_path(self, config: SourceConfig) -> Path | None:
path_str = config.params.get("path") or config.params.get("directory") or ""
if not path_str:
return None
source_path = Path(path_str)
if not source_path.exists():
return None
return source_path
def _collect_files(self, source_path: Path) -> list[Path]:
if source_path.is_file():
if source_path.suffix.lower() in DOCX_EXTENSIONS:
return [source_path]
return []
files: list[Path] = []
for ext in DOCX_EXTENSIONS:
files.extend(source_path.rglob(f"*{ext}"))
return sorted(files)
def _process_file(
self, file_path: Path, config: SourceConfig, context: str
) -> Artifact | None:
text = ""
try:
text = _extract_docx_text(file_path)
except Exception as e:
logger.warning("DOCX Extraktion fehlgeschlagen für %s: %s", file_path, e)
return self._create_artifact(file_path, text, context)
def _create_artifact(
self, file_path: Path, text: str, context: str
) -> Artifact:
title = file_path.stem.replace("-", " ").replace("_", " ").strip()
if not title:
title = file_path.name
content_hash = compute_content_hash(text) if text else ""
metadata = ArtifactMetadata(
type="reference",
title=title,
tags=["docx"],
source_context=context,
created=date.today(),
updated=date.today(),
shareable=False,
content_hash=content_hash,
source={
"type": "docx",
"file": str(file_path),
},
category="references",
)
content = f"# {title}\n\n{text}\n" if text else f"# {title}\n\n"
return Artifact(
metadata=metadata,
content=content,
file_path=file_path,
)