|  | @@ -1,6 +1,9 @@
 | 
	
		
			
			| 1 | 1 |  package webhook
 | 
	
		
			
			| 2 | 2 |  
 | 
	
		
			
			| 3 | 3 |  import (
 | 
	
		
			
			|  | 4 | +	"io/ioutil"
 | 
	
		
			
			|  | 5 | +	"path/filepath"
 | 
	
		
			
			|  | 6 | +
 | 
	
		
			
			| 4 | 7 |  	"config"
 | 
	
		
			
			| 5 | 8 |  	"git"
 | 
	
		
			
			| 6 | 9 |  	"grafana"
 | 
	
	
		
			
			|  | @@ -49,6 +52,13 @@ func Setup(conf *config.Config, client *grafana.Client, delRemoved bool) (err er
 | 
	
		
			
			| 49 | 52 |  func HandlePush(payload interface{}, header webhooks.Header) {
 | 
	
		
			
			| 50 | 53 |  	var err error
 | 
	
		
			
			| 51 | 54 |  
 | 
	
		
			
			|  | 55 | +	var (
 | 
	
		
			
			|  | 56 | +		added    = make([]string, 0)
 | 
	
		
			
			|  | 57 | +		modified = make([]string, 0)
 | 
	
		
			
			|  | 58 | +		removed  = make([]string, 0)
 | 
	
		
			
			|  | 59 | +		contents = make(map[string][]byte)
 | 
	
		
			
			|  | 60 | +	)
 | 
	
		
			
			|  | 61 | +
 | 
	
		
			
			| 52 | 62 |  	// Process the payload using the right structure
 | 
	
		
			
			| 53 | 63 |  	pl := payload.(gitlab.PushEventPayload)
 | 
	
		
			
			| 54 | 64 |  
 | 
	
	
		
			
			|  | @@ -57,25 +67,6 @@ func HandlePush(payload interface{}, header webhooks.Header) {
 | 
	
		
			
			| 57 | 67 |  		return
 | 
	
		
			
			| 58 | 68 |  	}
 | 
	
		
			
			| 59 | 69 |  
 | 
	
		
			
			| 60 |  | -	// Clone or pull the repository
 | 
	
		
			
			| 61 |  | -	if err = repo.Sync(false); err != nil {
 | 
	
		
			
			| 62 |  | -		logrus.WithFields(logrus.Fields{
 | 
	
		
			
			| 63 |  | -			"error":      err,
 | 
	
		
			
			| 64 |  | -			"repo":       cfg.Git.User + "@" + cfg.Git.URL,
 | 
	
		
			
			| 65 |  | -			"clone_path": cfg.Git.ClonePath,
 | 
	
		
			
			| 66 |  | -		}).Error("Failed to synchronise the Git repository with the remote")
 | 
	
		
			
			| 67 |  | -
 | 
	
		
			
			| 68 |  | -		return
 | 
	
		
			
			| 69 |  | -	}
 | 
	
		
			
			| 70 |  | -
 | 
	
		
			
			| 71 |  | -	// Files to push and their contents are stored in a map before being pushed
 | 
	
		
			
			| 72 |  | -	// to the Grafana API. We don't push them in the loop iterating over commits
 | 
	
		
			
			| 73 |  | -	// because, in the case a file is successively updated by two commits pushed
 | 
	
		
			
			| 74 |  | -	// at the same time, it would push the same file several time, which isn't
 | 
	
		
			
			| 75 |  | -	// an optimised behaviour.
 | 
	
		
			
			| 76 |  | -	filesToPush := make(map[string][]byte)
 | 
	
		
			
			| 77 |  | -
 | 
	
		
			
			| 78 |  | -	// Iterate over the commits descriptions from the payload
 | 
	
		
			
			| 79 | 70 |  	for _, commit := range pl.Commits {
 | 
	
		
			
			| 80 | 71 |  		// We don't want to process commits made by the puller
 | 
	
		
			
			| 81 | 72 |  		if commit.Author.Email == cfg.Git.CommitsAuthor.Email {
 | 
	
	
		
			
			|  | @@ -88,56 +79,52 @@ func HandlePush(payload interface{}, header webhooks.Header) {
 | 
	
		
			
			| 88 | 79 |  			continue
 | 
	
		
			
			| 89 | 80 |  		}
 | 
	
		
			
			| 90 | 81 |  
 | 
	
		
			
			| 91 |  | -		// Set all added files to be pushed, except the ones describing a
 | 
	
		
			
			| 92 |  | -		// dashboard which name starts with a the prefix specified in the
 | 
	
		
			
			| 93 |  | -		// configuration file.
 | 
	
		
			
			| 94 | 82 |  		for _, addedFile := range commit.Added {
 | 
	
		
			
			| 95 |  | -			if err = common.PrepareForPush(
 | 
	
		
			
			| 96 |  | -				addedFile, &filesToPush, cfg,
 | 
	
		
			
			| 97 |  | -			); err != nil {
 | 
	
		
			
			| 98 |  | -				logrus.WithFields(logrus.Fields{
 | 
	
		
			
			| 99 |  | -					"error":    err,
 | 
	
		
			
			| 100 |  | -					"filename": addedFile,
 | 
	
		
			
			| 101 |  | -				}).Error("Failed to prepare file for push")
 | 
	
		
			
			| 102 |  | -
 | 
	
		
			
			| 103 |  | -				continue
 | 
	
		
			
			| 104 |  | -			}
 | 
	
		
			
			|  | 83 | +			added = append(added, addedFile)
 | 
	
		
			
			| 105 | 84 |  		}
 | 
	
		
			
			| 106 | 85 |  
 | 
	
		
			
			| 107 |  | -		// Set all modified files to be pushed, except the ones describing a
 | 
	
		
			
			| 108 |  | -		// dashboard which name starts with a the prefix specified in the
 | 
	
		
			
			| 109 |  | -		// configuration file.
 | 
	
		
			
			| 110 | 86 |  		for _, modifiedFile := range commit.Modified {
 | 
	
		
			
			| 111 |  | -			if err = common.PrepareForPush(
 | 
	
		
			
			| 112 |  | -				modifiedFile, &filesToPush, cfg,
 | 
	
		
			
			| 113 |  | -			); err != nil {
 | 
	
		
			
			| 114 |  | -				logrus.WithFields(logrus.Fields{
 | 
	
		
			
			| 115 |  | -					"error":    err,
 | 
	
		
			
			| 116 |  | -					"filename": modifiedFile,
 | 
	
		
			
			| 117 |  | -				}).Error("Failed to prepare file for push")
 | 
	
		
			
			| 118 |  | -
 | 
	
		
			
			| 119 |  | -				continue
 | 
	
		
			
			| 120 |  | -			}
 | 
	
		
			
			|  | 87 | +			modified = append(modified, modifiedFile)
 | 
	
		
			
			| 121 | 88 |  		}
 | 
	
		
			
			| 122 | 89 |  
 | 
	
		
			
			| 123 |  | -		// If a file describing a dashboard gets removed from the Git repository,
 | 
	
		
			
			| 124 |  | -		// delete the corresponding dashboard on Grafana, but only if the user
 | 
	
		
			
			| 125 |  | -		// mentionned they want to do so with the correct command line flag.
 | 
	
		
			
			| 126 |  | -		if deleteRemoved {
 | 
	
		
			
			| 127 |  | -			for _, removedFile := range commit.Removed {
 | 
	
		
			
			| 128 |  | -				if err = common.DeleteDashboard(
 | 
	
		
			
			| 129 |  | -					removedFile, grafanaClient, cfg,
 | 
	
		
			
			| 130 |  | -				); err != nil {
 | 
	
		
			
			| 131 |  | -					logrus.WithFields(logrus.Fields{
 | 
	
		
			
			| 132 |  | -						"error":    err,
 | 
	
		
			
			| 133 |  | -						"filename": removedFile,
 | 
	
		
			
			| 134 |  | -					}).Error("Failed to delete the dashboard")
 | 
	
		
			
			| 135 |  | -				}
 | 
	
		
			
			| 136 |  | -			}
 | 
	
		
			
			|  | 90 | +		for _, removedFile := range commit.Removed {
 | 
	
		
			
			|  | 91 | +			removed = append(removed, removedFile)
 | 
	
		
			
			| 137 | 92 |  		}
 | 
	
		
			
			| 138 | 93 |  	}
 | 
	
		
			
			| 139 | 94 |  
 | 
	
		
			
			| 140 |  | -	common.PushFiles(filesToPush, grafanaClient)
 | 
	
		
			
			|  | 95 | +	if err = getFilesContents(removed, &contents, cfg); err != nil {
 | 
	
		
			
			|  | 96 | +		return
 | 
	
		
			
			|  | 97 | +	}
 | 
	
		
			
			|  | 98 | +
 | 
	
		
			
			|  | 99 | +	// Clone or pull the repository
 | 
	
		
			
			|  | 100 | +	if err = repo.Sync(false); err != nil {
 | 
	
		
			
			|  | 101 | +		logrus.WithFields(logrus.Fields{
 | 
	
		
			
			|  | 102 | +			"error":      err,
 | 
	
		
			
			|  | 103 | +			"repo":       cfg.Git.User + "@" + cfg.Git.URL,
 | 
	
		
			
			|  | 104 | +			"clone_path": cfg.Git.ClonePath,
 | 
	
		
			
			|  | 105 | +		}).Error("Failed to synchronise the Git repository with the remote")
 | 
	
		
			
			|  | 106 | +
 | 
	
		
			
			|  | 107 | +		return
 | 
	
		
			
			|  | 108 | +	}
 | 
	
		
			
			|  | 109 | +
 | 
	
		
			
			|  | 110 | +	if err = getFilesContents(added, &contents, cfg); err != nil {
 | 
	
		
			
			|  | 111 | +		return
 | 
	
		
			
			|  | 112 | +	}
 | 
	
		
			
			|  | 113 | +
 | 
	
		
			
			|  | 114 | +	if err = getFilesContents(modified, &contents, cfg); err != nil {
 | 
	
		
			
			|  | 115 | +		return
 | 
	
		
			
			|  | 116 | +	}
 | 
	
		
			
			|  | 117 | +
 | 
	
		
			
			|  | 118 | +	if err = common.FilterIgnored(&contents, cfg); err != nil {
 | 
	
		
			
			|  | 119 | +		return
 | 
	
		
			
			|  | 120 | +	}
 | 
	
		
			
			|  | 121 | +
 | 
	
		
			
			|  | 122 | +	common.PushFiles(added, contents, grafanaClient)
 | 
	
		
			
			|  | 123 | +	common.PushFiles(modified, contents, grafanaClient)
 | 
	
		
			
			|  | 124 | +
 | 
	
		
			
			|  | 125 | +	if deleteRemoved {
 | 
	
		
			
			|  | 126 | +		common.DeleteDashboards(removed, contents, grafanaClient)
 | 
	
		
			
			|  | 127 | +	}
 | 
	
		
			
			| 141 | 128 |  
 | 
	
		
			
			| 142 | 129 |  	// Grafana will auto-update the version number after we pushed the new
 | 
	
		
			
			| 143 | 130 |  	// dashboards, so we use the puller mechanic to pull the updated numbers and
 | 
	
	
		
			
			|  | @@ -150,3 +137,20 @@ func HandlePush(payload interface{}, header webhooks.Header) {
 | 
	
		
			
			| 150 | 137 |  		}).Error("Call to puller returned an error")
 | 
	
		
			
			| 151 | 138 |  	}
 | 
	
		
			
			| 152 | 139 |  }
 | 
	
		
			
			|  | 140 | +
 | 
	
		
			
			|  | 141 | +func getFilesContents(
 | 
	
		
			
			|  | 142 | +	filenames []string, contents *map[string][]byte, cfg *config.Config,
 | 
	
		
			
			|  | 143 | +) (err error) {
 | 
	
		
			
			|  | 144 | +	for _, filename := range filenames {
 | 
	
		
			
			|  | 145 | +		// Read the file's content
 | 
	
		
			
			|  | 146 | +		filePath := filepath.Join(cfg.Git.ClonePath, filename)
 | 
	
		
			
			|  | 147 | +		fileContent, err := ioutil.ReadFile(filePath)
 | 
	
		
			
			|  | 148 | +		if err != nil {
 | 
	
		
			
			|  | 149 | +			return err
 | 
	
		
			
			|  | 150 | +		}
 | 
	
		
			
			|  | 151 | +
 | 
	
		
			
			|  | 152 | +		(*contents)[filename] = fileContent
 | 
	
		
			
			|  | 153 | +	}
 | 
	
		
			
			|  | 154 | +
 | 
	
		
			
			|  | 155 | +	return
 | 
	
		
			
			|  | 156 | +}
 |