github.com/billybanfield/evergreen@v0.0.0-20170525200750-eeee692790f7/scripts/all_configs.go (about) 1 // This program uses the Evergreen REST API to grab the most recent configuration 2 // for each project and write each configuration file to the file system for 3 // further analysis. This program's purpose is to provide a useful utility that's 4 // too niche for the main CLI tool and provide a proof of concept to the REST API. 5 // 6 // Usage: upon execution, this program will load the user's CLI settings 7 // (default `~/.evergreen.yml`) and use them to download all project files 8 // to the working directory in the form of "<project_id>.yml" 9 // 10 // -c / --config can pass in a different CLI settings file 11 // 12 package main 13 14 import ( 15 "encoding/json" 16 "fmt" 17 "io" 18 "io/ioutil" 19 "net/http" 20 21 "github.com/evergreen-ci/evergreen/cli" 22 "github.com/jessevdk/go-flags" 23 ) 24 25 // uiClient handles requests against the UI server. 26 type uiClient struct { 27 client *http.Client 28 user string 29 key string 30 uiRoot string 31 } 32 33 // get executes a request against the given REST route, panicking on any errors. 34 func (c *uiClient) get(route string) *http.Response { 35 url := c.uiRoot + "/rest/v1/" + route 36 req, err := http.NewRequest("GET", url, nil) 37 if err != nil { 38 panic(err) 39 } 40 req.Header.Add("Auth-Username", c.user) 41 req.Header.Add("Api-Key", c.key) 42 resp, err := c.client.Do(req) 43 if err != nil { 44 panic(err) 45 } 46 if resp.StatusCode != http.StatusOK { 47 panic(fmt.Sprintf("Bad Status (%v) : %v", url, resp.StatusCode)) 48 } 49 return resp 50 } 51 52 // mustDecodeJSON is a quick helper for panicking if a Reader cannot be read as JSON. 53 func mustDecodeJSON(r io.Reader, i interface{}) { 54 err := json.NewDecoder(r).Decode(i) 55 if err != nil { 56 panic(err) 57 } 58 } 59 60 // fetchAndWriteConfig downloads the most recent config for a project 61 // and writes it to "project_name.yml" locally. 62 func fetchAndWriteConfig(uic *uiClient, project string) { 63 fmt.Println("Downloading configuration for", project) 64 resp := uic.get("projects/" + project + "/versions") 65 v := struct { 66 Versions []struct { 67 Id string `json:"version_id"` 68 } `json:"versions"` 69 }{} 70 mustDecodeJSON(resp.Body, &v) 71 if len(v.Versions) == 0 { 72 fmt.Println("WARNING:", project, "has no versions") 73 return 74 } 75 resp = uic.get("versions/" + v.Versions[0].Id + "?config=1") 76 c := struct { 77 Config string `json:"config"` 78 }{} 79 mustDecodeJSON(resp.Body, &c) 80 if len(c.Config) == 0 { 81 fmt.Println("WARNING:", project, "has empty config file") 82 return 83 } 84 err := ioutil.WriteFile(project+".yml", []byte(c.Config), 0666) 85 if err != nil { 86 panic(err) 87 } 88 } 89 90 func main() { 91 opts := &cli.Options{} 92 var parser = flags.NewParser(opts, flags.Default) 93 _, err := parser.Parse() 94 if err != nil { 95 panic(err) 96 } 97 settings, err := cli.LoadSettings(opts) 98 if err != nil { 99 panic(err) 100 } 101 uic := &uiClient{ 102 client: &http.Client{}, 103 user: settings.User, 104 key: settings.APIKey, 105 uiRoot: settings.UIServerHost, 106 } 107 108 // fetch list of all projects 109 resp := uic.get("projects") 110 pList := struct { 111 Projects []string `json:"projects"` 112 }{} 113 mustDecodeJSON(resp.Body, &pList) 114 115 for _, p := range pList.Projects { 116 fetchAndWriteConfig(uic, p) 117 } 118 }