Created
October 9, 2017 15:35
-
-
Save ShawnMilo/54138dd079b2037fd0bd1aa4929c445c to your computer and use it in GitHub Desktop.
Listen for GitHub webhooks and keep local repos up to date.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
/* | |
Listen for calls from GitHub and update local repositories. | |
*/ | |
import ( | |
"encoding/json" | |
"fmt" | |
"io/ioutil" | |
"log" | |
"net/http" | |
"os" | |
"os/exec" | |
"os/user" | |
"path/filepath" | |
"strings" | |
"time" | |
) | |
var gopath string | |
func init() { | |
// Set gopath to GOPATH or $HOME (the default) | |
gp := os.Getenv("GOPATH") | |
if gp == "" { | |
u, err := user.Current() | |
if err != nil { | |
log.Printf("Failed to check home dir: %s\n", err) | |
} else { | |
gp = u.HomeDir | |
} | |
} | |
gopath = filepath.Join(gp, "src") | |
} | |
// event represents a JSONfile from GitHub. | |
// It is a small subset of the actual data GitHub provides. | |
type event struct { | |
Repository repo `json:"repository"` | |
Action string | |
CommitID string `json:"after"` | |
Branch string `json:"ref"` | |
path string | |
} | |
type repo struct { | |
URL string `json:"html_url"` | |
Name string `json:"name"` | |
FullName string `json:"full_name"` | |
} | |
func (e event) String() string { | |
return fmt.Sprintf("%s %s", e.Repository.URL, e.Action) | |
} | |
func main() { | |
http.HandleFunc("/", catch) | |
http.ListenAndServe(":7000", nil) | |
} | |
func catch(w http.ResponseWriter, r *http.Request) { | |
defer w.Write([]byte("OK")) | |
body, err := ioutil.ReadAll(r.Body) | |
if err != nil { | |
log.Printf("Failed to read body: %s\n") | |
return | |
} | |
r.Body.Close() | |
filename := fmt.Sprintf("TEMP_%s_%s.json", r.RemoteAddr, time.Now().Format("2006-01-02_150405")) | |
err = ioutil.WriteFile(filename, body, 0644) | |
if err != nil { | |
log.Printf("Failed to write body: %s\n") | |
return | |
} | |
e, err := newEvent(body) | |
if err != nil { | |
log.Printf("Failed to parse event from JSON: %s\n", err) | |
return | |
} | |
go logEvent(e, filename) | |
if e.CommitID != "" { | |
go updateLocal(e) | |
} | |
} | |
func newEvent(body []byte) (*event, error) { | |
e := &event{} | |
err := json.Unmarshal(body, e) | |
if err != nil { | |
return e, err | |
} | |
head := "refs/heads/" | |
if e.CommitID != "" && strings.HasPrefix(e.Branch, head) { | |
e.Branch = e.Branch[len(head):] | |
} | |
prefix := "https://" | |
if strings.HasPrefix(e.Repository.URL, prefix) { | |
e.path = filepath.Join(gopath, e.Repository.URL[len(prefix):]) | |
} | |
return e, err | |
} | |
func logEvent(e *event, filename string) { | |
log.Printf("%s: %s\n", filename, e) | |
fmt.Printf("Event %#v\n", e) | |
if e.CommitID != "" { | |
fmt.Printf("Commit %s\n", e.CommitID) | |
} | |
} | |
func updateLocal(e *event) { | |
/* | |
Go to dir | |
check if dir clean | |
check out branch | |
fetch & pull | |
*/ | |
cmd := exec.Command("git", "diff") | |
cmd.Dir = e.path | |
out, err := cmd.CombinedOutput() | |
if err != nil { | |
log.Printf("Error running combined output: %s\n", err) | |
return | |
} | |
if len(out) > 0 { | |
log.Printf("%s directory not clean.\n", e.path) | |
return | |
} | |
cmd = exec.Command("git", "checkout", e.Branch) | |
cmd.Dir = e.path | |
if err = cmd.Run(); err != nil { | |
log.Printf("Failed to check out branch: %s\n", err) | |
return | |
} | |
log.Printf("Checked out %s %s\n", e.Repository, e.Branch) | |
cmd = exec.Command("git", "fetch") | |
cmd.Dir = e.path | |
if err = cmd.Run(); err != nil { | |
log.Printf("Failed to fetch: %s\n", err) | |
return | |
} | |
log.Printf("Fetched %s %s\n", e.Repository, e.Branch) | |
cmd = exec.Command("git", "pull", "origin", e.Branch) | |
cmd.Dir = e.path | |
if err = cmd.Run(); err != nil { | |
log.Printf("Failed to pull branch %s: %s\n", e.Branch, err) | |
return | |
} | |
log.Printf("Pulled %s %s\n", e.Repository, e.Branch) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment