AtlatestRepositoryfjo
1
;;; (fjo pipelines) - Woodpecker CI pipeline tools.2
;;;3
;;; MCP tools and CLI handlers for viewing Woodpecker CI pipeline4
;;; status with step details.6
(define-library (fjo pipelines)7
(import (sigil core)8
(sigil string)9
(sigil json)10
(sigil array)11
(sigil mcp server)12
(woodpecker pipelines)13
(fjo config))14
(export register-pipeline-tools!15
tool-pipelines-list16
tool-pipelines-get)17
(begin19
;; ============================================================20
;; Helpers21
;; ============================================================23
;;; Look up a Woodpecker repo ID from owner/repo.24
(define (lookup-repo-id base-url token owner repo)25
(guard (e (else26
(error (string-append "Failed to look up Woodpecker repo "27
owner "/" repo ": "28
(exception-message e)))))29
(let ((result (woodpecker-repo-lookup base-url token30
(string-append owner "/" repo))))31
(dict-ref result id:))))33
(define (truncate-message msg max-len)34
(let ((first-line (let ((nl (string-find msg "\n")))35
(if nl (substring msg 0 nl) msg))))36
(if (> (string-length first-line) max-len)37
(string-append (substring first-line 0 max-len) "...")38
first-line)))40
;; ============================================================41
;; Tool Schemas42
;; ============================================================44
(define pipelines-list-schema45
'((type . "object")46
(properties . ((owner . ((type . "string")47
(description . "Repository owner (user or org)")))48
(repo . ((type . "string")49
(description . "Repository name")))))50
(required . ("owner" "repo"))))52
(define pipelines-get-schema53
'((type . "object")54
(properties . ((owner . ((type . "string")55
(description . "Repository owner (user or org)")))56
(repo . ((type . "string")57
(description . "Repository name")))58
(number . ((type . "integer")59
(description . "Pipeline number")))))60
(required . ("owner" "repo" "number"))))62
;; ============================================================63
;; Formatting64
;; ============================================================66
(define (format-pipeline p)67
(let ((number (dict-ref p number:))68
(status (dict-ref p status:))69
(branch (dict-ref p branch: ""))70
(event (dict-ref p event: ""))71
(message (dict-ref p message: ""))72
(author (dict-ref p author: "")))73
(string-append74
"#" (number->string number)75
" [" status "] "76
(if (not (string=? event ""))77
(string-append event " ")78
"")79
(if (not (string=? branch ""))80
(string-append "on " branch " ")81
"")82
(if (not (string=? author ""))83
(string-append "by " author " ")84
"")85
"- " (truncate-message message 60))))87
(define (format-step s)88
(let ((name (dict-ref s name:))89
(state (dict-ref s state: "unknown"))90
(exit-code (dict-ref s exit_code: 0)))91
(string-append92
" " name " [" state "]"93
(if (not (= exit-code 0))94
(string-append " (exit " (number->string exit-code) ")")95
""))))97
(define (format-pipeline-detail p steps)98
(let ((number (dict-ref p number:))99
(status (dict-ref p status:))100
(branch (dict-ref p branch: ""))101
(event (dict-ref p event: ""))102
(message (dict-ref p message: ""))103
(author (dict-ref p author: ""))104
(commit (dict-ref p commit: "")))105
(string-append106
"Pipeline #" (number->string number) "\n"107
"Status: " status "\n"108
"Event: " event "\n"109
"Branch: " branch "\n"110
"Commit: " (if (> (string-length commit) 8)111
(substring commit 0 8)112
commit) "\n"113
"Author: " author "\n"114
"Message: " (truncate-message message 80) "\n"115
"\nSteps:\n"116
(if (and steps (> (array-length steps) 0))117
(string-join (map format-step (array->list steps)) "\n")118
" (no steps)"))))120
;; ============================================================121
;; Tool Handlers122
;; ============================================================124
(define (tool-pipelines-list args)125
(let* ((owner (dict-ref args owner:))126
(repo (dict-ref args repo:))127
(base (fjo-woodpecker-url))128
(token (fjo-woodpecker-token))129
(repo-id (lookup-repo-id base token owner repo))130
(pipelines (woodpecker-list-pipelines base token repo-id)))131
(if (or (not pipelines) (= (array-length pipelines) 0))132
(string-append "No pipelines found for " owner "/" repo ".")133
(string-append134
"Pipelines for " owner "/" repo ":\n\n"135
(string-join (map format-pipeline (array->list pipelines)) "\n")))))137
(define (tool-pipelines-get args)138
(let* ((owner (dict-ref args owner:))139
(repo (dict-ref args repo:))140
(number (dict-ref args number:))141
(base (fjo-woodpecker-url))142
(token (fjo-woodpecker-token))143
(repo-id (lookup-repo-id base token owner repo))144
(pipeline (woodpecker-get-pipeline base token repo-id number))145
(steps (woodpecker-list-steps base token repo-id number)))146
(if (not pipeline)147
(string-append "Pipeline #" (number->string number) " not found.")148
(format-pipeline-detail pipeline steps))))150
;; ============================================================151
;; MCP Registration152
;; ============================================================154
(define (register-pipeline-tools! server register)155
(register server156
"fjo/pipelines-list"157
"List recent Woodpecker CI pipelines for a repository."158
pipelines-list-schema159
tool-pipelines-list)161
(register server162
"fjo/pipelines-get"163
"Get details of a specific pipeline with step status."164
pipelines-get-schema165
tool-pipelines-get))167
))