Fix skipped pipelines model (#2923)

Fixes: https://github.com/woodpecker-ci/woodpecker/issues/2901

---------

Co-authored-by: Lauris BH <lauris@nix.lv>
This commit is contained in:
Robert Kaussow 2023-12-12 21:30:52 +01:00 committed by GitHub
parent 547f5dea35
commit 6de5922408
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 545 additions and 7 deletions

View file

@ -4249,10 +4249,12 @@ const docTemplate = `{
"killed", "killed",
"error", "error",
"blocked", "blocked",
"declined" "declined",
"created"
], ],
"x-enum-comments": { "x-enum-comments": {
"StatusBlocked": "waiting for approval", "StatusBlocked": "waiting for approval",
"StatusCreated": "created / internal use only",
"StatusDeclined": "blocked and declined", "StatusDeclined": "blocked and declined",
"StatusError": "error with the config / while parsing / some other system problem", "StatusError": "error with the config / while parsing / some other system problem",
"StatusFailure": "failed to finish (exit code != 0)", "StatusFailure": "failed to finish (exit code != 0)",
@ -4271,7 +4273,8 @@ const docTemplate = `{
"StatusKilled", "StatusKilled",
"StatusError", "StatusError",
"StatusBlocked", "StatusBlocked",
"StatusDeclined" "StatusDeclined",
"StatusCreated"
] ]
}, },
"Step": { "Step": {

View file

@ -1,4 +1,4 @@
// Code generated by mockery v2.37.1. DO NOT EDIT. // Code generated by mockery v2.38.0. DO NOT EDIT.
package mocks package mocks
@ -23,6 +23,10 @@ type Forge struct {
func (_m *Forge) Activate(ctx context.Context, u *model.User, r *model.Repo, link string) error { func (_m *Forge) Activate(ctx context.Context, u *model.User, r *model.Repo, link string) error {
ret := _m.Called(ctx, u, r, link) ret := _m.Called(ctx, u, r, link)
if len(ret) == 0 {
panic("no return value specified for Activate")
}
var r0 error var r0 error
if rf, ok := ret.Get(0).(func(context.Context, *model.User, *model.Repo, string) error); ok { if rf, ok := ret.Get(0).(func(context.Context, *model.User, *model.Repo, string) error); ok {
r0 = rf(ctx, u, r, link) r0 = rf(ctx, u, r, link)
@ -37,6 +41,10 @@ func (_m *Forge) Activate(ctx context.Context, u *model.User, r *model.Repo, lin
func (_m *Forge) Auth(ctx context.Context, token string, secret string) (string, error) { func (_m *Forge) Auth(ctx context.Context, token string, secret string) (string, error) {
ret := _m.Called(ctx, token, secret) ret := _m.Called(ctx, token, secret)
if len(ret) == 0 {
panic("no return value specified for Auth")
}
var r0 string var r0 string
var r1 error var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string, string) (string, error)); ok { if rf, ok := ret.Get(0).(func(context.Context, string, string) (string, error)); ok {
@ -61,6 +69,10 @@ func (_m *Forge) Auth(ctx context.Context, token string, secret string) (string,
func (_m *Forge) BranchHead(ctx context.Context, u *model.User, r *model.Repo, branch string) (string, error) { func (_m *Forge) BranchHead(ctx context.Context, u *model.User, r *model.Repo, branch string) (string, error) {
ret := _m.Called(ctx, u, r, branch) ret := _m.Called(ctx, u, r, branch)
if len(ret) == 0 {
panic("no return value specified for BranchHead")
}
var r0 string var r0 string
var r1 error var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *model.User, *model.Repo, string) (string, error)); ok { if rf, ok := ret.Get(0).(func(context.Context, *model.User, *model.Repo, string) (string, error)); ok {
@ -85,6 +97,10 @@ func (_m *Forge) BranchHead(ctx context.Context, u *model.User, r *model.Repo, b
func (_m *Forge) Branches(ctx context.Context, u *model.User, r *model.Repo, p *model.ListOptions) ([]string, error) { func (_m *Forge) Branches(ctx context.Context, u *model.User, r *model.Repo, p *model.ListOptions) ([]string, error) {
ret := _m.Called(ctx, u, r, p) ret := _m.Called(ctx, u, r, p)
if len(ret) == 0 {
panic("no return value specified for Branches")
}
var r0 []string var r0 []string
var r1 error var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *model.User, *model.Repo, *model.ListOptions) ([]string, error)); ok { if rf, ok := ret.Get(0).(func(context.Context, *model.User, *model.Repo, *model.ListOptions) ([]string, error)); ok {
@ -111,6 +127,10 @@ func (_m *Forge) Branches(ctx context.Context, u *model.User, r *model.Repo, p *
func (_m *Forge) Deactivate(ctx context.Context, u *model.User, r *model.Repo, link string) error { func (_m *Forge) Deactivate(ctx context.Context, u *model.User, r *model.Repo, link string) error {
ret := _m.Called(ctx, u, r, link) ret := _m.Called(ctx, u, r, link)
if len(ret) == 0 {
panic("no return value specified for Deactivate")
}
var r0 error var r0 error
if rf, ok := ret.Get(0).(func(context.Context, *model.User, *model.Repo, string) error); ok { if rf, ok := ret.Get(0).(func(context.Context, *model.User, *model.Repo, string) error); ok {
r0 = rf(ctx, u, r, link) r0 = rf(ctx, u, r, link)
@ -125,6 +145,10 @@ func (_m *Forge) Deactivate(ctx context.Context, u *model.User, r *model.Repo, l
func (_m *Forge) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, f string) ([]*types.FileMeta, error) { func (_m *Forge) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, f string) ([]*types.FileMeta, error) {
ret := _m.Called(ctx, u, r, b, f) ret := _m.Called(ctx, u, r, b, f)
if len(ret) == 0 {
panic("no return value specified for Dir")
}
var r0 []*types.FileMeta var r0 []*types.FileMeta
var r1 error var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *model.User, *model.Repo, *model.Pipeline, string) ([]*types.FileMeta, error)); ok { if rf, ok := ret.Get(0).(func(context.Context, *model.User, *model.Repo, *model.Pipeline, string) ([]*types.FileMeta, error)); ok {
@ -151,6 +175,10 @@ func (_m *Forge) Dir(ctx context.Context, u *model.User, r *model.Repo, b *model
func (_m *Forge) File(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, f string) ([]byte, error) { func (_m *Forge) File(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, f string) ([]byte, error) {
ret := _m.Called(ctx, u, r, b, f) ret := _m.Called(ctx, u, r, b, f)
if len(ret) == 0 {
panic("no return value specified for File")
}
var r0 []byte var r0 []byte
var r1 error var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *model.User, *model.Repo, *model.Pipeline, string) ([]byte, error)); ok { if rf, ok := ret.Get(0).(func(context.Context, *model.User, *model.Repo, *model.Pipeline, string) ([]byte, error)); ok {
@ -177,6 +205,10 @@ func (_m *Forge) File(ctx context.Context, u *model.User, r *model.Repo, b *mode
func (_m *Forge) Hook(ctx context.Context, r *http.Request) (*model.Repo, *model.Pipeline, error) { func (_m *Forge) Hook(ctx context.Context, r *http.Request) (*model.Repo, *model.Pipeline, error) {
ret := _m.Called(ctx, r) ret := _m.Called(ctx, r)
if len(ret) == 0 {
panic("no return value specified for Hook")
}
var r0 *model.Repo var r0 *model.Repo
var r1 *model.Pipeline var r1 *model.Pipeline
var r2 error var r2 error
@ -212,6 +244,10 @@ func (_m *Forge) Hook(ctx context.Context, r *http.Request) (*model.Repo, *model
func (_m *Forge) Login(ctx context.Context, w http.ResponseWriter, r *http.Request) (*model.User, error) { func (_m *Forge) Login(ctx context.Context, w http.ResponseWriter, r *http.Request) (*model.User, error) {
ret := _m.Called(ctx, w, r) ret := _m.Called(ctx, w, r)
if len(ret) == 0 {
panic("no return value specified for Login")
}
var r0 *model.User var r0 *model.User
var r1 error var r1 error
if rf, ok := ret.Get(0).(func(context.Context, http.ResponseWriter, *http.Request) (*model.User, error)); ok { if rf, ok := ret.Get(0).(func(context.Context, http.ResponseWriter, *http.Request) (*model.User, error)); ok {
@ -238,6 +274,10 @@ func (_m *Forge) Login(ctx context.Context, w http.ResponseWriter, r *http.Reque
func (_m *Forge) Name() string { func (_m *Forge) Name() string {
ret := _m.Called() ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for Name")
}
var r0 string var r0 string
if rf, ok := ret.Get(0).(func() string); ok { if rf, ok := ret.Get(0).(func() string); ok {
r0 = rf() r0 = rf()
@ -252,6 +292,10 @@ func (_m *Forge) Name() string {
func (_m *Forge) Netrc(u *model.User, r *model.Repo) (*model.Netrc, error) { func (_m *Forge) Netrc(u *model.User, r *model.Repo) (*model.Netrc, error) {
ret := _m.Called(u, r) ret := _m.Called(u, r)
if len(ret) == 0 {
panic("no return value specified for Netrc")
}
var r0 *model.Netrc var r0 *model.Netrc
var r1 error var r1 error
if rf, ok := ret.Get(0).(func(*model.User, *model.Repo) (*model.Netrc, error)); ok { if rf, ok := ret.Get(0).(func(*model.User, *model.Repo) (*model.Netrc, error)); ok {
@ -278,6 +322,10 @@ func (_m *Forge) Netrc(u *model.User, r *model.Repo) (*model.Netrc, error) {
func (_m *Forge) Org(ctx context.Context, u *model.User, org string) (*model.Org, error) { func (_m *Forge) Org(ctx context.Context, u *model.User, org string) (*model.Org, error) {
ret := _m.Called(ctx, u, org) ret := _m.Called(ctx, u, org)
if len(ret) == 0 {
panic("no return value specified for Org")
}
var r0 *model.Org var r0 *model.Org
var r1 error var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *model.User, string) (*model.Org, error)); ok { if rf, ok := ret.Get(0).(func(context.Context, *model.User, string) (*model.Org, error)); ok {
@ -304,6 +352,10 @@ func (_m *Forge) Org(ctx context.Context, u *model.User, org string) (*model.Org
func (_m *Forge) OrgMembership(ctx context.Context, u *model.User, org string) (*model.OrgPerm, error) { func (_m *Forge) OrgMembership(ctx context.Context, u *model.User, org string) (*model.OrgPerm, error) {
ret := _m.Called(ctx, u, org) ret := _m.Called(ctx, u, org)
if len(ret) == 0 {
panic("no return value specified for OrgMembership")
}
var r0 *model.OrgPerm var r0 *model.OrgPerm
var r1 error var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *model.User, string) (*model.OrgPerm, error)); ok { if rf, ok := ret.Get(0).(func(context.Context, *model.User, string) (*model.OrgPerm, error)); ok {
@ -330,6 +382,10 @@ func (_m *Forge) OrgMembership(ctx context.Context, u *model.User, org string) (
func (_m *Forge) PullRequests(ctx context.Context, u *model.User, r *model.Repo, p *model.ListOptions) ([]*model.PullRequest, error) { func (_m *Forge) PullRequests(ctx context.Context, u *model.User, r *model.Repo, p *model.ListOptions) ([]*model.PullRequest, error) {
ret := _m.Called(ctx, u, r, p) ret := _m.Called(ctx, u, r, p)
if len(ret) == 0 {
panic("no return value specified for PullRequests")
}
var r0 []*model.PullRequest var r0 []*model.PullRequest
var r1 error var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *model.User, *model.Repo, *model.ListOptions) ([]*model.PullRequest, error)); ok { if rf, ok := ret.Get(0).(func(context.Context, *model.User, *model.Repo, *model.ListOptions) ([]*model.PullRequest, error)); ok {
@ -356,6 +412,10 @@ func (_m *Forge) PullRequests(ctx context.Context, u *model.User, r *model.Repo,
func (_m *Forge) Repo(ctx context.Context, u *model.User, remoteID model.ForgeRemoteID, owner string, name string) (*model.Repo, error) { func (_m *Forge) Repo(ctx context.Context, u *model.User, remoteID model.ForgeRemoteID, owner string, name string) (*model.Repo, error) {
ret := _m.Called(ctx, u, remoteID, owner, name) ret := _m.Called(ctx, u, remoteID, owner, name)
if len(ret) == 0 {
panic("no return value specified for Repo")
}
var r0 *model.Repo var r0 *model.Repo
var r1 error var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *model.User, model.ForgeRemoteID, string, string) (*model.Repo, error)); ok { if rf, ok := ret.Get(0).(func(context.Context, *model.User, model.ForgeRemoteID, string, string) (*model.Repo, error)); ok {
@ -382,6 +442,10 @@ func (_m *Forge) Repo(ctx context.Context, u *model.User, remoteID model.ForgeRe
func (_m *Forge) Repos(ctx context.Context, u *model.User) ([]*model.Repo, error) { func (_m *Forge) Repos(ctx context.Context, u *model.User) ([]*model.Repo, error) {
ret := _m.Called(ctx, u) ret := _m.Called(ctx, u)
if len(ret) == 0 {
panic("no return value specified for Repos")
}
var r0 []*model.Repo var r0 []*model.Repo
var r1 error var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *model.User) ([]*model.Repo, error)); ok { if rf, ok := ret.Get(0).(func(context.Context, *model.User) ([]*model.Repo, error)); ok {
@ -408,6 +472,10 @@ func (_m *Forge) Repos(ctx context.Context, u *model.User) ([]*model.Repo, error
func (_m *Forge) Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, p *model.Workflow) error { func (_m *Forge) Status(ctx context.Context, u *model.User, r *model.Repo, b *model.Pipeline, p *model.Workflow) error {
ret := _m.Called(ctx, u, r, b, p) ret := _m.Called(ctx, u, r, b, p)
if len(ret) == 0 {
panic("no return value specified for Status")
}
var r0 error var r0 error
if rf, ok := ret.Get(0).(func(context.Context, *model.User, *model.Repo, *model.Pipeline, *model.Workflow) error); ok { if rf, ok := ret.Get(0).(func(context.Context, *model.User, *model.Repo, *model.Pipeline, *model.Workflow) error); ok {
r0 = rf(ctx, u, r, b, p) r0 = rf(ctx, u, r, b, p)
@ -422,6 +490,10 @@ func (_m *Forge) Status(ctx context.Context, u *model.User, r *model.Repo, b *mo
func (_m *Forge) Teams(ctx context.Context, u *model.User) ([]*model.Team, error) { func (_m *Forge) Teams(ctx context.Context, u *model.User) ([]*model.Team, error) {
ret := _m.Called(ctx, u) ret := _m.Called(ctx, u)
if len(ret) == 0 {
panic("no return value specified for Teams")
}
var r0 []*model.Team var r0 []*model.Team
var r1 error var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *model.User) ([]*model.Team, error)); ok { if rf, ok := ret.Get(0).(func(context.Context, *model.User) ([]*model.Team, error)); ok {
@ -448,6 +520,10 @@ func (_m *Forge) Teams(ctx context.Context, u *model.User) ([]*model.Team, error
func (_m *Forge) URL() string { func (_m *Forge) URL() string {
ret := _m.Called() ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for URL")
}
var r0 string var r0 string
if rf, ok := ret.Get(0).(func() string); ok { if rf, ok := ret.Get(0).(func() string); ok {
r0 = rf() r0 = rf()

View file

@ -61,6 +61,7 @@ const (
StatusError StatusValue = "error" // error with the config / while parsing / some other system problem StatusError StatusValue = "error" // error with the config / while parsing / some other system problem
StatusBlocked StatusValue = "blocked" // waiting for approval StatusBlocked StatusValue = "blocked" // waiting for approval
StatusDeclined StatusValue = "declined" // blocked and declined StatusDeclined StatusValue = "declined" // blocked and declined
StatusCreated StatusValue = "created" // created / internal use only
) )
// SCMKind represent different version control systems // SCMKind represent different version control systems

View file

@ -53,7 +53,7 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, pipeline
// update some pipeline fields // update some pipeline fields
pipeline.RepoID = repo.ID pipeline.RepoID = repo.ID
pipeline.Status = model.StatusPending pipeline.Status = model.StatusCreated
setGatedState(repo, pipeline) setGatedState(repo, pipeline)
err = _store.CreatePipeline(pipeline) err = _store.CreatePipeline(pipeline)
if err != nil { if err != nil {
@ -81,9 +81,17 @@ func Create(ctx context.Context, _store store.Store, repo *model.Repo, pipeline
if len(pipelineItems) == 0 { if len(pipelineItems) == 0 {
log.Debug().Str("repo", repo.FullName).Msg(ErrFiltered.Error()) log.Debug().Str("repo", repo.FullName).Msg(ErrFiltered.Error())
if err := _store.DeletePipeline(pipeline); err != nil {
log.Error().Str("repo", repo.FullName).Err(err).Msg("failed to delete empty pipeline")
}
return nil, ErrFiltered return nil, ErrFiltered
} }
if err := updatePipelinePending(ctx, _store, pipeline, repo, repoUser); err != nil {
return nil, err
}
pipeline = setPipelineStepsOnPipeline(pipeline, pipelineItems) pipeline = setPipelineStepsOnPipeline(pipeline, pipelineItems)
// persist the pipeline config for historical correctness, restarts, etc // persist the pipeline config for historical correctness, restarts, etc
@ -135,3 +143,17 @@ func updatePipelineWithErr(ctx context.Context, _store store.Store, pipeline *mo
return nil return nil
} }
func updatePipelinePending(ctx context.Context, _store store.Store, pipeline *model.Pipeline, repo *model.Repo, repoUser *model.User) error {
pipeline.Status = model.StatusPending
dbErr := _store.UpdatePipeline(pipeline)
if dbErr != nil {
msg := fmt.Errorf("failed to save pipeline for %s", repo.FullName)
log.Error().Err(dbErr).Msg(msg.Error())
return msg
}
publishPipeline(ctx, pipeline, repo, repoUser)
return nil
}

View file

@ -136,7 +136,11 @@ func (s storage) UpdatePipeline(pipeline *model.Pipeline) error {
return err return err
} }
func deletePipeline(sess *xorm.Session, pipelineID int64) error { func (s storage) DeletePipeline(pipeline *model.Pipeline) error {
return s.deletePipeline(s.engine.NewSession(), pipeline.ID)
}
func (s storage) deletePipeline(sess *xorm.Session, pipelineID int64) error {
// delete related steps // delete related steps
for startSteps := 0; ; startSteps += perPage { for startSteps := 0; ; startSteps += perPage {
stepIDs := make([]int64, 0, perPage) stepIDs := make([]int64, 0, perPage)

View file

@ -123,7 +123,7 @@ func (s storage) deleteRepo(sess *xorm.Session, repo *model.Repo) error {
} }
for i := range pipelineIDs { for i := range pipelineIDs {
if err := deletePipeline(sess, pipelineIDs[i]); err != nil { if err := s.deletePipeline(sess, pipelineIDs[i]); err != nil {
return err return err
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -93,6 +93,8 @@ type Store interface {
CreatePipeline(*model.Pipeline, ...*model.Step) error CreatePipeline(*model.Pipeline, ...*model.Step) error
// UpdatePipeline updates a pipeline. // UpdatePipeline updates a pipeline.
UpdatePipeline(*model.Pipeline) error UpdatePipeline(*model.Pipeline) error
// DeletePipeline deletes a pipeline.
DeletePipeline(*model.Pipeline) error
// Feeds // Feeds
UserFeed(*model.User) ([]*model.Feed, error) UserFeed(*model.User) ([]*model.Feed, error)