all repos — memnarch @ 2bb6d24546698e84f332e59c36c22c5b8de764ba

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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
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/action"
  "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
      clone := exec.Command("git", "clone", repoUrl)
      clone.Dir = workingDir
    
      err := clone.Run()
      if err != nil {
        // clone error - log it and quit
        return
      }
      // read memnarch action file
      urlParams := req.Context().Value("params").(map[string]string)
      jobName := urlParams["job"]
      
      jobFile := filepath.Join(workingDir, repo, jobName + ".yml")
      a, err := action.Read(jobFile)
      
      if err != nil {
        fmt.Println(err.Error())
      }
    
      // decode and perform action
      // build
      buildCmd := exec.Command(a.Build.Cmd)
      buildCmd.Dir = filepath.Join(workingDir, repo)
      
      // pre-deploy
      // deploy
      // post-deploy
    }()
    
    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)
  }
}