memnarch/main.go

121 lines
3 KiB
Go
Raw Normal View History

2023-08-26 05:30:39 +00:00
package main
import (
"encoding/json"
"fmt"
"html/template"
"os"
"os/exec"
2023-08-26 05:30:39 +00:00
"net/http"
"path/filepath"
2023-08-26 05:30:39 +00:00
"hacklab.nilfm.cc/quartzgun/renderer"
"hacklab.nilfm.cc/quartzgun/router"
. "hacklab.nilfm.cc/quartzgun/util"
"forge.lightcrystal.systems/lightcrystal/memnarch/webhook"
2023-08-26 05:30:39 +00:00
)
func decode(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
data := make(map[string]interface{})
2023-08-26 05:30:39 +00:00
err := json.NewDecoder(req.Body).Decode(&data)
2023-08-26 05:30:39 +00:00
if err == nil {
AddContextValue(req, "data", data)
} else {
AddContextValue(req, "data", err.Error())
}
next.ServeHTTP(w, req)
})
}
func runJob(secret string, next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
// validate signature
_, err := webhook.Verify([]byte(secret), req)
if err != nil {
w.WriteHeader(422)
return
}
// get repo from data
data := req.Context().Value("data").(map[string]interface{})
if data != nil {
w.WriteHeader(500)
return
}
repoUrl := data["repository"].(map[string]interface{})["clone_url"].(string)
owner := data["owner"].(map[string]interface{})["login"].(string)
repo := data["repository"].(map[string]interface{})["name"].(string)
obj := data["head_commit"].(map[string]interface{})["id"].(string)
// create working dir
workingDir := filepath.Join("working", owner, repo, obj)
if (os.MkdirAll(workingDir, 0750) != nil) {
w.WriteHeader(500)
return
}
// from this point on we can tell the client they succeeded
// so we run the rest in a goroutine...
go func() {
// cd and checkout repo
cmd := exec.Command("git", "clone", repoUrl)
cmd.Dir = workingDir
err := cmd.Run()
if err != nil {
// clone error - log it and quit
return
}
// read memnarch action file
// decode and perform action
}()
AddContextValue(req, "data", "job submitted")
next.ServeHTTP(w, req)
})
}
func seeJobsForRepo(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
})
}
func seeJobsForObject(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
})
2023-08-26 05:30:39 +00:00
}
func run(args []string) error {
secret := args[1]
2023-08-26 05:30:39 +00:00
rtr := &router.Router{
Fallback: *template.Must(template.ParseFiles("templates/error.html")),
}
rtr.Post("/echo", decode(renderer.JSON("data")))
rtr.Post(`/do/(?P<job>\S+)`, decode(runJob(secret, renderer.JSON("data"))))
rtr.Get(`/status/(?P<owner>[^/]+)/(?P<repo>\S+)`, seeJobsForRepo(renderer.JSON("data")))
rtr.Get(`/status/(?P<owner>[^/]+)/(?P<repo>[^/]+)/(?P<object>\S+)`, seeJobsForObject(renderer.JSON("data")))
2023-08-26 05:30:39 +00:00
http.ListenAndServe(":9999", rtr);
return nil
}
func main () {
err := run(os.Args)
if err == nil {
os.Exit(0)
} else {
fmt.Println(err.Error())
os.Exit(1)
}
}