| 
									
										
										
										
											2018-02-19 14:24:10 -08:00
										 |  |  | // Copyright 2018 Drone.IO Inc. | 
					
						
							| 
									
										
										
										
											2021-06-28 19:28:18 +02:00
										 |  |  | // Copyright 2021 Informatyka Boguslawski sp. z o.o. sp.k., http://www.ib.pl/ | 
					
						
							| 
									
										
										
										
											2018-03-21 14:02:17 +01:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2018-02-19 14:24:10 -08:00
										 |  |  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  | // you may not use this file except in compliance with the License. | 
					
						
							|  |  |  | // You may obtain a copy of the License at | 
					
						
							| 
									
										
										
										
											2018-03-21 14:02:17 +01:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2018-02-19 14:24:10 -08:00
										 |  |  | //      http://www.apache.org/licenses/LICENSE-2.0 | 
					
						
							| 
									
										
										
										
											2018-03-21 14:02:17 +01:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2018-02-19 14:24:10 -08:00
										 |  |  | // Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  | // distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  | // See the License for the specific language governing permissions and | 
					
						
							|  |  |  | // limitations under the License. | 
					
						
							| 
									
										
										
										
											2021-06-28 19:28:18 +02:00
										 |  |  | // | 
					
						
							|  |  |  | // This file has been modified by Informatyka Boguslawski sp. z o.o. sp.k. | 
					
						
							| 
									
										
										
										
											2018-02-19 14:24:10 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-22 13:48:01 -05:00
										 |  |  | package api | 
					
						
							| 
									
										
										
										
											2015-04-08 15:43:59 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2017-03-16 18:14:02 +08:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2017-05-05 18:59:37 +02:00
										 |  |  | 	"crypto/sha256" | 
					
						
							| 
									
										
										
										
											2017-03-16 18:14:02 +08:00
										 |  |  | 	"encoding/json" | 
					
						
							| 
									
										
										
										
											2015-09-29 18:21:17 -07:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2017-05-12 15:02:24 +02:00
										 |  |  | 	"math/rand" | 
					
						
							| 
									
										
										
										
											2019-06-28 08:29:57 +02:00
										 |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2017-03-16 18:14:02 +08:00
										 |  |  | 	"regexp" | 
					
						
							| 
									
										
										
										
											2016-09-26 00:39:28 -05:00
										 |  |  | 	"strconv" | 
					
						
							| 
									
										
										
										
											2017-03-16 18:14:02 +08:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2016-01-10 17:19:48 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/gin-gonic/gin" | 
					
						
							| 
									
										
										
										
											2021-10-12 02:25:13 -05:00
										 |  |  | 	"github.com/rs/zerolog/log" | 
					
						
							| 
									
										
										
										
											2017-03-16 18:14:02 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-24 06:18:34 -05:00
										 |  |  | 	"github.com/woodpecker-ci/woodpecker/pipeline/frontend/yaml" | 
					
						
							|  |  |  | 	"github.com/woodpecker-ci/woodpecker/pipeline/rpc" | 
					
						
							| 
									
										
										
										
											2021-09-22 13:48:01 -05:00
										 |  |  | 	"github.com/woodpecker-ci/woodpecker/server" | 
					
						
							| 
									
										
										
										
											2021-10-12 02:25:13 -05:00
										 |  |  | 	"github.com/woodpecker-ci/woodpecker/server/model" | 
					
						
							| 
									
										
										
										
											2021-09-23 15:29:09 -05:00
										 |  |  | 	"github.com/woodpecker-ci/woodpecker/server/pubsub" | 
					
						
							|  |  |  | 	"github.com/woodpecker-ci/woodpecker/server/queue" | 
					
						
							| 
									
										
										
										
											2021-09-23 11:25:51 -05:00
										 |  |  | 	"github.com/woodpecker-ci/woodpecker/server/remote" | 
					
						
							| 
									
										
										
										
											2021-09-22 13:48:01 -05:00
										 |  |  | 	"github.com/woodpecker-ci/woodpecker/server/shared" | 
					
						
							| 
									
										
										
										
											2021-09-23 06:33:59 -05:00
										 |  |  | 	"github.com/woodpecker-ci/woodpecker/server/store" | 
					
						
							| 
									
										
										
										
											2021-10-12 02:25:13 -05:00
										 |  |  | 	"github.com/woodpecker-ci/woodpecker/shared/token" | 
					
						
							| 
									
										
										
										
											2015-04-08 15:43:59 -07:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-16 18:14:02 +08:00
										 |  |  | var skipRe = regexp.MustCompile(`\[(?i:ci *skip|skip *ci)\]`) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-12 15:02:24 +02:00
										 |  |  | func init() { | 
					
						
							|  |  |  | 	rand.Seed(time.Now().UnixNano()) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-16 18:14:02 +08:00
										 |  |  | func GetQueueInfo(c *gin.Context) { | 
					
						
							|  |  |  | 	c.IndentedJSON(200, | 
					
						
							| 
									
										
										
										
											2021-09-22 13:48:01 -05:00
										 |  |  | 		server.Config.Services.Queue.Info(c), | 
					
						
							| 
									
										
										
										
											2017-03-16 18:14:02 +08:00
										 |  |  | 	) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-28 08:29:57 +02:00
										 |  |  | func PauseQueue(c *gin.Context) { | 
					
						
							| 
									
										
										
										
											2021-09-22 13:48:01 -05:00
										 |  |  | 	server.Config.Services.Queue.Pause() | 
					
						
							| 
									
										
										
										
											2019-06-28 08:29:57 +02:00
										 |  |  | 	c.Status(http.StatusOK) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func ResumeQueue(c *gin.Context) { | 
					
						
							| 
									
										
										
										
											2021-09-22 13:48:01 -05:00
										 |  |  | 	server.Config.Services.Queue.Resume() | 
					
						
							| 
									
										
										
										
											2019-06-28 08:29:57 +02:00
										 |  |  | 	c.Status(http.StatusOK) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-28 08:42:06 +02:00
										 |  |  | func BlockTilQueueHasRunningItem(c *gin.Context) { | 
					
						
							|  |  |  | 	for { | 
					
						
							| 
									
										
										
										
											2021-09-22 13:48:01 -05:00
										 |  |  | 		info := server.Config.Services.Queue.Info(c) | 
					
						
							| 
									
										
										
										
											2019-06-28 08:42:06 +02:00
										 |  |  | 		if info.Stats.Running == 0 { | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	c.Status(http.StatusOK) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-08 15:43:59 -07:00
										 |  |  | func PostHook(c *gin.Context) { | 
					
						
							| 
									
										
										
										
											2021-12-01 14:22:06 +01:00
										 |  |  | 	_store := store.FromContext(c) | 
					
						
							| 
									
										
										
										
											2015-04-08 15:43:59 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-17 23:46:59 +01:00
										 |  |  | 	tmpRepo, build, err := server.Config.Services.Remote.Hook(c, c.Request) | 
					
						
							| 
									
										
										
										
											2015-04-08 15:43:59 -07:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-12-18 00:09:09 +01:00
										 |  |  | 		msg := "failure to parse hook" | 
					
						
							|  |  |  | 		log.Debug().Err(err).Msg(msg) | 
					
						
							| 
									
										
										
										
											2021-12-18 14:58:01 +01:00
										 |  |  | 		c.String(http.StatusBadRequest, msg) | 
					
						
							| 
									
										
										
										
											2015-04-08 15:43:59 -07:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-09-29 18:21:17 -07:00
										 |  |  | 	if build == nil { | 
					
						
							| 
									
										
										
										
											2021-12-18 14:58:01 +01:00
										 |  |  | 		msg := "ignoring hook: hook parsing resulted in empty build" | 
					
						
							|  |  |  | 		log.Debug().Msg(msg) | 
					
						
							|  |  |  | 		c.String(http.StatusOK, msg) | 
					
						
							| 
									
										
										
										
											2015-04-08 15:43:59 -07:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-09-27 23:32:08 +02:00
										 |  |  | 	if tmpRepo == nil { | 
					
						
							| 
									
										
										
										
											2021-12-18 14:58:01 +01:00
										 |  |  | 		msg := "failure to ascertain repo from hook" | 
					
						
							|  |  |  | 		log.Debug().Msg(msg) | 
					
						
							|  |  |  | 		c.String(http.StatusBadRequest, msg) | 
					
						
							| 
									
										
										
										
											2015-04-08 15:43:59 -07:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-11 01:44:14 +01:00
										 |  |  | 	// skip the build if any case-insensitive combination of the words "skip" and "ci" | 
					
						
							|  |  |  | 	// wrapped in square brackets appear in the commit message | 
					
						
							| 
									
										
										
										
											2015-12-11 02:12:27 +01:00
										 |  |  | 	skipMatch := skipRe.FindString(build.Message) | 
					
						
							|  |  |  | 	if len(skipMatch) > 0 { | 
					
						
							| 
									
										
										
										
											2021-12-18 00:09:09 +01:00
										 |  |  | 		msg := fmt.Sprintf("ignoring hook: %s found in %s", skipMatch, build.Commit) | 
					
						
							|  |  |  | 		log.Debug().Msg(msg) | 
					
						
							|  |  |  | 		c.String(http.StatusNoContent, msg) | 
					
						
							| 
									
										
										
										
											2015-04-08 15:43:59 -07:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-01 14:22:06 +01:00
										 |  |  | 	repo, err := _store.GetRepoName(tmpRepo.Owner + "/" + tmpRepo.Name) | 
					
						
							| 
									
										
										
										
											2015-04-08 15:43:59 -07:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-12-18 14:58:01 +01:00
										 |  |  | 		msg := fmt.Sprintf("failure to get repo %s from store", tmpRepo.FullName) | 
					
						
							| 
									
										
										
										
											2021-12-18 00:09:09 +01:00
										 |  |  | 		log.Error().Err(err).Msg(msg) | 
					
						
							| 
									
										
										
										
											2021-12-18 14:58:01 +01:00
										 |  |  | 		c.String(http.StatusNotFound, msg) | 
					
						
							| 
									
										
										
										
											2015-04-08 15:43:59 -07:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-07-14 15:58:38 -04:00
										 |  |  | 	if !repo.IsActive { | 
					
						
							| 
									
										
										
										
											2021-12-18 14:58:01 +01:00
										 |  |  | 		msg := fmt.Sprintf("ignoring hook: repo %s is inactive", tmpRepo.FullName) | 
					
						
							|  |  |  | 		log.Debug().Msg(msg) | 
					
						
							|  |  |  | 		c.String(http.StatusNoContent, msg) | 
					
						
							| 
									
										
										
										
											2017-07-14 15:58:38 -04:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-04-08 15:43:59 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-11 01:36:07 -07:00
										 |  |  | 	// get the token and verify the hook is authorized | 
					
						
							| 
									
										
										
										
											2021-12-18 00:09:09 +01:00
										 |  |  | 	parsed, err := token.ParseRequest(c.Request, func(_ *token.Token) (string, error) { | 
					
						
							| 
									
										
										
										
											2015-09-09 14:05:52 -07:00
										 |  |  | 		return repo.Hash, nil | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-12-18 00:09:09 +01:00
										 |  |  | 		msg := fmt.Sprintf("failure to parse token from hook for %s", repo.FullName) | 
					
						
							|  |  |  | 		log.Error().Err(err).Msg(msg) | 
					
						
							| 
									
										
										
										
											2021-12-18 14:58:01 +01:00
										 |  |  | 		c.String(http.StatusBadRequest, msg) | 
					
						
							| 
									
										
										
										
											2015-09-09 14:05:52 -07:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if parsed.Text != repo.FullName { | 
					
						
							| 
									
										
										
										
											2021-12-18 00:09:09 +01:00
										 |  |  | 		msg := fmt.Sprintf("failure to verify token from hook. Expected %s, got %s", repo.FullName, parsed.Text) | 
					
						
							|  |  |  | 		log.Debug().Msg(msg) | 
					
						
							|  |  |  | 		c.String(http.StatusForbidden, msg) | 
					
						
							| 
									
										
										
										
											2015-08-11 01:36:07 -07:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-29 18:21:17 -07:00
										 |  |  | 	if repo.UserID == 0 { | 
					
						
							| 
									
										
										
										
											2021-12-18 00:09:09 +01:00
										 |  |  | 		msg := fmt.Sprintf("ignoring hook. repo %s has no owner.", repo.FullName) | 
					
						
							|  |  |  | 		log.Warn().Msg(msg) | 
					
						
							|  |  |  | 		c.String(http.StatusNoContent, msg) | 
					
						
							| 
									
										
										
										
											2015-04-11 15:46:30 -07:00
										 |  |  | 		return | 
					
						
							| 
									
										
										
										
											2015-09-29 18:21:17 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-18 16:28:35 +02:00
										 |  |  | 	if build.Event == model.EventPull && !repo.AllowPull { | 
					
						
							| 
									
										
										
										
											2021-12-18 00:09:09 +01:00
										 |  |  | 		msg := "ignoring hook: pull requests are disabled for this repo in woodpecker" | 
					
						
							|  |  |  | 		log.Debug().Str("repo", repo.FullName).Msg(msg) | 
					
						
							|  |  |  | 		c.String(http.StatusNoContent, msg) | 
					
						
							| 
									
										
										
										
											2015-04-08 15:43:59 -07:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-18 00:09:09 +01:00
										 |  |  | 	repoUser, err := _store.GetUser(repo.UserID) | 
					
						
							| 
									
										
										
										
											2015-04-08 15:43:59 -07:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-12-18 14:58:01 +01:00
										 |  |  | 		msg := fmt.Sprintf("failure to find repo owner via id '%d'", repo.UserID) | 
					
						
							|  |  |  | 		log.Error().Err(err).Str("repo", repo.FullName).Msg(msg) | 
					
						
							|  |  |  | 		c.String(http.StatusInternalServerError, msg) | 
					
						
							| 
									
										
										
										
											2015-04-08 15:43:59 -07:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-04 17:40:27 -07:00
										 |  |  | 	// if the remote has a refresh token, the current access token | 
					
						
							|  |  |  | 	// may be stale. Therefore, we should refresh prior to dispatching | 
					
						
							| 
									
										
										
										
											2017-04-02 23:13:26 +09:00
										 |  |  | 	// the build. | 
					
						
							| 
									
										
										
										
											2021-12-18 00:09:09 +01:00
										 |  |  | 	if refresher, ok := server.Config.Services.Remote.(remote.Refresher); ok { | 
					
						
							|  |  |  | 		refreshed, err := refresher.Refresh(c, repoUser) | 
					
						
							| 
									
										
										
										
											2021-09-27 23:32:08 +02:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2021-12-18 00:09:09 +01:00
										 |  |  | 			log.Error().Err(err).Msgf("failed to refresh oauth2 token for repoUser: %s", repoUser.Login) | 
					
						
							|  |  |  | 		} else if refreshed { | 
					
						
							|  |  |  | 			if err := _store.UpdateUser(repoUser); err != nil { | 
					
						
							|  |  |  | 				log.Error().Err(err).Msgf("error while updating repoUser: %s", repoUser.Login) | 
					
						
							| 
									
										
										
										
											2021-09-27 23:32:08 +02:00
										 |  |  | 				// move forward | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-10-04 17:40:27 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-01 12:52:02 +02:00
										 |  |  | 	// fetch the build file from the remote | 
					
						
							| 
									
										
										
										
											2022-02-28 10:56:23 +01:00
										 |  |  | 	configFetcher := shared.NewConfigFetcher(server.Config.Services.Remote, server.Config.Services.ConfigService, repoUser, repo, build) | 
					
						
							| 
									
										
										
										
											2021-09-28 12:56:59 +02:00
										 |  |  | 	remoteYamlConfigs, err := configFetcher.Fetch(c) | 
					
						
							| 
									
										
										
										
											2015-04-08 15:43:59 -07:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-12-19 00:23:48 +01:00
										 |  |  | 		msg := fmt.Sprintf("cannot find config '%s' in '%s' with user: '%s'", repo.Config, build.Ref, repoUser.Login) | 
					
						
							| 
									
										
										
										
											2021-12-18 00:09:09 +01:00
										 |  |  | 		log.Debug().Err(err).Str("repo", repo.FullName).Msg(msg) | 
					
						
							| 
									
										
										
										
											2021-12-18 14:58:01 +01:00
										 |  |  | 		c.String(http.StatusNotFound, msg) | 
					
						
							| 
									
										
										
										
											2015-04-08 15:43:59 -07:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-09 09:53:54 +02:00
										 |  |  | 	filtered, err := branchFiltered(build, remoteYamlConfigs) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-12-18 00:09:09 +01:00
										 |  |  | 		msg := "failure to parse yaml from hook" | 
					
						
							|  |  |  | 		log.Debug().Err(err).Str("repo", repo.FullName).Msg(msg) | 
					
						
							| 
									
										
										
										
											2021-12-18 14:58:01 +01:00
										 |  |  | 		c.String(http.StatusBadRequest, msg) | 
					
						
							|  |  |  | 		return | 
					
						
							| 
									
										
										
										
											2019-09-09 09:53:54 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if filtered { | 
					
						
							| 
									
										
										
										
											2021-12-18 00:09:09 +01:00
										 |  |  | 		msg := "ignoring hook: branch does not match restrictions defined in yaml" | 
					
						
							|  |  |  | 		log.Debug().Str("repo", repo.FullName).Msg(msg) | 
					
						
							| 
									
										
										
										
											2021-12-18 14:58:01 +01:00
										 |  |  | 		c.String(http.StatusOK, msg) | 
					
						
							| 
									
										
										
										
											2019-06-19 09:36:54 +02:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-06-04 15:04:18 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-22 13:43:18 +02:00
										 |  |  | 	if zeroSteps(build, remoteYamlConfigs) { | 
					
						
							| 
									
										
										
										
											2021-12-18 00:09:09 +01:00
										 |  |  | 		msg := "ignoring hook: step conditions yield zero runnable steps" | 
					
						
							|  |  |  | 		log.Debug().Str("repo", repo.FullName).Msg(msg) | 
					
						
							| 
									
										
										
										
											2021-12-18 14:58:01 +01:00
										 |  |  | 		c.String(http.StatusOK, msg) | 
					
						
							| 
									
										
										
										
											2019-07-19 10:13:02 +02:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-01 12:59:29 +02:00
										 |  |  | 	// update some build fields | 
					
						
							|  |  |  | 	build.RepoID = repo.ID | 
					
						
							|  |  |  | 	build.Verified = true | 
					
						
							|  |  |  | 	build.Status = model.StatusPending | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-18 00:09:09 +01:00
										 |  |  | 	// TODO(336) extend gated feature with an allow/block List | 
					
						
							| 
									
										
										
										
											2022-01-01 13:17:42 +01:00
										 |  |  | 	if repo.IsGated { | 
					
						
							| 
									
										
										
										
											2019-07-18 14:21:05 +02:00
										 |  |  | 		build.Status = model.StatusBlocked | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-01 14:22:06 +01:00
										 |  |  | 	err = _store.CreateBuild(build, build.Procs...) | 
					
						
							| 
									
										
										
										
											2017-04-11 19:06:45 +02:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-12-28 17:02:49 +01:00
										 |  |  | 		msg := fmt.Sprintf("failure to save build for %s", repo.FullName) | 
					
						
							| 
									
										
										
										
											2021-12-18 14:58:01 +01:00
										 |  |  | 		log.Error().Err(err).Msg(msg) | 
					
						
							|  |  |  | 		c.String(http.StatusInternalServerError, msg) | 
					
						
							| 
									
										
										
										
											2015-04-24 14:25:03 -07:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-11 10:50:50 +02:00
										 |  |  | 	// persist the build config for historical correctness, restarts, etc | 
					
						
							|  |  |  | 	for _, remoteYamlConfig := range remoteYamlConfigs { | 
					
						
							| 
									
										
										
										
											2022-01-05 17:54:44 +01:00
										 |  |  | 		_, err := findOrPersistPipelineConfig(_store, build, remoteYamlConfig) | 
					
						
							| 
									
										
										
										
											2019-06-11 10:50:50 +02:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2021-12-18 14:58:01 +01:00
										 |  |  | 			msg := fmt.Sprintf("failure to find or persist pipeline config for %s", repo.FullName) | 
					
						
							|  |  |  | 			log.Error().Err(err).Msg(msg) | 
					
						
							|  |  |  | 			c.String(http.StatusInternalServerError, msg) | 
					
						
							| 
									
										
										
										
											2019-06-11 10:50:50 +02:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 17:02:49 +01:00
										 |  |  | 	build, buildItems, err := createBuildItems(c, _store, build, repoUser, repo, remoteYamlConfigs, nil) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		msg := fmt.Sprintf("failure to createBuildItems for %s", repo.FullName) | 
					
						
							|  |  |  | 		log.Error().Err(err).Msg(msg) | 
					
						
							|  |  |  | 		c.String(http.StatusInternalServerError, msg) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-11 19:06:45 +02:00
										 |  |  | 	if build.Status == model.StatusBlocked { | 
					
						
							| 
									
										
										
										
											2022-01-09 03:47:31 +01:00
										 |  |  | 		if err := publishToTopic(c, build, repo); err != nil { | 
					
						
							| 
									
										
										
										
											2021-12-19 00:23:48 +01:00
										 |  |  | 			log.Error().Err(err).Msg("publishToTopic") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 17:02:49 +01:00
										 |  |  | 		if err := updateBuildStatus(c, build, repo, repoUser); err != nil { | 
					
						
							|  |  |  | 			log.Error().Err(err).Msg("updateBuildStatus") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-18 14:58:01 +01:00
										 |  |  | 		c.JSON(http.StatusOK, build) | 
					
						
							| 
									
										
										
										
											2017-04-11 19:06:45 +02:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-03-18 19:25:53 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-28 17:02:49 +01:00
										 |  |  | 	build, err = startBuild(c, _store, build, repoUser, repo, buildItems) | 
					
						
							| 
									
										
										
										
											2017-05-19 23:36:08 +02:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-12-18 14:58:01 +01:00
										 |  |  | 		msg := fmt.Sprintf("failure to start build for %s", repo.FullName) | 
					
						
							|  |  |  | 		log.Error().Err(err).Msg(msg) | 
					
						
							|  |  |  | 		c.String(http.StatusInternalServerError, msg) | 
					
						
							|  |  |  | 		return | 
					
						
							| 
									
										
										
										
											2021-11-23 15:36:52 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-12-18 14:58:01 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	c.JSON(http.StatusOK, build) | 
					
						
							| 
									
										
										
										
											2019-06-01 10:08:41 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-27 23:32:08 +02:00
										 |  |  | // TODO: parse yaml once and not for each filter function | 
					
						
							| 
									
										
										
										
											2019-09-09 09:53:54 +02:00
										 |  |  | func branchFiltered(build *model.Build, remoteYamlConfigs []*remote.FileMeta) (bool, error) { | 
					
						
							| 
									
										
										
										
											2021-10-12 02:25:13 -05:00
										 |  |  | 	log.Trace().Msgf("hook.branchFiltered(): build branch: '%s' build event: '%s' config count: %d", build.Branch, build.Event, len(remoteYamlConfigs)) | 
					
						
							| 
									
										
										
										
											2022-01-05 17:54:44 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if build.Event == model.EventTag || build.Event == model.EventDeploy { | 
					
						
							|  |  |  | 		return false, nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-19 09:36:54 +02:00
										 |  |  | 	for _, remoteYamlConfig := range remoteYamlConfigs { | 
					
						
							| 
									
										
										
										
											2022-01-05 17:54:44 +01:00
										 |  |  | 		parsedPipelineConfig, err := yaml.ParseBytes(remoteYamlConfig.Data) | 
					
						
							| 
									
										
										
										
											2019-09-09 09:53:54 +02:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2021-10-12 02:25:13 -05:00
										 |  |  | 			log.Trace().Msgf("parse config '%s': %s", remoteYamlConfig.Name, err) | 
					
						
							| 
									
										
										
										
											2019-09-09 09:53:54 +02:00
										 |  |  | 			return false, err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-10-12 02:25:13 -05:00
										 |  |  | 		log.Trace().Msgf("config '%s': %#v", remoteYamlConfig.Name, parsedPipelineConfig) | 
					
						
							| 
									
										
										
										
											2019-09-09 09:53:54 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-05 17:54:44 +01:00
										 |  |  | 		if parsedPipelineConfig.Branches.Match(build.Branch) { | 
					
						
							| 
									
										
										
										
											2019-09-09 09:53:54 +02:00
										 |  |  | 			return false, nil | 
					
						
							| 
									
										
										
										
											2019-06-19 09:36:54 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-01-17 23:46:59 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-09 09:53:54 +02:00
										 |  |  | 	return true, nil | 
					
						
							| 
									
										
										
										
											2019-06-19 09:36:54 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-22 13:43:18 +02:00
										 |  |  | func zeroSteps(build *model.Build, remoteYamlConfigs []*remote.FileMeta) bool { | 
					
						
							| 
									
										
										
										
											2021-09-22 13:48:01 -05:00
										 |  |  | 	b := shared.ProcBuilder{ | 
					
						
							| 
									
										
										
										
											2019-07-19 10:13:02 +02:00
										 |  |  | 		Repo:  &model.Repo{}, | 
					
						
							| 
									
										
										
										
											2019-07-22 13:43:18 +02:00
										 |  |  | 		Curr:  build, | 
					
						
							| 
									
										
										
										
											2019-07-19 10:13:02 +02:00
										 |  |  | 		Last:  &model.Build{}, | 
					
						
							|  |  |  | 		Netrc: &model.Netrc{}, | 
					
						
							|  |  |  | 		Secs:  []*model.Secret{}, | 
					
						
							|  |  |  | 		Regs:  []*model.Registry{}, | 
					
						
							|  |  |  | 		Link:  "", | 
					
						
							|  |  |  | 		Yamls: remoteYamlConfigs, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	buildItems, err := b.Build() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if len(buildItems) == 0 { | 
					
						
							|  |  |  | 		return true | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return false | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-05 17:54:44 +01:00
										 |  |  | func findOrPersistPipelineConfig(store store.Store, build *model.Build, remoteYamlConfig *remote.FileMeta) (*model.Config, error) { | 
					
						
							| 
									
										
										
										
											2019-06-13 17:38:19 +02:00
										 |  |  | 	sha := shasum(remoteYamlConfig.Data) | 
					
						
							| 
									
										
										
										
											2022-01-05 17:54:44 +01:00
										 |  |  | 	conf, err := store.ConfigFindIdentical(build.RepoID, sha) | 
					
						
							| 
									
										
										
										
											2019-06-01 12:52:02 +02:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		conf = &model.Config{ | 
					
						
							| 
									
										
										
										
											2019-06-11 10:50:50 +02:00
										 |  |  | 			RepoID: build.RepoID, | 
					
						
							| 
									
										
										
										
											2021-11-13 20:18:06 +01:00
										 |  |  | 			Data:   remoteYamlConfig.Data, | 
					
						
							| 
									
										
										
										
											2019-06-01 12:52:02 +02:00
										 |  |  | 			Hash:   sha, | 
					
						
							| 
									
										
										
										
											2021-09-22 13:48:01 -05:00
										 |  |  | 			Name:   shared.SanitizePath(remoteYamlConfig.Name), | 
					
						
							| 
									
										
										
										
											2019-06-01 12:52:02 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-01-05 17:54:44 +01:00
										 |  |  | 		err = store.ConfigCreate(conf) | 
					
						
							| 
									
										
										
										
											2019-06-01 12:52:02 +02:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			// retry in case we receive two hooks at the same time | 
					
						
							| 
									
										
										
										
											2022-01-05 17:54:44 +01:00
										 |  |  | 			conf, err = store.ConfigFindIdentical(build.RepoID, sha) | 
					
						
							| 
									
										
										
										
											2019-06-01 12:52:02 +02:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				return nil, err | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-11 10:50:50 +02:00
										 |  |  | 	buildConfig := &model.BuildConfig{ | 
					
						
							|  |  |  | 		ConfigID: conf.ID, | 
					
						
							|  |  |  | 		BuildID:  build.ID, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-01-05 17:54:44 +01:00
										 |  |  | 	if err := store.BuildConfigCreate(buildConfig); err != nil { | 
					
						
							| 
									
										
										
										
											2019-06-11 10:50:50 +02:00
										 |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-01 12:52:02 +02:00
										 |  |  | 	return conf, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-13 17:38:19 +02:00
										 |  |  | // publishes message to UI clients | 
					
						
							| 
									
										
										
										
											2022-01-09 03:47:31 +01:00
										 |  |  | func publishToTopic(c context.Context, build *model.Build, repo *model.Repo) (err error) { | 
					
						
							| 
									
										
										
										
											2017-03-16 18:14:02 +08:00
										 |  |  | 	message := pubsub.Message{ | 
					
						
							|  |  |  | 		Labels: map[string]string{ | 
					
						
							|  |  |  | 			"repo":    repo.FullName, | 
					
						
							| 
									
										
										
										
											2021-11-22 12:55:13 +01:00
										 |  |  | 			"private": strconv.FormatBool(repo.IsSCMPrivate), | 
					
						
							| 
									
										
										
										
											2017-03-16 18:14:02 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-04-04 18:30:06 +09:00
										 |  |  | 	buildCopy := *build | 
					
						
							| 
									
										
										
										
											2021-12-08 23:36:23 +01:00
										 |  |  | 	if buildCopy.Procs, err = model.Tree(buildCopy.Procs); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-16 18:14:02 +08:00
										 |  |  | 	message.Data, _ = json.Marshal(model.Event{ | 
					
						
							| 
									
										
										
										
											2016-09-26 00:39:28 -05:00
										 |  |  | 		Repo:  *repo, | 
					
						
							| 
									
										
										
										
											2017-04-04 18:30:06 +09:00
										 |  |  | 		Build: buildCopy, | 
					
						
							| 
									
										
										
										
											2017-03-16 18:14:02 +08:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2021-11-23 15:36:52 +01:00
										 |  |  | 	return server.Config.Services.Pubsub.Publish(c, "topic/events", message) | 
					
						
							| 
									
										
										
										
											2019-06-01 10:08:41 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2016-09-26 00:39:28 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-23 15:36:52 +01:00
										 |  |  | func queueBuild(build *model.Build, repo *model.Repo, buildItems []*shared.BuildItem) error { | 
					
						
							| 
									
										
										
										
											2019-06-13 17:38:19 +02:00
										 |  |  | 	var tasks []*queue.Task | 
					
						
							| 
									
										
										
										
											2019-06-01 10:08:41 +02:00
										 |  |  | 	for _, item := range buildItems { | 
					
						
							| 
									
										
										
										
											2019-06-19 09:36:54 +02:00
										 |  |  | 		if item.Proc.State == model.StatusSkipped { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-03-16 18:14:02 +08:00
										 |  |  | 		task := new(queue.Task) | 
					
						
							| 
									
										
										
										
											2017-04-02 23:13:26 +09:00
										 |  |  | 		task.ID = fmt.Sprint(item.Proc.ID) | 
					
						
							| 
									
										
										
										
											2017-03-16 18:14:02 +08:00
										 |  |  | 		task.Labels = map[string]string{} | 
					
						
							|  |  |  | 		for k, v := range item.Labels { | 
					
						
							|  |  |  | 			task.Labels[k] = v | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-09-08 15:28:25 -07:00
										 |  |  | 		task.Labels["platform"] = item.Platform | 
					
						
							| 
									
										
										
										
											2019-06-01 10:08:41 +02:00
										 |  |  | 		task.Labels["repo"] = repo.FullName | 
					
						
							| 
									
										
										
										
											2019-06-13 17:38:19 +02:00
										 |  |  | 		task.Dependencies = taskIds(item.DependsOn, buildItems) | 
					
						
							| 
									
										
										
										
											2019-06-17 09:06:36 +02:00
										 |  |  | 		task.RunOn = item.RunsOn | 
					
						
							| 
									
										
										
										
											2019-07-22 12:43:59 +02:00
										 |  |  | 		task.DepStatus = make(map[string]string) | 
					
						
							| 
									
										
										
										
											2017-03-16 18:14:02 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		task.Data, _ = json.Marshal(rpc.Pipeline{ | 
					
						
							| 
									
										
										
										
											2017-04-02 23:13:26 +09:00
										 |  |  | 			ID:      fmt.Sprint(item.Proc.ID), | 
					
						
							| 
									
										
										
										
											2017-03-16 18:14:02 +08:00
										 |  |  | 			Config:  item.Config, | 
					
						
							| 
									
										
										
										
											2019-06-01 10:08:41 +02:00
										 |  |  | 			Timeout: repo.Timeout, | 
					
						
							| 
									
										
										
										
											2017-03-16 18:14:02 +08:00
										 |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-23 15:36:52 +01:00
										 |  |  | 		if err := server.Config.Services.Logs.Open(context.Background(), task.ID); err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2019-06-13 17:38:19 +02:00
										 |  |  | 		tasks = append(tasks, task) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-11-23 15:36:52 +01:00
										 |  |  | 	return server.Config.Services.Queue.PushAtOnce(context.Background(), tasks) | 
					
						
							| 
									
										
										
										
											2019-06-13 17:38:19 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-24 16:29:26 +02:00
										 |  |  | func taskIds(dependsOn []string, buildItems []*shared.BuildItem) (taskIds []string) { | 
					
						
							| 
									
										
										
										
											2019-06-13 17:38:19 +02:00
										 |  |  | 	for _, dep := range dependsOn { | 
					
						
							|  |  |  | 		for _, buildItem := range buildItems { | 
					
						
							|  |  |  | 			if buildItem.Proc.Name == dep { | 
					
						
							|  |  |  | 				taskIds = append(taskIds, fmt.Sprint(buildItem.Proc.ID)) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-04-18 12:07:01 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-09-24 16:29:26 +02:00
										 |  |  | 	return | 
					
						
							| 
									
										
										
										
											2017-03-05 18:56:08 +11:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2017-03-16 19:00:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-05 18:59:37 +02:00
										 |  |  | func shasum(raw []byte) string { | 
					
						
							|  |  |  | 	sum := sha256.Sum256(raw) | 
					
						
							|  |  |  | 	return fmt.Sprintf("%x", sum) | 
					
						
							|  |  |  | } |