all repos — memnarch @ 2a1845f04cfe9eb566077f0c98f7133ec23dc6e3

featherweight orchestrator

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)
  }
}