From 2bf3c9ca988d54cccc44f946c40f898a10cc0e14 Mon Sep 17 00:00:00 2001 From: TP Honey Date: Wed, 29 Sep 2021 10:33:46 +0100 Subject: [PATCH] (DRON-124) adding new status endpoint (#3143) --- core/repo.go | 32 +++++++++++++++++++++ go.sum | 6 ---- handler/api/api.go | 1 + handler/api/builds/builds.go | 13 +++++++++ handler/api/builds/builds_oss.go | 4 +++ mock/mock_gen.go | 15 ++++++++++ store/repos/repos.go | 47 ++++++++++++++++++++++++++++++ store/repos/scan.go | 49 ++++++++++++++++++++++++++++++++ 8 files changed, 161 insertions(+), 6 deletions(-) diff --git a/core/repo.go b/core/repo.go index 74f554fbf..f88b0083b 100644 --- a/core/repo.go +++ b/core/repo.go @@ -67,6 +67,35 @@ type ( Perms *Perm `json:"permissions,omitempty"` } + RepoBuildStage struct { + RepoNamespace string `json:"repo_namespace"` + RepoName string `json:"repo_name"` + RepoSlug string `json:"repo_slug"` + BuildNumber int64 `json:"build_number"` + BuildAuthor string `json:"build_author"` + BuildAuthorName string `json:"build_author_name"` + BuildAuthorEmail string `json:"build_author_email"` + BuildAuthorAvatar string `json:"build_author_avatar"` + BuildSender string `json:"build_sender"` + BuildStarted int64 `json:"build_started"` + BuildFinished int64 `json:"build_finished"` + BuildCreated int64 `json:"build_created"` + BuildUpdated int64 `json:"build_updated"` + StageName string `json:"stage_name"` + StageKind string `json:"stage_kind"` + StageType string `json:"stage_type"` + StageStatus string `json:"stage_status"` + StageMachine string `json:"stage_machine"` + StageOS string `json:"stage_os"` + StageArch string `json:"stage_arch"` + StageVariant string `json:"stage_variant"` + StageKernel string `json:"stage_kernel"` + StageLimit string `json:"stage_limit"` + StageLimitRepo string `json:"stage_limit_repo"` + StageStarted int64 `json:"stage_started"` + StageStopped int64 `json:"stage_stopped"` + } + // RepositoryStore defines operations for working with repositories. RepositoryStore interface { // List returns a repository list from the datastore. @@ -84,6 +113,9 @@ type ( // the datastore with incomplete builds. ListIncomplete(context.Context) ([]*Repository, error) + // ListRunningStatus returns a list of build / repository /stage information for builds that are incomplete. + ListRunningStatus(context.Context) ([]*RepoBuildStage, error) + // ListAll returns a paginated list of all repositories // stored in the database, including disabled repositories. ListAll(ctx context.Context, limit, offset int) ([]*Repository, error) diff --git a/go.sum b/go.sum index 25cbfedbc..be214d52d 100644 --- a/go.sum +++ b/go.sum @@ -78,12 +78,6 @@ github.com/drone/drone-go v1.4.1-0.20201109202657-b9e58bbbcf27/go.mod h1:fxCf9jA github.com/drone/drone-runtime v1.0.7-0.20190729202838-87c84080f4a1/go.mod h1:+osgwGADc/nyl40J0fdsf8Z09bgcBZXvXXnLOY48zYs= github.com/drone/drone-runtime v1.1.1-0.20200623162453-61e33e2cab5d h1:P5HI/Y9hARTZ3F3EKs0kYijhjXZWQRQHYn1neTi0pWM= github.com/drone/drone-runtime v1.1.1-0.20200623162453-61e33e2cab5d/go.mod h1:4/2QToW5+HGD0y1sTw7X35W1f7YINS14UfDY4isggT8= -github.com/drone/drone-ui v2.0.1+incompatible h1:p+cFE2xB5zlQKaEDWXNe2SGzbzyy0oAcmQE2oe8h/xw= -github.com/drone/drone-ui v2.0.1+incompatible/go.mod h1:NBtVWW7NNJpD9+huMD/5TAE1db2nrEh0i35/9Rf1MPI= -github.com/drone/drone-ui v2.1.0+incompatible h1:mxRP0Oauq4M+HiDIxSiI3P2/hkmyxR+2JRLQ9EihqBU= -github.com/drone/drone-ui v2.1.0+incompatible/go.mod h1:NBtVWW7NNJpD9+huMD/5TAE1db2nrEh0i35/9Rf1MPI= -github.com/drone/drone-ui v2.2.0+incompatible h1:De3m4tFw/hg7/6Bap6t8x9M31dByavmvwpJlqUJdKvY= -github.com/drone/drone-ui v2.2.0+incompatible/go.mod h1:NBtVWW7NNJpD9+huMD/5TAE1db2nrEh0i35/9Rf1MPI= github.com/drone/drone-ui v2.2.1+incompatible h1:j5Py26SOjyPHCp294qmVCASeCQ+Q8l/fBNw8UqBPyNU= github.com/drone/drone-ui v2.2.1+incompatible/go.mod h1:NBtVWW7NNJpD9+huMD/5TAE1db2nrEh0i35/9Rf1MPI= github.com/drone/drone-ui v2.3.0+incompatible h1:iFNrvqF/huhKCmGFH80FapiIF4JscNkCfT9lSnm4+Is= diff --git a/handler/api/api.go b/handler/api/api.go index c33f2e624..56ccc5e5d 100644 --- a/handler/api/api.go +++ b/handler/api/api.go @@ -345,6 +345,7 @@ func (s Server) Handler() http.Handler { r.Route("/builds", func(r chi.Router) { r.Use(acl.AuthorizeAdmin) r.Get("/incomplete", globalbuilds.HandleIncomplete(s.Repos)) + r.Get("/incomplete/v2", globalbuilds.HandleRunningStatus(s.Repos)) }) r.Route("/secrets", func(r chi.Router) { diff --git a/handler/api/builds/builds.go b/handler/api/builds/builds.go index 179816eba..52b25cb88 100644 --- a/handler/api/builds/builds.go +++ b/handler/api/builds/builds.go @@ -28,3 +28,16 @@ func HandleIncomplete(repos core.RepositoryStore) http.HandlerFunc { } } } + +func HandleRunningStatus(repos core.RepositoryStore) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + list, err := repos.ListRunningStatus(r.Context()) + if err != nil { + render.InternalError(w, err) + logger.FromRequest(r).WithError(err). + Debugln("api: cannot list incomplete builds") + } else { + render.JSON(w, list, 200) + } + } +} diff --git a/handler/api/builds/builds_oss.go b/handler/api/builds/builds_oss.go index 7da015f1f..1ab6f7fb5 100644 --- a/handler/api/builds/builds_oss.go +++ b/handler/api/builds/builds_oss.go @@ -31,3 +31,7 @@ var notImplemented = func(w http.ResponseWriter, r *http.Request) { func HandleIncomplete(repos core.RepositoryStore) http.HandlerFunc { return notImplemented } + +func HandleRunningStatus(repos core.RepositoryStore) http.HandlerFunc { + return notImplemented +} diff --git a/mock/mock_gen.go b/mock/mock_gen.go index b630a3ddf..214edd413 100644 --- a/mock/mock_gen.go +++ b/mock/mock_gen.go @@ -1917,6 +1917,21 @@ func (mr *MockRepositoryStoreMockRecorder) ListRecent(arg0, arg1 interface{}) *g return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListRecent", reflect.TypeOf((*MockRepositoryStore)(nil).ListRecent), arg0, arg1) } +// ListRunningStatus mocks base method. +func (m *MockRepositoryStore) ListRunningStatus(arg0 context.Context) ([]*core.RepoBuildStage, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListRunningStatus", arg0) + ret0, _ := ret[0].([]*core.RepoBuildStage) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListRunningStatus indicates an expected call of ListRunningStatus. +func (mr *MockRepositoryStoreMockRecorder) ListRunningStatus(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListRunningStatus", reflect.TypeOf((*MockRepositoryStore)(nil).ListRunningStatus), arg0) +} + // Update mocks base method. func (m *MockRepositoryStore) Update(arg0 context.Context, arg1 *core.Repository) error { m.ctrl.T.Helper() diff --git a/store/repos/repos.go b/store/repos/repos.go index a48a524a9..ac883bf69 100644 --- a/store/repos/repos.go +++ b/store/repos/repos.go @@ -104,6 +104,19 @@ func (s *repoStore) ListIncomplete(ctx context.Context) ([]*core.Repository, err return out, err } +func (s *repoStore) ListRunningStatus(ctx context.Context) ([]*core.RepoBuildStage, error) { + var out []*core.RepoBuildStage + err := s.db.View(func(queryer db.Queryer, binder db.Binder) error { + rows, err := queryer.Query(queryReposRunningStatus) + if err != nil { + return err + } + out, err = repoBuildStageRowsBuild(rows) + return err + }) + return out, err +} + func (s *repoStore) ListAll(ctx context.Context, limit, offset int) ([]*core.Repository, error) { var out []*core.Repository err := s.db.View(func(queryer db.Queryer, binder db.Binder) error { @@ -536,3 +549,37 @@ WHERE EXISTS ( ORDER BY build_id DESC LIMIT 50; ` +const queryReposRunningStatus = ` +SELECT +repo_namespace +,repo_name +,repo_slug +,build_number +,build_author +,build_author_name +,build_author_email +,build_author_avatar +,build_sender +,build_started +,build_finished +,build_created +,build_updated +,stage_name +,stage_kind +,stage_type +,stage_status +,stage_machine +,stage_os +,stage_arch +,stage_variant +,stage_kernel +,stage_limit +,stage_limit_repo +,stage_started +,stage_stopped +FROM repos +INNER JOIN builds ON builds.build_repo_id = repos.repo_id +inner join stages on stages.stage_build_id = builds.build_id +where stages.stage_status IN ('pending', 'running') +ORDER BY build_id DESC; +` diff --git a/store/repos/scan.go b/store/repos/scan.go index 4dd2f1a3e..9ddbd1320 100644 --- a/store/repos/scan.go +++ b/store/repos/scan.go @@ -208,3 +208,52 @@ func scanRowsBuild(rows *sql.Rows) ([]*core.Repository, error) { } return repos, nil } + +// helper function scans the sql.Row and copies the column values to the destination object. +func repoBuildStageRowBuild(scanner db.Scanner, dest *core.RepoBuildStage) error { + err := scanner.Scan( + &dest.RepoNamespace, + &dest.RepoName, + &dest.RepoSlug, + &dest.BuildNumber, + &dest.BuildAuthor, + &dest.BuildAuthorName, + &dest.BuildAuthorEmail, + &dest.BuildAuthorAvatar, + &dest.BuildSender, + &dest.BuildStarted, + &dest.BuildFinished, + &dest.BuildCreated, + &dest.BuildUpdated, + &dest.StageName, + &dest.StageKind, + &dest.StageType, + &dest.StageStatus, + &dest.StageMachine, + &dest.StageOS, + &dest.StageArch, + &dest.StageVariant, + &dest.StageKernel, + &dest.StageLimit, + &dest.StageLimitRepo, + &dest.StageStarted, + &dest.StageStopped, + ) + return err +} + +// helper function scans the sql.Row and copies the column values to the destination object. +func repoBuildStageRowsBuild(rows *sql.Rows) ([]*core.RepoBuildStage, error) { + defer rows.Close() + + slices := []*core.RepoBuildStage{} + for rows.Next() { + row := new(core.RepoBuildStage) + err := repoBuildStageRowBuild(rows, row) + if err != nil { + return nil, err + } + slices = append(slices, row) + } + return slices, nil +}