| 
				
			 | 
			
			
				@@ -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
			 | 
			
			
				+} 
			 |