Skip to content

Instantly share code, notes, and snippets.

@kylebrandt
Last active October 30, 2018 02:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kylebrandt/6860ae8de43edc917392cc3ed6d9fde4 to your computer and use it in GitHub Desktop.
Save kylebrandt/6860ae8de43edc917392cc3ed6d9fde4 to your computer and use it in GitHub Desktop.
Bosun git saving and pulling
package main
import (
"fmt"
"log"
"os"
"path/filepath"
"<replaceme>/bogit/util"
)
const Git = "git"
func main() {
if len(os.Args) < 4 {
log.Fatal("error: not enough arguments, expected filename, user, message")
}
fileArg := os.Args[1]
user := os.Args[2]
message := os.Args[3]
if fileArg == "" {
log.Fatal("error: missing config file name")
}
if user == "" {
log.Fatal("error: missing user")
}
if message == "" {
log.Fatal("error: missing message")
}
fileDir := filepath.Dir(fileArg)
gitCommand := util.GetGitExecuter("git", fileDir, "/opt/bosun/id_rsa")
// We clean (except maybe other files)
output, err := gitCommand("status", "-uno", "--porcelain")
if err != nil {
log.Fatal(fmt.Sprintf("failed to get git status to see if the working tree is clean"))
}
if output == "" {
log.Println("nothing to do since the working tree is clean")
os.Exit(0)
}
// Commit
output, err = gitCommand("commit", "-a", "-m", message, fmt.Sprintf("--author=%v <>", user)) // TODO check for exisiting <> in the future
if err != nil {
log.Fatal(fmt.Sprintf("could not issue commit: %v %v", err, output))
}
// Push
output, err = gitCommand("push", "origin", "master")
if err != nil {
// Assume the commit worked above and restore the state. Bosun should reset the file when this fails,
// so the tree should be clean again
_, err2 := gitCommand("git", "reset", "HEAD~1")
gitReset := "successful"
if err2 != nil {
gitReset = "failed"
}
log.Fatal(fmt.Sprintf("could not issue commit (issued a git reset hard which was %v): %v %v", gitReset, err, output))
}
}
package main
import (
"bytes"
"flag"
"fmt"
"log"
"os"
"strings"
"strconv"
"encoding/json"
"net/http"
"<replaceme>/bogit/util"
)
var repoDirFlag = flag.String("repo", "", "location of the repo")
var keyFlag = flag.String("key", "", "path the the file that contains the private ssh key to access git")
var bosunURLFlag = flag.String("bosun", "", "url to bosun, i.e. http://bosun")
func main() {
flag.Parse()
if *repoDirFlag == "" || *keyFlag == "" || *bosunURLFlag == "" {
log.Fatal("all flags must be specified")
}
// check bosun and make sure save is not enabled
saveEnabled, err := checkBosunSave(*bosunURLFlag)
if err != nil {
log.Fatal(err)
}
if saveEnabled {
log.Println("save enabled on this bosun instance - taking no action")
os.Exit(0)
}
gitCommand := util.GetGitExecuter("git", *repoDirFlag, *keyFlag)
fetchOutput, err := gitCommand("fetch")
if err != nil {
log.Fatalf("failed to run git fetch: %v", fetchOutput)
}
ahead, err := revCount(gitCommand, "ahead")
if err != nil {
log.Fatal(err)
}
if ahead > 0 {
log.Fatal(fmt.Errorf("local master is ahead of origin, aborting"))
}
behind, err := revCount(gitCommand, "behind")
if err != nil {
log.Fatal(err)
}
if behind == 0 {
os.Exit(0)
}
if mergeOutput, err := gitCommand("merge", "origin/master", "--ff-only"); err != nil {
log.Fatalf("failed to fast forward only merge origin/master into master: %v", mergeOutput)
}
if err := reloadBosun(*bosunURLFlag); err != nil {
log.Fatalf("failed to reload bosun: %v", err)
}
}
func revCount(gitCommand func(args ...string) (string, error), ab string) (int, error) {
var rawCount string
var err error
switch ab {
case "ahead":
rawCount, err = gitCommand("rev-list", "--count", "origin/master..master")
case "behind":
rawCount, err = gitCommand("rev-list", "--count", "master..origin/master")
default:
return -1, fmt.Errorf("revCount must be behind or ahead, got %v", ab)
}
if err != nil {
return -1, fmt.Errorf("failed to get rev-list for commits %v count: %v", ab, err)
}
count, err := strconv.Atoi(strings.TrimSpace(rawCount))
if err != nil {
return -1, fmt.Errorf("failed to parse rev-list for commits %v result: %v", ab, err)
}
return count, nil
}
func checkBosunSave(bosunAddr string) (bool, error) {
r, err := http.Get(bosunAddr + "/api/save_enabled")
var enabled bool
if err != nil {
return enabled, fmt.Errorf("unable to get bosun save status: %v", err)
}
defer r.Body.Close()
err = json.NewDecoder(r.Body).Decode(&enabled)
if err != nil {
return enabled, fmt.Errorf("unable to decode response for bosun's save status: %v", err)
}
return enabled, nil
}
func reloadBosun(bosunAddr string) error {
reload := struct{ Reload bool }{true}
b := new(bytes.Buffer)
json.NewEncoder(b).Encode(reload)
_, err := http.Post(bosunAddr+"/api/reload", "application/json", b)
if err != nil {
return fmt.Errorf("unable to issue reload request via HTTP POST to bosun: %v", err)
}
return nil
}
package util
import (
"fmt"
"os"
"os/exec"
)
func GetGitExecuter(gitCmd, fileDir, keyFile string) func(args ...string) (string, error) {
gitSSHEnv := fmt.Sprintf("GIT_SSH_COMMAND=%v", fmt.Sprintf("ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i %v", keyFile))
return func(args ...string) (string, error) {
args = append([]string{"-C", fileDir}, args...)
gitCmd := exec.Command(gitCmd, args...)
//fmt.Println(args)
if keyFile != "" {
gitCmd.Env = append(os.Environ(), gitSSHEnv)
}
output, err := gitCmd.CombinedOutput()
//fmt.Println(string(output))
if err != nil {
return string(output), err
}
return string(output), nil
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment