chore: Woodpecker CI entfernt — nur noch Gitea Actions
All checks were successful
CI / test-bqas (push) Successful in 27s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-consent (push) Successful in 27s
CI / test-python-voice (push) Successful in 28s
All checks were successful
CI / test-bqas (push) Successful in 27s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-consent (push) Successful in 27s
CI / test-python-voice (push) Successful in 28s
Woodpecker wird nicht mehr verwendet. Wir migrieren vollstaendig auf Gitea Actions (gitea.meghsakha.com). Entfernt: - woodpecker-server + woodpecker-agent Container (docker-compose.yml) - woodpecker_data Volume - backend-core/woodpecker_proxy_api.py (SQLite-DB Proxy) - admin-core/app/api/admin/infrastructure/woodpecker/route.ts - admin-core/app/api/webhooks/woodpecker/route.ts - .woodpecker/main.yml (alte CI-Pipeline-Konfiguration) Bereinigt: - ci-cd/page.tsx: Woodpecker-Tab + Status-Karte + State entfernt - types/infrastructure-modules.ts: Woodpecker-Typen + API-Endpunkte - DevOpsPipelineSidebar.tsx: Textbeschreibungen auf Gitea Actions - dashboard/page.tsx: Woodpecker aus Service-Health-Liste - sbom/page.tsx: Woodpecker aus SBOM-Liste - navigation.ts: Beschreibung aktualisiert - .env.example: WOODPECKER_* Variablen entfernt Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,271 +0,0 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
|
||||
// Woodpecker API configuration
|
||||
const WOODPECKER_URL = process.env.WOODPECKER_URL || 'http://woodpecker-server:8000'
|
||||
const WOODPECKER_TOKEN = process.env.WOODPECKER_TOKEN || ''
|
||||
const BACKEND_URL = process.env.BACKEND_URL || 'http://backend-core:8000'
|
||||
|
||||
export interface PipelineStep {
|
||||
name: string
|
||||
state: 'pending' | 'running' | 'success' | 'failure' | 'skipped'
|
||||
exit_code: number
|
||||
error?: string
|
||||
}
|
||||
|
||||
export interface Pipeline {
|
||||
id: number
|
||||
number: number
|
||||
status: 'pending' | 'running' | 'success' | 'failure' | 'error'
|
||||
event: string
|
||||
branch: string
|
||||
commit: string
|
||||
message: string
|
||||
author: string
|
||||
created: number
|
||||
started: number
|
||||
finished: number
|
||||
steps: PipelineStep[]
|
||||
errors?: string[]
|
||||
repo_name?: string
|
||||
}
|
||||
|
||||
export interface WoodpeckerStatusResponse {
|
||||
status: 'online' | 'offline'
|
||||
pipelines: Pipeline[]
|
||||
lastUpdate: string
|
||||
error?: string
|
||||
}
|
||||
|
||||
async function fetchFromBackendProxy(repoId: string, limit: number): Promise<WoodpeckerStatusResponse> {
|
||||
// Use backend-core proxy that reads Woodpecker sqlite DB directly
|
||||
const url = `${BACKEND_URL}/api/v1/woodpecker/pipelines?repo=${repoId}&limit=${limit}`
|
||||
const response = await fetch(url, { cache: 'no-store' })
|
||||
|
||||
if (!response.ok) {
|
||||
return {
|
||||
status: 'offline',
|
||||
pipelines: [],
|
||||
lastUpdate: new Date().toISOString(),
|
||||
error: `Backend Woodpecker Proxy Fehler (${response.status})`
|
||||
}
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
return {
|
||||
status: data.status || 'online',
|
||||
pipelines: (data.pipelines || []).map((p: any) => ({
|
||||
id: p.id,
|
||||
number: p.number,
|
||||
status: p.status,
|
||||
event: p.event,
|
||||
branch: p.branch || 'main',
|
||||
commit: p.commit || '',
|
||||
message: p.message || '',
|
||||
author: p.author || '',
|
||||
created: p.created,
|
||||
started: p.started,
|
||||
finished: p.finished,
|
||||
repo_name: p.repo_name,
|
||||
steps: (p.steps || []).map((s: any) => ({
|
||||
name: s.name,
|
||||
state: s.state,
|
||||
exit_code: s.exit_code || 0,
|
||||
error: s.error
|
||||
})),
|
||||
})),
|
||||
lastUpdate: data.lastUpdate || new Date().toISOString(),
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchFromWoodpeckerAPI(repoId: string, limit: number): Promise<WoodpeckerStatusResponse> {
|
||||
const response = await fetch(
|
||||
`${WOODPECKER_URL}/api/repos/${repoId}/pipelines?per_page=${limit}`,
|
||||
{
|
||||
headers: {
|
||||
'Authorization': `Bearer ${WOODPECKER_TOKEN}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
cache: 'no-store',
|
||||
}
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
return {
|
||||
status: 'offline',
|
||||
pipelines: [],
|
||||
lastUpdate: new Date().toISOString(),
|
||||
error: `Woodpecker API nicht erreichbar (${response.status})`
|
||||
}
|
||||
}
|
||||
|
||||
const rawPipelines = await response.json()
|
||||
|
||||
const pipelines: Pipeline[] = rawPipelines.map((p: any) => {
|
||||
const errors: string[] = []
|
||||
const steps: PipelineStep[] = []
|
||||
|
||||
if (p.workflows) {
|
||||
for (const workflow of p.workflows) {
|
||||
if (workflow.children) {
|
||||
for (const child of workflow.children) {
|
||||
steps.push({
|
||||
name: child.name,
|
||||
state: child.state,
|
||||
exit_code: child.exit_code,
|
||||
error: child.error
|
||||
})
|
||||
if (child.state === 'failure' && child.error) {
|
||||
errors.push(`${child.name}: ${child.error}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
id: p.id,
|
||||
number: p.number,
|
||||
status: p.status,
|
||||
event: p.event,
|
||||
branch: p.branch,
|
||||
commit: p.commit?.substring(0, 7) || '',
|
||||
message: p.message || '',
|
||||
author: p.author,
|
||||
created: p.created,
|
||||
started: p.started,
|
||||
finished: p.finished,
|
||||
steps,
|
||||
errors: errors.length > 0 ? errors : undefined
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
status: 'online',
|
||||
pipelines,
|
||||
lastUpdate: new Date().toISOString()
|
||||
}
|
||||
}
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
const searchParams = request.nextUrl.searchParams
|
||||
const repoId = searchParams.get('repo') || '0'
|
||||
const limit = parseInt(searchParams.get('limit') || '10')
|
||||
|
||||
try {
|
||||
// If WOODPECKER_TOKEN is set, use the Woodpecker API directly
|
||||
// Otherwise, use the backend proxy that reads the sqlite DB
|
||||
if (WOODPECKER_TOKEN) {
|
||||
return NextResponse.json(await fetchFromWoodpeckerAPI(repoId, limit))
|
||||
} else {
|
||||
return NextResponse.json(await fetchFromBackendProxy(repoId, limit))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Woodpecker API error:', error)
|
||||
return NextResponse.json({
|
||||
status: 'offline',
|
||||
pipelines: [],
|
||||
lastUpdate: new Date().toISOString(),
|
||||
error: 'Fehler beim Abrufen des Woodpecker Status'
|
||||
} as WoodpeckerStatusResponse)
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger a new pipeline
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const body = await request.json()
|
||||
const { repoId = '1', branch = 'main' } = body
|
||||
|
||||
if (!WOODPECKER_TOKEN) {
|
||||
return NextResponse.json(
|
||||
{ error: 'WOODPECKER_TOKEN nicht konfiguriert - Pipeline-Start nicht moeglich' },
|
||||
{ status: 503 }
|
||||
)
|
||||
}
|
||||
|
||||
const response = await fetch(
|
||||
`${WOODPECKER_URL}/api/repos/${repoId}/pipelines`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${WOODPECKER_TOKEN}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ branch }),
|
||||
}
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Pipeline konnte nicht gestartet werden' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
|
||||
const pipeline = await response.json()
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
pipeline: {
|
||||
id: pipeline.id,
|
||||
number: pipeline.number,
|
||||
status: pipeline.status
|
||||
}
|
||||
})
|
||||
|
||||
} catch (error) {
|
||||
console.error('Pipeline trigger error:', error)
|
||||
return NextResponse.json(
|
||||
{ error: 'Fehler beim Starten der Pipeline' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Get pipeline logs
|
||||
export async function PUT(request: NextRequest) {
|
||||
try {
|
||||
const body = await request.json()
|
||||
const { repoId = '1', pipelineNumber, stepId } = body
|
||||
|
||||
if (!pipelineNumber || !stepId) {
|
||||
return NextResponse.json(
|
||||
{ error: 'pipelineNumber und stepId erforderlich' },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
if (!WOODPECKER_TOKEN) {
|
||||
return NextResponse.json(
|
||||
{ error: 'WOODPECKER_TOKEN nicht konfiguriert' },
|
||||
{ status: 503 }
|
||||
)
|
||||
}
|
||||
|
||||
const response = await fetch(
|
||||
`${WOODPECKER_URL}/api/repos/${repoId}/pipelines/${pipelineNumber}/logs/${stepId}`,
|
||||
{
|
||||
headers: {
|
||||
'Authorization': `Bearer ${WOODPECKER_TOKEN}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
if (!response.ok) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Logs nicht verfuegbar' },
|
||||
{ status: response.status }
|
||||
)
|
||||
}
|
||||
|
||||
const logs = await response.json()
|
||||
return NextResponse.json({ logs })
|
||||
|
||||
} catch (error) {
|
||||
console.error('Pipeline logs error:', error)
|
||||
return NextResponse.json(
|
||||
{ error: 'Fehler beim Abrufen der Logs' },
|
||||
{ status: 500 }
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user