main.go (raw)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
package main import ( "encoding/json" "fmt" "html/template" "os" "os/exec" "net/http" "path/filepath" "hacklab.nilfm.cc/quartzgun/renderer" "hacklab.nilfm.cc/quartzgun/router" . "hacklab.nilfm.cc/quartzgun/util" "forge.lightcrystal.systems/lightcrystal/memnarch/webhook" ) func decode(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { data := make(map[string]interface{}) err := json.NewDecoder(req.Body).Decode(&data) 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) { }) } func run(args []string) error { secret := args[1] 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"))) 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) } } |