|  | @@ -12,12 +12,16 @@ import (
 | 
	
		
			
			| 12 | 12 |  	gogit "gopkg.in/src-d/go-git.v4"
 | 
	
		
			
			| 13 | 13 |  )
 | 
	
		
			
			| 14 | 14 |  
 | 
	
		
			
			|  | 15 | +// diffVersion represents a dashboard version diff.
 | 
	
		
			
			| 15 | 16 |  type diffVersion struct {
 | 
	
		
			
			| 16 | 17 |  	oldVersion int
 | 
	
		
			
			| 17 | 18 |  	newVersion int
 | 
	
		
			
			| 18 | 19 |  }
 | 
	
		
			
			| 19 | 20 |  
 | 
	
		
			
			| 20 |  | -func Pull(client *grafana.Client) error {
 | 
	
		
			
			|  | 21 | +// PullGrafanaAndCommit pulls all the dashboards from Grafana then commits each
 | 
	
		
			
			|  | 22 | +// of them to Git except for those that have a newer or equal version number
 | 
	
		
			
			|  | 23 | +// already versionned in the repo
 | 
	
		
			
			|  | 24 | +func PullGrafanaAndCommit(client *grafana.Client) error {
 | 
	
		
			
			| 21 | 25 |  	dv := make(map[string]diffVersion)
 | 
	
		
			
			| 22 | 26 |  
 | 
	
		
			
			| 23 | 27 |  	dbVersions, err := getDashboardsVersions()
 | 
	
	
		
			
			|  | @@ -48,11 +52,14 @@ func Pull(client *grafana.Client) error {
 | 
	
		
			
			| 48 | 52 |  
 | 
	
		
			
			| 49 | 53 |  		version, ok := dbVersions[dashboard.Slug]
 | 
	
		
			
			| 50 | 54 |  		if !ok || dashboard.Version > version {
 | 
	
		
			
			| 51 |  | -			if err = addDashboardChangesToRepo(
 | 
	
		
			
			| 52 |  | -				dashboard, version, w, &dv,
 | 
	
		
			
			| 53 |  | -			); err != nil {
 | 
	
		
			
			|  | 55 | +			if err = addDashboardChangesToRepo(dashboard, w); err != nil {
 | 
	
		
			
			| 54 | 56 |  				return err
 | 
	
		
			
			| 55 | 57 |  			}
 | 
	
		
			
			|  | 58 | +
 | 
	
		
			
			|  | 59 | +			dv[dashboard.Slug] = diffVersion{
 | 
	
		
			
			|  | 60 | +				oldVersion: version,
 | 
	
		
			
			|  | 61 | +				newVersion: dashboard.Version,
 | 
	
		
			
			|  | 62 | +			}
 | 
	
		
			
			| 56 | 63 |  		}
 | 
	
		
			
			| 57 | 64 |  	}
 | 
	
		
			
			| 58 | 65 |  
 | 
	
	
		
			
			|  | @@ -74,9 +81,11 @@ func Pull(client *grafana.Client) error {
 | 
	
		
			
			| 74 | 81 |  	return nil
 | 
	
		
			
			| 75 | 82 |  }
 | 
	
		
			
			| 76 | 83 |  
 | 
	
		
			
			|  | 84 | +// addDashboardChangesToRepo writes a dashboard content in a file, then adds the
 | 
	
		
			
			|  | 85 | +// file to the git index so it can be comitted afterwards.
 | 
	
		
			
			|  | 86 | +// Returns an error if there was an issue with either of the steps.
 | 
	
		
			
			| 77 | 87 |  func addDashboardChangesToRepo(
 | 
	
		
			
			| 78 |  | -	dashboard *grafana.Dashboard, oldVersion int, worktree *gogit.Worktree,
 | 
	
		
			
			| 79 |  | -	dv *map[string]diffVersion,
 | 
	
		
			
			|  | 88 | +	dashboard *grafana.Dashboard, worktree *gogit.Worktree,
 | 
	
		
			
			| 80 | 89 |  ) error {
 | 
	
		
			
			| 81 | 90 |  	slugExt := dashboard.Slug + ".json"
 | 
	
		
			
			| 82 | 91 |  	if err := rewriteFile(
 | 
	
	
		
			
			|  | @@ -90,14 +99,17 @@ func addDashboardChangesToRepo(
 | 
	
		
			
			| 90 | 99 |  		return err
 | 
	
		
			
			| 91 | 100 |  	}
 | 
	
		
			
			| 92 | 101 |  
 | 
	
		
			
			| 93 |  | -	(*dv)[dashboard.Slug] = diffVersion{
 | 
	
		
			
			| 94 |  | -		oldVersion: oldVersion,
 | 
	
		
			
			| 95 |  | -		newVersion: dashboard.Version,
 | 
	
		
			
			| 96 |  | -	}
 | 
	
		
			
			| 97 |  | -
 | 
	
		
			
			| 98 | 102 |  	return nil
 | 
	
		
			
			| 99 | 103 |  }
 | 
	
		
			
			| 100 | 104 |  
 | 
	
		
			
			|  | 105 | +// rewriteFile removes a given file and re-creates it with a new content. The
 | 
	
		
			
			|  | 106 | +// content is provided as JSON, and is then indented before being written down.
 | 
	
		
			
			|  | 107 | +// We need the whole "remove then recreate" thing because, if the file already
 | 
	
		
			
			|  | 108 | +// exists, ioutil.WriteFile will append the content to it. However, we want to
 | 
	
		
			
			|  | 109 | +// replace the oldest version with another (so git can diff it), so we re-create
 | 
	
		
			
			|  | 110 | +// the file with the changed content.
 | 
	
		
			
			|  | 111 | +// Returns an error if there was an issue when removing or writing the file, or
 | 
	
		
			
			|  | 112 | +// indenting the JSON content.
 | 
	
		
			
			| 101 | 113 |  func rewriteFile(filename string, content []byte) error {
 | 
	
		
			
			| 102 | 114 |  	if err := os.Remove(filename); err != nil {
 | 
	
		
			
			| 103 | 115 |  		pe, ok := err.(*os.PathError)
 | 
	
	
		
			
			|  | @@ -114,6 +126,10 @@ func rewriteFile(filename string, content []byte) error {
 | 
	
		
			
			| 114 | 126 |  	return ioutil.WriteFile(filename, indentedContent, 0644)
 | 
	
		
			
			| 115 | 127 |  }
 | 
	
		
			
			| 116 | 128 |  
 | 
	
		
			
			|  | 129 | +// indent indents a given JSON content with tabs.
 | 
	
		
			
			|  | 130 | +// We need to indent the content as the Grafana API returns a one-lined JSON
 | 
	
		
			
			|  | 131 | +// string, which isn't great to work with.
 | 
	
		
			
			|  | 132 | +// Returns an error if there was an issue with the process.
 | 
	
		
			
			| 117 | 133 |  func indent(srcJSON []byte) (indentedJSON []byte, err error) {
 | 
	
		
			
			| 118 | 134 |  	buf := bytes.NewBuffer(nil)
 | 
	
		
			
			| 119 | 135 |  	if err = json.Indent(buf, srcJSON, "", "\t"); err != nil {
 |