You've already forked woodpecker
							
							
				mirror of
				https://github.com/woodpecker-ci/woodpecker.git
				synced 2025-10-30 23:27:39 +02:00 
			
		
		
		
	Improve status updates (#561)
- link to specific proc (only general build before) - set status for all procs (before: only for the whole build on some SCMs) - set status after restart - set status to pending after waiting for approval - make status of gitlab, gitea & github equal - dedupe status update code - dedupe `PostBuild` code close #410, close #297, close #459, close #521
This commit is contained in:
		| @@ -313,98 +313,28 @@ func PostApproval(c *gin.Context) { | ||||
| 		yamls = append(yamls, &remote.FileMeta{Data: y.Data, Name: y.Name}) | ||||
| 	} | ||||
|  | ||||
| 	build, err = startBuild(c, _store, build, user, repo, yamls) | ||||
| 	build, buildItems, err := createBuildItems(c, _store, build, user, repo, yamls, nil) | ||||
| 	if err != nil { | ||||
| 		c.String(http.StatusInternalServerError, fmt.Sprintf("startBuild: %v", err)) | ||||
| 	} | ||||
| 	c.JSON(200, build) | ||||
| } | ||||
|  | ||||
| func startBuild(ctx context.Context, store store.Store, build *model.Build, user *model.User, repo *model.Repo, yamls []*remote.FileMeta) (*model.Build, error) { | ||||
| 	netrc, err := server.Config.Services.Remote.Netrc(user, repo) | ||||
| 	if err != nil { | ||||
| 		msg := "Failed to generate netrc file" | ||||
| 		msg := fmt.Sprintf("failure to createBuildItems for %s", repo.FullName) | ||||
| 		log.Error().Err(err).Msg(msg) | ||||
| 		return nil, fmt.Errorf("%s: %v", msg, err) | ||||
| 		c.String(http.StatusInternalServerError, msg) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// get the previous build so that we can send status change notifications | ||||
| 	last, err := store.GetBuildLastBefore(repo, build.Branch, build.ID) | ||||
| 	if err != nil && !errors.Is(err, sql.ErrNoRows) { | ||||
| 		log.Error().Err(err).Str("repo", repo.FullName).Msgf("Error getting last build before build number '%d'", build.Number) | ||||
| 	} | ||||
|  | ||||
| 	secs, err := server.Config.Services.Secrets.SecretListBuild(repo, build) | ||||
| 	build, err = startBuild(c, _store, build, user, repo, buildItems) | ||||
| 	if err != nil { | ||||
| 		log.Error().Err(err).Msgf("Error getting secrets for %s#%d", repo.FullName, build.Number) | ||||
| 		msg := fmt.Sprintf("failure to start build for %s", repo.FullName) | ||||
| 		log.Error().Err(err).Msg(msg) | ||||
| 		c.String(http.StatusInternalServerError, msg) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	regs, err := server.Config.Services.Registries.RegistryList(repo) | ||||
| 	if err != nil { | ||||
| 		log.Error().Err(err).Msgf("Error getting registry credentials for %s#%d", repo.FullName, build.Number) | ||||
| 	} | ||||
|  | ||||
| 	envs := map[string]string{} | ||||
| 	if server.Config.Services.Environ != nil { | ||||
| 		globals, _ := server.Config.Services.Environ.EnvironList(repo) | ||||
| 		for _, global := range globals { | ||||
| 			envs[global.Name] = global.Value | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	b := shared.ProcBuilder{ | ||||
| 		Repo:  repo, | ||||
| 		Curr:  build, | ||||
| 		Last:  last, | ||||
| 		Netrc: netrc, | ||||
| 		Secs:  secs, | ||||
| 		Regs:  regs, | ||||
| 		Envs:  envs, | ||||
| 		Link:  server.Config.Server.Host, | ||||
| 		Yamls: yamls, | ||||
| 	} | ||||
| 	buildItems, err := b.Build() | ||||
| 	if err != nil { | ||||
| 		if _, err := shared.UpdateToStatusError(store, *build, err); err != nil { | ||||
| 			log.Error().Err(err).Msgf("Error setting error status of build for %s#%d", repo.FullName, build.Number) | ||||
| 		} | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	build = shared.SetBuildStepsOnBuild(b.Curr, buildItems) | ||||
|  | ||||
| 	if err := store.ProcCreate(build.Procs); err != nil { | ||||
| 		log.Error().Err(err).Str("repo", repo.FullName).Msgf("error persisting procs for %s#%d", repo.FullName, build.Number) | ||||
| 	} | ||||
|  | ||||
| 	defer func() { | ||||
| 		for _, item := range buildItems { | ||||
| 			uri := fmt.Sprintf("%s/%s/build/%d", server.Config.Server.Host, repo.FullName, build.Number) | ||||
| 			if len(buildItems) > 1 { | ||||
| 				err = server.Config.Services.Remote.Status(ctx, user, repo, build, uri, item.Proc) | ||||
| 			} else { | ||||
| 				err = server.Config.Services.Remote.Status(ctx, user, repo, build, uri, nil) | ||||
| 			} | ||||
| 			if err != nil { | ||||
| 				log.Error().Err(err).Msgf("error setting commit status for %s/%d", repo.FullName, build.Number) | ||||
| 			} | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| 	if err := publishToTopic(ctx, build, repo, model.Enqueued); err != nil { | ||||
| 		log.Error().Err(err).Msg("publishToTopic") | ||||
| 	} | ||||
| 	if err := queueBuild(build, repo, buildItems); err != nil { | ||||
| 		log.Error().Err(err).Msg("queueBuild") | ||||
| 	} | ||||
|  | ||||
| 	return build, nil | ||||
| 	c.JSON(200, build) | ||||
| } | ||||
|  | ||||
| func PostDecline(c *gin.Context) { | ||||
| 	var ( | ||||
| 		_remote = server.Config.Services.Remote | ||||
| 		_store  = store.FromContext(c) | ||||
|  | ||||
| 		_store = store.FromContext(c) | ||||
| 		repo   = session.Repo(c) | ||||
| 		user   = session.User(c) | ||||
| 		num, _ = strconv.ParseInt(c.Params.ByName("number"), 10, 64) | ||||
| @@ -425,10 +355,15 @@ func PostDecline(c *gin.Context) { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	uri := fmt.Sprintf("%s/%s/%d", server.Config.Server.Host, repo.FullName, build.Number) | ||||
| 	err = _remote.Status(c, user, repo, build, uri, nil) | ||||
| 	if err != nil { | ||||
| 		log.Error().Msgf("error setting commit status for %s/%d: %v", repo.FullName, build.Number, err) | ||||
| 	if build.Procs, err = _store.ProcList(build); err != nil { | ||||
| 		log.Error().Err(err).Msg("can not get proc list from store") | ||||
| 	} | ||||
| 	if build.Procs, err = model.Tree(build.Procs); err != nil { | ||||
| 		log.Error().Err(err).Msg("can not build tree from proc list") | ||||
| 	} | ||||
|  | ||||
| 	if err := updateBuildStatus(c, build, repo, user); err != nil { | ||||
| 		log.Error().Err(err).Msg("updateBuildStatus") | ||||
| 	} | ||||
|  | ||||
| 	c.JSON(200, build) | ||||
| @@ -497,12 +432,9 @@ func PostBuild(c *gin.Context) { | ||||
| 		_ = c.AbortWithError(404, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	netrc, err := _remote.Netrc(user, repo) | ||||
| 	if err != nil { | ||||
| 		log.Error().Msgf("failure to generate netrc for %s. %s", repo.FullName, err) | ||||
| 		_ = c.AbortWithError(500, err) | ||||
| 		return | ||||
| 	var yamls []*remote.FileMeta | ||||
| 	for _, y := range configs { | ||||
| 		yamls = append(yamls, &remote.FileMeta{Data: y.Data, Name: y.Name}) | ||||
| 	} | ||||
|  | ||||
| 	build.ID = 0 | ||||
| @@ -516,99 +448,63 @@ func PostBuild(c *gin.Context) { | ||||
| 	build.Deploy = c.DefaultQuery("deploy_to", build.Deploy) | ||||
|  | ||||
| 	if event, ok := c.GetQuery("event"); ok { | ||||
| 		if event := model.WebhookEvent(event); model.ValidateWebhookEvent(event) { | ||||
| 			build.Event = event | ||||
| 		build.Event = model.WebhookEvent(event) | ||||
|  | ||||
| 		if !model.ValidateWebhookEvent(build.Event) { | ||||
| 			msg := fmt.Sprintf("build event '%s' is invalid", event) | ||||
| 			c.String(http.StatusBadRequest, msg) | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	err = _store.CreateBuild(build) | ||||
| 	if err != nil { | ||||
| 		c.String(500, err.Error()) | ||||
| 		msg := fmt.Sprintf("failure to save build for %s", repo.FullName) | ||||
| 		log.Error().Err(err).Msg(msg) | ||||
| 		c.String(http.StatusInternalServerError, msg) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	err = persistBuildConfigs(configs, build.ID) | ||||
| 	if err != nil { | ||||
| 		log.Error().Msgf("failure to persist build config for %s. %s", repo.FullName, err) | ||||
| 		_ = c.AbortWithError(500, err) | ||||
| 		msg := fmt.Sprintf("failure to persist build config for %s.", repo.FullName) | ||||
| 		log.Error().Err(err).Msg(msg) | ||||
| 		c.String(http.StatusInternalServerError, msg) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// Read query string parameters into buildParams, exclude reserved params | ||||
| 	var buildParams = map[string]string{} | ||||
| 	var envs = map[string]string{} | ||||
| 	for key, val := range c.Request.URL.Query() { | ||||
| 		switch key { | ||||
| 		// Skip some options of the endpoint | ||||
| 		case "fork", "event", "deploy_to": | ||||
| 			continue | ||||
| 		default: | ||||
| 			// We only accept string literals, because build parameters will be | ||||
| 			// injected as environment variables | ||||
| 			buildParams[key] = val[0] | ||||
| 			// TODO: sanitize the value | ||||
| 			envs[key] = val[0] | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// get the previous build so that we can send | ||||
| 	// on status change notifications | ||||
| 	last, _ := _store.GetBuildLastBefore(repo, build.Branch, build.ID) | ||||
| 	secs, err := server.Config.Services.Secrets.SecretListBuild(repo, build) | ||||
| 	build, buildItems, err := createBuildItems(c, _store, build, user, repo, yamls, envs) | ||||
| 	if err != nil { | ||||
| 		log.Debug().Msgf("Error getting secrets for %s#%d. %s", repo.FullName, build.Number, err) | ||||
| 	} | ||||
| 	regs, err := server.Config.Services.Registries.RegistryList(repo) | ||||
| 	if err != nil { | ||||
| 		log.Debug().Msgf("Error getting registry credentials for %s#%d. %s", repo.FullName, build.Number, err) | ||||
| 	} | ||||
| 	if server.Config.Services.Environ != nil { | ||||
| 		globals, _ := server.Config.Services.Environ.EnvironList(repo) | ||||
| 		for _, global := range globals { | ||||
| 			buildParams[global.Name] = global.Value | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	var yamls []*remote.FileMeta | ||||
| 	for _, y := range configs { | ||||
| 		yamls = append(yamls, &remote.FileMeta{Data: y.Data, Name: y.Name}) | ||||
| 	} | ||||
|  | ||||
| 	b := shared.ProcBuilder{ | ||||
| 		Repo:  repo, | ||||
| 		Curr:  build, | ||||
| 		Last:  last, | ||||
| 		Netrc: netrc, | ||||
| 		Secs:  secs, | ||||
| 		Regs:  regs, | ||||
| 		Link:  server.Config.Server.Host, | ||||
| 		Yamls: yamls, | ||||
| 		Envs:  buildParams, | ||||
| 	} | ||||
| 	buildItems, err := b.Build() | ||||
| 	if err != nil { | ||||
| 		build.Status = model.StatusError | ||||
| 		build.Started = time.Now().Unix() | ||||
| 		build.Finished = build.Started | ||||
| 		build.Error = err.Error() | ||||
| 		c.JSON(500, build) | ||||
| 		msg := fmt.Sprintf("failure to createBuildItems for %s", repo.FullName) | ||||
| 		log.Error().Err(err).Msg(msg) | ||||
| 		c.String(http.StatusInternalServerError, msg) | ||||
| 		return | ||||
| 	} | ||||
| 	build = shared.SetBuildStepsOnBuild(b.Curr, buildItems) | ||||
|  | ||||
| 	err = _store.ProcCreate(build.Procs) | ||||
| 	build, err = startBuild(c, _store, build, user, repo, buildItems) | ||||
| 	if err != nil { | ||||
| 		log.Error().Msgf("cannot restart %s#%d: %s", repo.FullName, build.Number, err) | ||||
| 		build.Status = model.StatusError | ||||
| 		build.Started = time.Now().Unix() | ||||
| 		build.Finished = build.Started | ||||
| 		build.Error = err.Error() | ||||
| 		c.JSON(500, build) | ||||
| 		msg := fmt.Sprintf("failure to start build for %s", repo.FullName) | ||||
| 		log.Error().Err(err).Msg(msg) | ||||
| 		c.String(http.StatusInternalServerError, msg) | ||||
| 		return | ||||
| 	} | ||||
| 	c.JSON(202, build) | ||||
|  | ||||
| 	if err := publishToTopic(c, build, repo, model.Enqueued); err != nil { | ||||
| 		log.Error().Err(err).Msg("publishToTopic") | ||||
| 	} | ||||
| 	if err := queueBuild(build, repo, buildItems); err != nil { | ||||
| 		log.Error().Err(err).Msg("queueBuild") | ||||
| 	} | ||||
| 	c.JSON(200, build) | ||||
| } | ||||
|  | ||||
| func DeleteBuildLogs(c *gin.Context) { | ||||
| @@ -652,6 +548,101 @@ func DeleteBuildLogs(c *gin.Context) { | ||||
| 	c.String(204, "") | ||||
| } | ||||
|  | ||||
| func createBuildItems(ctx context.Context, store store.Store, build *model.Build, user *model.User, repo *model.Repo, yamls []*remote.FileMeta, envs map[string]string) (*model.Build, []*shared.BuildItem, error) { | ||||
| 	netrc, err := server.Config.Services.Remote.Netrc(user, repo) | ||||
| 	if err != nil { | ||||
| 		log.Error().Err(err).Msg("Failed to generate netrc file") | ||||
| 	} | ||||
|  | ||||
| 	// get the previous build so that we can send status change notifications | ||||
| 	last, err := store.GetBuildLastBefore(repo, build.Branch, build.ID) | ||||
| 	if err != nil && !errors.Is(err, sql.ErrNoRows) { | ||||
| 		log.Error().Err(err).Str("repo", repo.FullName).Msgf("Error getting last build before build number '%d'", build.Number) | ||||
| 	} | ||||
|  | ||||
| 	secs, err := server.Config.Services.Secrets.SecretListBuild(repo, build) | ||||
| 	if err != nil { | ||||
| 		log.Error().Err(err).Msgf("Error getting secrets for %s#%d", repo.FullName, build.Number) | ||||
| 	} | ||||
|  | ||||
| 	regs, err := server.Config.Services.Registries.RegistryList(repo) | ||||
| 	if err != nil { | ||||
| 		log.Error().Err(err).Msgf("Error getting registry credentials for %s#%d", repo.FullName, build.Number) | ||||
| 	} | ||||
|  | ||||
| 	if envs == nil { | ||||
| 		envs = map[string]string{} | ||||
| 	} | ||||
| 	if server.Config.Services.Environ != nil { | ||||
| 		globals, _ := server.Config.Services.Environ.EnvironList(repo) | ||||
| 		for _, global := range globals { | ||||
| 			envs[global.Name] = global.Value | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	b := shared.ProcBuilder{ | ||||
| 		Repo:  repo, | ||||
| 		Curr:  build, | ||||
| 		Last:  last, | ||||
| 		Netrc: netrc, | ||||
| 		Secs:  secs, | ||||
| 		Regs:  regs, | ||||
| 		Envs:  envs, | ||||
| 		Link:  server.Config.Server.Host, | ||||
| 		Yamls: yamls, | ||||
| 	} | ||||
| 	buildItems, err := b.Build() | ||||
| 	if err != nil { | ||||
| 		if _, err := shared.UpdateToStatusError(store, *build, err); err != nil { | ||||
| 			log.Error().Err(err).Msgf("Error setting error status of build for %s#%d", repo.FullName, build.Number) | ||||
| 		} | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | ||||
| 	build = shared.SetBuildStepsOnBuild(b.Curr, buildItems) | ||||
|  | ||||
| 	return build, buildItems, nil | ||||
| } | ||||
|  | ||||
| func startBuild(ctx context.Context, store store.Store, build *model.Build, user *model.User, repo *model.Repo, buildItems []*shared.BuildItem) (*model.Build, error) { | ||||
| 	if err := store.ProcCreate(build.Procs); err != nil { | ||||
| 		log.Error().Err(err).Str("repo", repo.FullName).Msgf("error persisting procs for %s#%d", repo.FullName, build.Number) | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	if err := publishToTopic(ctx, build, repo, model.Enqueued); err != nil { | ||||
| 		log.Error().Err(err).Msg("publishToTopic") | ||||
| 	} | ||||
|  | ||||
| 	if err := queueBuild(build, repo, buildItems); err != nil { | ||||
| 		log.Error().Err(err).Msg("queueBuild") | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	if err := updateBuildStatus(ctx, build, repo, user); err != nil { | ||||
| 		log.Error().Err(err).Msg("updateBuildStatus") | ||||
| 	} | ||||
|  | ||||
| 	return build, nil | ||||
| } | ||||
|  | ||||
| func updateBuildStatus(ctx context.Context, build *model.Build, repo *model.Repo, user *model.User) error { | ||||
| 	for _, proc := range build.Procs { | ||||
| 		// skip child procs | ||||
| 		if !proc.IsParent() { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		err := server.Config.Services.Remote.Status(ctx, user, repo, build, proc) | ||||
| 		if err != nil { | ||||
| 			log.Error().Err(err).Msgf("error setting commit status for %s/%d", repo.FullName, build.Number) | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func persistBuildConfigs(configs []*model.Config, buildID int64) error { | ||||
| 	for _, conf := range configs { | ||||
| 		buildConfig := &model.BuildConfig{ | ||||
|   | ||||
| @@ -219,7 +219,7 @@ func PostHook(c *gin.Context) { | ||||
|  | ||||
| 	err = _store.CreateBuild(build, build.Procs...) | ||||
| 	if err != nil { | ||||
| 		msg := fmt.Sprintf("failure to save commit for %s", repo.FullName) | ||||
| 		msg := fmt.Sprintf("failure to save build for %s", repo.FullName) | ||||
| 		log.Error().Err(err).Msg(msg) | ||||
| 		c.String(http.StatusInternalServerError, msg) | ||||
| 		return | ||||
| @@ -236,16 +236,28 @@ func PostHook(c *gin.Context) { | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	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 | ||||
| 	} | ||||
|  | ||||
| 	if build.Status == model.StatusBlocked { | ||||
| 		if err := publishToTopic(c, build, repo, model.Enqueued); err != nil { | ||||
| 			log.Error().Err(err).Msg("publishToTopic") | ||||
| 		} | ||||
|  | ||||
| 		if err := updateBuildStatus(c, build, repo, repoUser); err != nil { | ||||
| 			log.Error().Err(err).Msg("updateBuildStatus") | ||||
| 		} | ||||
|  | ||||
| 		c.JSON(http.StatusOK, build) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	build, err = startBuild(c, _store, build, repoUser, repo, remoteYamlConfigs) | ||||
| 	build, err = startBuild(c, _store, build, repoUser, repo, buildItems) | ||||
| 	if err != nil { | ||||
| 		msg := fmt.Sprintf("failure to start build for %s", repo.FullName) | ||||
| 		log.Error().Err(err).Msg(msg) | ||||
|   | ||||
| @@ -345,15 +345,9 @@ func (s *RPC) Done(c context.Context, id string, state rpc.State) error { | ||||
| 		if build, err = shared.UpdateStatusToDone(s.store, *build, buildStatus(procs), proc.Stopped); err != nil { | ||||
| 			log.Error().Err(err).Msgf("error: done: cannot update build_id %d final state", build.ID) | ||||
| 		} | ||||
|  | ||||
| 		if !isMultiPipeline(procs) { | ||||
| 			s.updateRemoteStatus(c, repo, build, nil) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if isMultiPipeline(procs) { | ||||
| 		s.updateRemoteStatus(c, repo, build, proc) | ||||
| 	} | ||||
| 	s.updateRemoteStatus(c, repo, build, proc) | ||||
|  | ||||
| 	if err := s.logger.Close(c, id); err != nil { | ||||
| 		log.Error().Err(err).Msgf("done: cannot close build_id %d logger", proc.ID) | ||||
| @@ -431,21 +425,27 @@ func buildStatus(procs []*model.Proc) model.StatusValue { | ||||
|  | ||||
| func (s *RPC) updateRemoteStatus(ctx context.Context, repo *model.Repo, build *model.Build, proc *model.Proc) { | ||||
| 	user, err := s.store.GetUser(repo.UserID) | ||||
| 	if err == nil { | ||||
| 		if refresher, ok := s.remote.(remote.Refresher); ok { | ||||
| 			ok, err := refresher.Refresh(ctx, user) | ||||
| 			if err != nil { | ||||
| 				log.Error().Err(err).Msgf("grpc: refresh oauth token of user '%s' failed", user.Login) | ||||
| 			} else if ok { | ||||
| 				if err := s.store.UpdateUser(user); err != nil { | ||||
| 					log.Error().Err(err).Msg("fail to save user to store after refresh oauth token") | ||||
| 				} | ||||
| 	if err != nil { | ||||
| 		log.Error().Err(err).Msgf("can not get user with id '%d'", repo.UserID) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if refresher, ok := s.remote.(remote.Refresher); ok { | ||||
| 		ok, err := refresher.Refresh(ctx, user) | ||||
| 		if err != nil { | ||||
| 			log.Error().Err(err).Msgf("grpc: refresh oauth token of user '%s' failed", user.Login) | ||||
| 		} else if ok { | ||||
| 			if err := s.store.UpdateUser(user); err != nil { | ||||
| 				log.Error().Err(err).Msg("fail to save user to store after refresh oauth token") | ||||
| 			} | ||||
| 		} | ||||
| 		uri := fmt.Sprintf("%s/%s/%d", server.Config.Server.Host, repo.FullName, build.Number) | ||||
| 		err = s.remote.Status(ctx, user, repo, build, uri, proc) | ||||
| 	} | ||||
|  | ||||
| 	// only do status updates for parent procs | ||||
| 	if proc != nil && proc.IsParent() { | ||||
| 		err = s.remote.Status(ctx, user, repo, build, proc) | ||||
| 		if err != nil { | ||||
| 			log.Error().Msgf("error setting commit status for %s/%d: %v", repo.FullName, build.Number, err) | ||||
| 			log.Error().Err(err).Msgf("error setting commit status for %s/%d", repo.FullName, build.Number) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -63,6 +63,11 @@ func (p *Proc) Failing() bool { | ||||
| 	return p.State == StatusError || p.State == StatusKilled || p.State == StatusFailure | ||||
| } | ||||
|  | ||||
| // IsParent returns true if the process is a parent process. | ||||
| func (p *Proc) IsParent() bool { | ||||
| 	return p.PPID == 0 | ||||
| } | ||||
|  | ||||
| // Tree creates a process tree from a flat process list. | ||||
| func Tree(procs []*Proc) ([]*Proc, error) { | ||||
| 	var nodes []*Proc | ||||
|   | ||||
| @@ -26,6 +26,7 @@ import ( | ||||
| 	"github.com/woodpecker-ci/woodpecker/server/model" | ||||
| 	"github.com/woodpecker-ci/woodpecker/server/remote" | ||||
| 	"github.com/woodpecker-ci/woodpecker/server/remote/bitbucket/internal" | ||||
| 	"github.com/woodpecker-ci/woodpecker/server/remote/common" | ||||
| ) | ||||
|  | ||||
| // Bitbucket cloud endpoints. | ||||
| @@ -221,14 +222,14 @@ func (c *config) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model | ||||
| } | ||||
|  | ||||
| // Status creates a build status for the Bitbucket commit. | ||||
| func (c *config) Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, link string, proc *model.Proc) error { | ||||
| func (c *config) Status(ctx context.Context, user *model.User, repo *model.Repo, build *model.Build, proc *model.Proc) error { | ||||
| 	status := internal.BuildStatus{ | ||||
| 		State: convertStatus(b.Status), | ||||
| 		Desc:  convertDesc(b.Status), | ||||
| 		State: convertStatus(build.Status), | ||||
| 		Desc:  common.GetBuildStatusDescription(build.Status), | ||||
| 		Key:   "Woodpecker", | ||||
| 		URL:   link, | ||||
| 		URL:   common.GetBuildStatusLink(repo, build, nil), | ||||
| 	} | ||||
| 	return c.newClient(ctx, u).CreateStatus(r.Owner, r.Name, b.Commit, &status) | ||||
| 	return c.newClient(ctx, user).CreateStatus(repo.Owner, repo.Name, build.Commit, &status) | ||||
| } | ||||
|  | ||||
| // Activate activates the repository by registering repository push hooks with | ||||
|   | ||||
| @@ -254,7 +254,7 @@ func Test_bitbucket(t *testing.T) { | ||||
| 		}) | ||||
|  | ||||
| 		g.It("Should update the status", func() { | ||||
| 			err := c.Status(ctx, fakeUser, fakeRepo, fakeBuild, "http://127.0.0.1", nil) | ||||
| 			err := c.Status(ctx, fakeUser, fakeRepo, fakeBuild, fakeProc) | ||||
| 			g.Assert(err).IsNil() | ||||
| 		}) | ||||
|  | ||||
| @@ -352,4 +352,9 @@ var ( | ||||
| 	fakeBuild = &model.Build{ | ||||
| 		Commit: "9ecad50", | ||||
| 	} | ||||
|  | ||||
| 	fakeProc = &model.Proc{ | ||||
| 		Name:  "test", | ||||
| 		State: model.StatusSuccess, | ||||
| 	} | ||||
| ) | ||||
|   | ||||
| @@ -32,15 +32,6 @@ const ( | ||||
| 	statusFailure = "FAILED" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	descPending  = "this build is pending" | ||||
| 	descSuccess  = "the build was successful" | ||||
| 	descFailure  = "the build failed" | ||||
| 	descBlocked  = "the build requires approval" | ||||
| 	descDeclined = "the build was rejected" | ||||
| 	descError    = "oops, something went wrong" | ||||
| ) | ||||
|  | ||||
| // convertStatus is a helper function used to convert a Woodpecker status to a | ||||
| // Bitbucket commit status. | ||||
| func convertStatus(status model.StatusValue) string { | ||||
| @@ -54,25 +45,6 @@ func convertStatus(status model.StatusValue) string { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // convertDesc is a helper function used to convert a Woodpecker status to a | ||||
| // Bitbucket status description. | ||||
| func convertDesc(status model.StatusValue) string { | ||||
| 	switch status { | ||||
| 	case model.StatusPending, model.StatusRunning: | ||||
| 		return descPending | ||||
| 	case model.StatusSuccess: | ||||
| 		return descSuccess | ||||
| 	case model.StatusFailure: | ||||
| 		return descFailure | ||||
| 	case model.StatusBlocked: | ||||
| 		return descBlocked | ||||
| 	case model.StatusDeclined: | ||||
| 		return descDeclined | ||||
| 	default: | ||||
| 		return descError | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // convertRepo is a helper function used to convert a Bitbucket repository | ||||
| // structure to the common Woodpecker repository structure. | ||||
| func convertRepo(from *internal.Repo) *model.Repo { | ||||
|   | ||||
| @@ -43,24 +43,6 @@ func Test_helper(t *testing.T) { | ||||
| 			g.Assert(convertStatus(model.StatusError)).Equal(statusFailure) | ||||
| 		}) | ||||
|  | ||||
| 		g.It("should convert passing desc", func() { | ||||
| 			g.Assert(convertDesc(model.StatusSuccess)).Equal(descSuccess) | ||||
| 		}) | ||||
|  | ||||
| 		g.It("should convert pending desc", func() { | ||||
| 			g.Assert(convertDesc(model.StatusPending)).Equal(descPending) | ||||
| 			g.Assert(convertDesc(model.StatusRunning)).Equal(descPending) | ||||
| 		}) | ||||
|  | ||||
| 		g.It("should convert failing desc", func() { | ||||
| 			g.Assert(convertDesc(model.StatusFailure)).Equal(descFailure) | ||||
| 		}) | ||||
|  | ||||
| 		g.It("should convert error desc", func() { | ||||
| 			g.Assert(convertDesc(model.StatusKilled)).Equal(descError) | ||||
| 			g.Assert(convertDesc(model.StatusError)).Equal(descError) | ||||
| 		}) | ||||
|  | ||||
| 		g.It("should convert repository", func() { | ||||
| 			from := &internal.Repo{ | ||||
| 				FullName:  "octocat/hello-world", | ||||
|   | ||||
| @@ -34,6 +34,7 @@ import ( | ||||
| 	"github.com/woodpecker-ci/woodpecker/server/model" | ||||
| 	"github.com/woodpecker-ci/woodpecker/server/remote" | ||||
| 	"github.com/woodpecker-ci/woodpecker/server/remote/bitbucketserver/internal" | ||||
| 	"github.com/woodpecker-ci/woodpecker/server/remote/common" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| @@ -185,18 +186,18 @@ func (c *Config) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model | ||||
| } | ||||
|  | ||||
| // Status is not supported by the bitbucketserver driver. | ||||
| func (c *Config) Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, link string, proc *model.Proc) error { | ||||
| func (c *Config) Status(ctx context.Context, user *model.User, repo *model.Repo, build *model.Build, proc *model.Proc) error { | ||||
| 	status := internal.BuildStatus{ | ||||
| 		State: convertStatus(b.Status), | ||||
| 		Desc:  convertDesc(b.Status), | ||||
| 		Name:  fmt.Sprintf("Woodpecker #%d - %s", b.Number, b.Branch), | ||||
| 		State: convertStatus(build.Status), | ||||
| 		Desc:  common.GetBuildStatusDescription(build.Status), | ||||
| 		Name:  fmt.Sprintf("Woodpecker #%d - %s", build.Number, build.Branch), | ||||
| 		Key:   "Woodpecker", | ||||
| 		URL:   link, | ||||
| 		URL:   common.GetBuildStatusLink(repo, build, nil), | ||||
| 	} | ||||
|  | ||||
| 	client := internal.NewClientWithToken(ctx, c.URL, c.Consumer, u.Token) | ||||
| 	client := internal.NewClientWithToken(ctx, c.URL, c.Consumer, user.Token) | ||||
|  | ||||
| 	return client.CreateStatus(b.Commit, &status) | ||||
| 	return client.CreateStatus(build.Commit, &status) | ||||
| } | ||||
|  | ||||
| func (c *Config) Netrc(user *model.User, r *model.Repo) (*model.Netrc, error) { | ||||
|   | ||||
| @@ -34,13 +34,6 @@ const ( | ||||
| 	statusFailure = "FAILED" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	descPending = "this build is pending" | ||||
| 	descSuccess = "the build was successful" | ||||
| 	descFailure = "the build failed" | ||||
| 	descError   = "oops, something went wrong" | ||||
| ) | ||||
|  | ||||
| // convertStatus is a helper function used to convert a Woodpecker status to a | ||||
| // Bitbucket commit status. | ||||
| func convertStatus(status model.StatusValue) string { | ||||
| @@ -54,21 +47,6 @@ func convertStatus(status model.StatusValue) string { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // convertDesc is a helper function used to convert a Woodpecker status to a | ||||
| // Bitbucket status description. | ||||
| func convertDesc(status model.StatusValue) string { | ||||
| 	switch status { | ||||
| 	case model.StatusPending, model.StatusRunning: | ||||
| 		return descPending | ||||
| 	case model.StatusSuccess: | ||||
| 		return descSuccess | ||||
| 	case model.StatusFailure: | ||||
| 		return descFailure | ||||
| 	default: | ||||
| 		return descError | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // convertRepo is a helper function used to convert a Bitbucket server repository | ||||
| // structure to the common Woodpecker repository structure. | ||||
| func convertRepo(from *internal.Repo) *model.Repo { | ||||
|   | ||||
| @@ -243,7 +243,7 @@ func (c *Coding) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model | ||||
| } | ||||
|  | ||||
| // Status sends the commit status to the remote system. | ||||
| func (c *Coding) Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, link string, proc *model.Proc) error { | ||||
| func (c *Coding) Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, proc *model.Proc) error { | ||||
| 	// EMPTY: not implemented in Coding OAuth API | ||||
| 	return nil | ||||
| } | ||||
|   | ||||
							
								
								
									
										60
									
								
								server/remote/common/status.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								server/remote/common/status.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| package common | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
|  | ||||
| 	"github.com/woodpecker-ci/woodpecker/server" | ||||
| 	"github.com/woodpecker-ci/woodpecker/server/model" | ||||
| ) | ||||
|  | ||||
| const base = "ci/woodpecker" | ||||
|  | ||||
| func GetBuildStatusContext(repo *model.Repo, build *model.Build, proc *model.Proc) string { | ||||
| 	name := base | ||||
|  | ||||
| 	switch build.Event { | ||||
| 	case model.EventPull: | ||||
| 		name += "/pr" | ||||
| 	default: | ||||
| 		if len(build.Event) > 0 { | ||||
| 			name += "/" + string(build.Event) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if proc != nil { | ||||
| 		name += "/" + proc.Name | ||||
| 	} | ||||
|  | ||||
| 	return name | ||||
| } | ||||
|  | ||||
| // getBuildStatusDescription is a helper function that generates a description | ||||
| // message for the current build status. | ||||
| func GetBuildStatusDescription(status model.StatusValue) string { | ||||
| 	switch status { | ||||
| 	case model.StatusPending: | ||||
| 		return "Pipeline is pending" | ||||
| 	case model.StatusRunning: | ||||
| 		return "Pipeline is running" | ||||
| 	case model.StatusSuccess: | ||||
| 		return "Pipeline was successful" | ||||
| 	case model.StatusFailure, model.StatusError: | ||||
| 		return "Pipeline failed" | ||||
| 	case model.StatusKilled: | ||||
| 		return "Pipeline was canceled" | ||||
| 	case model.StatusBlocked: | ||||
| 		return "Pipeline is pending approval" | ||||
| 	case model.StatusDeclined: | ||||
| 		return "Pipeline was rejected" | ||||
| 	default: | ||||
| 		return "unknown status" | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func GetBuildStatusLink(repo *model.Repo, build *model.Build, proc *model.Proc) string { | ||||
| 	if proc == nil { | ||||
| 		return fmt.Sprintf("%s/%s/build/%d", server.Config.Server.Host, repo.FullName, build.Number) | ||||
| 	} | ||||
|  | ||||
| 	return fmt.Sprintf("%s/%s/build/%d/%d", server.Config.Server.Host, repo.FullName, build.Number, proc.PID) | ||||
| } | ||||
| @@ -33,6 +33,7 @@ import ( | ||||
| 	"github.com/woodpecker-ci/woodpecker/server" | ||||
| 	"github.com/woodpecker-ci/woodpecker/server/model" | ||||
| 	"github.com/woodpecker-ci/woodpecker/server/remote" | ||||
| 	"github.com/woodpecker-ci/woodpecker/server/remote/common" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| @@ -337,27 +338,23 @@ func (c *Gitea) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model. | ||||
| } | ||||
|  | ||||
| // Status is supported by the Gitea driver. | ||||
| func (c *Gitea) Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, link string, proc *model.Proc) error { | ||||
| 	client, err := c.newClientToken(ctx, u.Token) | ||||
| func (c *Gitea) Status(ctx context.Context, user *model.User, repo *model.Repo, build *model.Build, proc *model.Proc) error { | ||||
| 	client, err := c.newClientToken(ctx, user.Token) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	status := getStatus(b.Status) | ||||
| 	desc := getDesc(b.Status) | ||||
|  | ||||
| 	_, _, err = client.CreateStatus( | ||||
| 		r.Owner, | ||||
| 		r.Name, | ||||
| 		b.Commit, | ||||
| 		repo.Owner, | ||||
| 		repo.Name, | ||||
| 		build.Commit, | ||||
| 		gitea.CreateStatusOption{ | ||||
| 			State:       status, | ||||
| 			TargetURL:   link, | ||||
| 			Description: desc, | ||||
| 			Context:     c.Context, | ||||
| 			State:       getStatus(proc.State), | ||||
| 			TargetURL:   common.GetBuildStatusLink(repo, build, proc), | ||||
| 			Description: common.GetBuildStatusDescription(proc.State), | ||||
| 			Context:     common.GetBuildStatusContext(repo, build, proc), | ||||
| 		}, | ||||
| 	) | ||||
|  | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| @@ -460,16 +457,6 @@ func (c *Gitea) newClientToken(ctx context.Context, token string) (*gitea.Client | ||||
| 	return gitea.NewClient(c.URL, gitea.SetToken(token), gitea.SetHTTPClient(httpClient), gitea.SetContext(ctx)) | ||||
| } | ||||
|  | ||||
| const ( | ||||
| 	DescPending  = "the build is pending" | ||||
| 	DescRunning  = "the build is running" | ||||
| 	DescSuccess  = "the build was successful" | ||||
| 	DescFailure  = "the build failed" | ||||
| 	DescCanceled = "the build canceled" | ||||
| 	DescBlocked  = "the build is pending approval" | ||||
| 	DescDeclined = "the build was rejected" | ||||
| ) | ||||
|  | ||||
| // getStatus is a helper function that converts a Woodpecker | ||||
| // status to a Gitea status. | ||||
| func getStatus(status model.StatusValue) gitea.StatusState { | ||||
| @@ -490,26 +477,3 @@ func getStatus(status model.StatusValue) gitea.StatusState { | ||||
| 		return gitea.StatusFailure | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // getDesc is a helper function that generates a description | ||||
| // message for the build based on the status. | ||||
| func getDesc(status model.StatusValue) string { | ||||
| 	switch status { | ||||
| 	case model.StatusPending: | ||||
| 		return DescPending | ||||
| 	case model.StatusRunning: | ||||
| 		return DescRunning | ||||
| 	case model.StatusSuccess: | ||||
| 		return DescSuccess | ||||
| 	case model.StatusFailure, model.StatusError: | ||||
| 		return DescFailure | ||||
| 	case model.StatusKilled: | ||||
| 		return DescCanceled | ||||
| 	case model.StatusBlocked: | ||||
| 		return DescBlocked | ||||
| 	case model.StatusDeclined: | ||||
| 		return DescDeclined | ||||
| 	default: | ||||
| 		return DescFailure | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -151,7 +151,7 @@ func Test_gitea(t *testing.T) { | ||||
| 		}) | ||||
|  | ||||
| 		g.It("Should return nil from send build status", func() { | ||||
| 			err := c.Status(ctx, fakeUser, fakeRepo, fakeBuild, "http://gitea.io", nil) | ||||
| 			err := c.Status(ctx, fakeUser, fakeRepo, fakeBuild, fakeProc) | ||||
| 			g.Assert(err).IsNil() | ||||
| 		}) | ||||
|  | ||||
| @@ -196,4 +196,9 @@ var ( | ||||
| 	fakeBuild = &model.Build{ | ||||
| 		Commit: "9ecad50", | ||||
| 	} | ||||
|  | ||||
| 	fakeProc = &model.Proc{ | ||||
| 		Name:  "test", | ||||
| 		State: model.StatusSuccess, | ||||
| 	} | ||||
| ) | ||||
|   | ||||
| @@ -64,7 +64,7 @@ func parsePushHook(payload io.Reader) (repo *model.Repo, build *model.Build, err | ||||
| 		return nil, nil, nil | ||||
| 	} | ||||
|  | ||||
| 	// is this even needed? | ||||
| 	// TODO is this even needed? | ||||
| 	if push.RefType == refBranch { | ||||
| 		return nil, nil, nil | ||||
| 	} | ||||
|   | ||||
| @@ -31,6 +31,7 @@ import ( | ||||
| 	"github.com/woodpecker-ci/woodpecker/server" | ||||
| 	"github.com/woodpecker-ci/woodpecker/server/model" | ||||
| 	"github.com/woodpecker-ci/woodpecker/server/remote" | ||||
| 	"github.com/woodpecker-ci/woodpecker/server/remote/common" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| @@ -418,66 +419,34 @@ func matchingHooks(hooks []*github.Hook, rawurl string) *github.Hook { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // | ||||
| // TODO(bradrydzewski) refactor below functions | ||||
| // | ||||
| var reDeploy = regexp.MustCompile(`.+/deployments/(\d+)`) | ||||
|  | ||||
| // Status sends the commit status to the remote system. | ||||
| // An example would be the GitHub pull request status. | ||||
| func (c *client) Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, link string, proc *model.Proc) error { | ||||
| 	client := c.newClientToken(ctx, u.Token) | ||||
| 	switch b.Event { | ||||
| 	case "deployment": | ||||
| 		return deploymentStatus(ctx, client, r, b, link) | ||||
| 	default: | ||||
| 		return repoStatus(ctx, client, r, b, link, c.Context, proc) | ||||
| 	} | ||||
| } | ||||
| func (c *client) Status(ctx context.Context, user *model.User, repo *model.Repo, build *model.Build, proc *model.Proc) error { | ||||
| 	client := c.newClientToken(ctx, user.Token) | ||||
|  | ||||
| func repoStatus(c context.Context, client *github.Client, r *model.Repo, b *model.Build, link, ctx string, proc *model.Proc) error { | ||||
| 	switch b.Event { | ||||
| 	case model.EventPull: | ||||
| 		ctx += "/pr" | ||||
| 	default: | ||||
| 		if len(b.Event) > 0 { | ||||
| 			ctx += "/" + string(b.Event) | ||||
| 	if build.Event == model.EventDeploy { | ||||
| 		matches := reDeploy.FindStringSubmatch(build.Link) | ||||
| 		if len(matches) != 2 { | ||||
| 			return nil | ||||
| 		} | ||||
| 		id, _ := strconv.Atoi(matches[1]) | ||||
|  | ||||
| 		_, _, err := client.Repositories.CreateDeploymentStatus(ctx, repo.Owner, repo.Name, int64(id), &github.DeploymentStatusRequest{ | ||||
| 			State:       github.String(convertStatus(build.Status)), | ||||
| 			Description: github.String(common.GetBuildStatusDescription(build.Status)), | ||||
| 			LogURL:      github.String(common.GetBuildStatusLink(repo, build, nil)), | ||||
| 		}) | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	status := github.String(convertStatus(b.Status)) | ||||
| 	desc := github.String(convertDesc(b.Status)) | ||||
|  | ||||
| 	if proc != nil { | ||||
| 		ctx += "/" + proc.Name | ||||
| 		status = github.String(convertStatus(proc.State)) | ||||
| 		desc = github.String(convertDesc(proc.State)) | ||||
| 	} | ||||
|  | ||||
| 	data := github.RepoStatus{ | ||||
| 		Context:     github.String(ctx), | ||||
| 		State:       status, | ||||
| 		Description: desc, | ||||
| 		TargetURL:   github.String(link), | ||||
| 	} | ||||
| 	_, _, err := client.Repositories.CreateStatus(c, r.Owner, r.Name, b.Commit, &data) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| var reDeploy = regexp.MustCompile(`.+/deployments/(\d+)`) | ||||
|  | ||||
| func deploymentStatus(ctx context.Context, client *github.Client, r *model.Repo, b *model.Build, link string) error { | ||||
| 	matches := reDeploy.FindStringSubmatch(b.Link) | ||||
| 	if len(matches) != 2 { | ||||
| 		return nil | ||||
| 	} | ||||
| 	id, _ := strconv.Atoi(matches[1]) | ||||
|  | ||||
| 	data := github.DeploymentStatusRequest{ | ||||
| 		State:       github.String(convertStatus(b.Status)), | ||||
| 		Description: github.String(convertDesc(b.Status)), | ||||
| 		LogURL:      github.String(link), | ||||
| 	} | ||||
| 	_, _, err := client.Repositories.CreateDeploymentStatus(ctx, r.Owner, r.Name, int64(id), &data) | ||||
| 	_, _, err := client.Repositories.CreateStatus(ctx, repo.Owner, repo.Name, build.Commit, &github.RepoStatus{ | ||||
| 		Context:     github.String(common.GetBuildStatusContext(repo, build, proc)), | ||||
| 		State:       github.String(convertStatus(proc.State)), | ||||
| 		Description: github.String(common.GetBuildStatusDescription(proc.State)), | ||||
| 		TargetURL:   github.String(common.GetBuildStatusLink(repo, build, proc)), | ||||
| 	}) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -29,13 +29,13 @@ import ( | ||||
| 	"github.com/woodpecker-ci/woodpecker/server" | ||||
| 	"github.com/woodpecker-ci/woodpecker/server/model" | ||||
| 	"github.com/woodpecker-ci/woodpecker/server/remote" | ||||
| 	"github.com/woodpecker-ci/woodpecker/server/remote/common" | ||||
| 	"github.com/woodpecker-ci/woodpecker/shared/oauth2" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	defaultScope  = "api" | ||||
| 	perPage       = 100 | ||||
| 	statusContext = "ci/drone" | ||||
| 	defaultScope = "api" | ||||
| 	perPage      = 100 | ||||
| ) | ||||
|  | ||||
| // Opts defines configuration options. | ||||
| @@ -347,7 +347,7 @@ func (g *Gitlab) Dir(ctx context.Context, user *model.User, repo *model.Repo, bu | ||||
| } | ||||
|  | ||||
| // Status sends the commit status back to gitlab. | ||||
| func (g *Gitlab) Status(ctx context.Context, user *model.User, repo *model.Repo, build *model.Build, link string, proc *model.Proc) error { | ||||
| func (g *Gitlab) Status(ctx context.Context, user *model.User, repo *model.Repo, build *model.Build, proc *model.Proc) error { | ||||
| 	client, err := newClient(g.URL, user.Token, g.SkipVerify) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| @@ -359,12 +359,11 @@ func (g *Gitlab) Status(ctx context.Context, user *model.User, repo *model.Repo, | ||||
| 	} | ||||
|  | ||||
| 	_, _, err = client.Commits.SetCommitStatus(_repo.ID, build.Commit, &gitlab.SetCommitStatusOptions{ | ||||
| 		Ref:         gitlab.String(strings.ReplaceAll(build.Ref, "refs/heads/", "")), | ||||
| 		State:       getStatus(build.Status), | ||||
| 		Description: gitlab.String(getDesc(build.Status)), | ||||
| 		TargetURL:   &link, | ||||
| 		Name:        nil, | ||||
| 		Context:     gitlab.String(statusContext), | ||||
| 		State:       getStatus(proc.State), | ||||
| 		Description: gitlab.String(common.GetBuildStatusDescription(proc.State)), | ||||
| 		TargetURL:   gitlab.String(common.GetBuildStatusLink(repo, build, proc)), | ||||
| 		Context:     gitlab.String(common.GetBuildStatusContext(repo, build, proc)), | ||||
| 		PipelineID:  gitlab.Int(int(build.Number)), | ||||
| 	}, gitlab.WithContext(ctx)) | ||||
|  | ||||
| 	return err | ||||
|   | ||||
| @@ -20,16 +20,6 @@ import ( | ||||
| 	"github.com/woodpecker-ci/woodpecker/server/model" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	DescPending  = "the build is pending" | ||||
| 	DescRunning  = "the buils is running" | ||||
| 	DescSuccess  = "the build was successful" | ||||
| 	DescFailure  = "the build failed" | ||||
| 	DescCanceled = "the build canceled" | ||||
| 	DescBlocked  = "the build is pending approval" | ||||
| 	DescDeclined = "the build was rejected" | ||||
| ) | ||||
|  | ||||
| // getStatus is a helper that converts a Woodpecker status to a Gitlab status. | ||||
| func getStatus(status model.StatusValue) gitlab.BuildStateValue { | ||||
| 	switch status { | ||||
| @@ -47,26 +37,3 @@ func getStatus(status model.StatusValue) gitlab.BuildStateValue { | ||||
| 		return gitlab.Failed | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // getDesc is a helper function that generates a description | ||||
| // message for the build based on the status. | ||||
| func getDesc(status model.StatusValue) string { | ||||
| 	switch status { | ||||
| 	case model.StatusPending: | ||||
| 		return DescPending | ||||
| 	case model.StatusRunning: | ||||
| 		return DescRunning | ||||
| 	case model.StatusSuccess: | ||||
| 		return DescSuccess | ||||
| 	case model.StatusFailure, model.StatusError: | ||||
| 		return DescFailure | ||||
| 	case model.StatusKilled: | ||||
| 		return DescCanceled | ||||
| 	case model.StatusBlocked: | ||||
| 		return DescBlocked | ||||
| 	case model.StatusDeclined: | ||||
| 		return DescDeclined | ||||
| 	default: | ||||
| 		return DescFailure | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -209,7 +209,7 @@ func (c *client) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model | ||||
| } | ||||
|  | ||||
| // Status is not supported by the Gogs driver. | ||||
| func (c *client) Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, link string, proc *model.Proc) error { | ||||
| func (c *client) Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, proc *model.Proc) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -164,7 +164,7 @@ func Test_gogs(t *testing.T) { | ||||
|  | ||||
| 		g.It("Should return no-op for usupporeted features", func() { | ||||
| 			_, err1 := c.Auth(ctx, "octocat", "4vyW6b49Z") | ||||
| 			err2 := c.Status(ctx, nil, nil, nil, "", nil) | ||||
| 			err2 := c.Status(ctx, nil, nil, nil, nil) | ||||
| 			err3 := c.Deactivate(ctx, nil, nil, "") | ||||
| 			g.Assert(err1).IsNotNil() | ||||
| 			g.Assert(err2).IsNil() | ||||
|   | ||||
| @@ -283,12 +283,12 @@ func (_m *Remote) Repos(ctx context.Context, u *model.User) ([]*model.Repo, erro | ||||
| } | ||||
|  | ||||
| // Status provides a mock function with given fields: ctx, u, r, b, link, proc | ||||
| func (_m *Remote) Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, link string, proc *model.Proc) error { | ||||
| 	ret := _m.Called(ctx, u, r, b, link, proc) | ||||
| func (_m *Remote) Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, proc *model.Proc) error { | ||||
| 	ret := _m.Called(ctx, u, r, b, proc) | ||||
|  | ||||
| 	var r0 error | ||||
| 	if rf, ok := ret.Get(0).(func(context.Context, *model.User, *model.Repo, *model.Build, string, *model.Proc) error); ok { | ||||
| 		r0 = rf(ctx, u, r, b, link, proc) | ||||
| 	if rf, ok := ret.Get(0).(func(context.Context, *model.User, *model.Repo, *model.Build, *model.Proc) error); ok { | ||||
| 		r0 = rf(ctx, u, r, b, proc) | ||||
| 	} else { | ||||
| 		r0 = ret.Error(0) | ||||
| 	} | ||||
|   | ||||
| @@ -57,7 +57,7 @@ type Remote interface { | ||||
|  | ||||
| 	// Status sends the commit status to the remote system. | ||||
| 	// An example would be the GitHub pull request status. | ||||
| 	Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, link string, proc *model.Proc) error | ||||
| 	Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Build, p *model.Proc) error | ||||
|  | ||||
| 	// Netrc returns a .netrc file that can be used to clone | ||||
| 	// private repositories from a remote system. | ||||
|   | ||||
		Reference in New Issue
	
	Block a user