Feature/dron 101 cards 2 (#3158)
* refactor create / find / delete end points for cards
This commit is contained in:
parent
a2210384f9
commit
df2da1c646
29 changed files with 362 additions and 640 deletions
49
core/card.go
49
core/card.go
|
@ -17,48 +17,19 @@ package core
|
|||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/drone/drone/handler/api/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
errCardStepInvalid = errors.New("No Step ID Provided")
|
||||
errCardBuildInvalid = errors.New("No Build ID Provided")
|
||||
errCardSchemaInvalid = errors.New("No Card Schema Has Been Provided")
|
||||
)
|
||||
|
||||
type Card struct {
|
||||
Id int64 `json:"id,omitempty"`
|
||||
Build int64 `json:"build,omitempty"`
|
||||
Stage int64 `json:"stage,omitempty"`
|
||||
Step int64 `json:"step,omitempty"`
|
||||
Schema string `json:"schema,omitempty"`
|
||||
}
|
||||
|
||||
type CardData struct {
|
||||
Id int64 `json:"id,omitempty"`
|
||||
Data []byte `json:"card_data"`
|
||||
}
|
||||
|
||||
// CardStore manages repository cards.
|
||||
type CardStore interface {
|
||||
FindByBuild(ctx context.Context, build int64) ([]*Card, error)
|
||||
Find(ctx context.Context, step int64) (*Card, error)
|
||||
FindData(ctx context.Context, id int64) (io.ReadCloser, error)
|
||||
Create(ctx context.Context, card *Card, data io.ReadCloser) error
|
||||
Delete(ctx context.Context, id int64) error
|
||||
}
|
||||
// Find returns a card data stream from the datastore.
|
||||
Find(ctx context.Context, step int64) (io.ReadCloser, error)
|
||||
|
||||
// Validate validates the required fields and formats.
|
||||
func (c *Card) Validate() error {
|
||||
switch {
|
||||
case c.Step == 0:
|
||||
return errCardStepInvalid
|
||||
case c.Build == 0:
|
||||
return errCardBuildInvalid
|
||||
case len(c.Schema) == 0:
|
||||
return errCardSchemaInvalid
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
// Create copies the card stream from Reader r to the datastore.
|
||||
Create(ctx context.Context, step int64, r io.Reader) error
|
||||
|
||||
// Update copies the card stream from Reader r to the datastore.
|
||||
Update(ctx context.Context, step int64, r io.Reader) error
|
||||
|
||||
// Delete purges the card data from the datastore.
|
||||
Delete(ctx context.Context, step int64) error
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ type (
|
|||
DependsOn []string `json:"depends_on,omitempty"`
|
||||
Image string `json:"image,omitempty"`
|
||||
Detached bool `json:"detached,omitempty"`
|
||||
Schema string `json:"schema,omitempty"`
|
||||
}
|
||||
|
||||
// StepStore persists build step information to storage.
|
||||
|
|
|
@ -291,9 +291,7 @@ func (s Server) Handler() http.Handler {
|
|||
})
|
||||
|
||||
r.Route("/cards", func(r chi.Router) {
|
||||
r.Get("/{build}", card.HandleFindAll(s.Builds, s.Card, s.Repos))
|
||||
r.Get("/{build}/{stage}/{step}", card.HandleFind(s.Builds, s.Card, s.Stages, s.Steps, s.Repos))
|
||||
r.Get("/{build}/{stage}/{step}/json", card.HandleFindData(s.Builds, s.Card, s.Stages, s.Steps, s.Repos))
|
||||
r.With(
|
||||
acl.CheckAdminAccess(),
|
||||
).Post("/{build}/{stage}/{step}", card.HandleCreate(s.Builds, s.Card, s.Stages, s.Steps, s.Repos))
|
||||
|
|
|
@ -85,29 +85,24 @@ func HandleCreate(
|
|||
return
|
||||
}
|
||||
|
||||
c := &core.Card{
|
||||
Build: build.ID,
|
||||
Stage: stage.ID,
|
||||
Step: step.ID,
|
||||
Schema: in.Schema,
|
||||
}
|
||||
|
||||
err = c.Validate()
|
||||
if err != nil {
|
||||
render.BadRequest(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
data := ioutil.NopCloser(
|
||||
bytes.NewBuffer([]byte(in.Data)),
|
||||
bytes.NewBuffer(in.Data),
|
||||
)
|
||||
|
||||
err = cardStore.Create(r.Context(), c, data)
|
||||
/// create card
|
||||
err = cardStore.Create(r.Context(), step.ID, data)
|
||||
if err != nil {
|
||||
render.InternalError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.JSON(w, c, 200)
|
||||
// add schema
|
||||
step.Schema = in.Schema
|
||||
err = stepStore.Update(r.Context(), step)
|
||||
if err != nil {
|
||||
render.InternalError(w, err)
|
||||
return
|
||||
}
|
||||
render.JSON(w, step.ID, 200)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
@ -24,6 +23,11 @@ import (
|
|||
"github.com/google/go-cmp/cmp"
|
||||
)
|
||||
|
||||
type card struct {
|
||||
Id int64 `json:"id,omitempty"`
|
||||
Data []byte `json:"card_data"`
|
||||
}
|
||||
|
||||
var (
|
||||
dummyRepo = &core.Repository{
|
||||
ID: 1,
|
||||
|
@ -42,23 +46,12 @@ var (
|
|||
dummyStep = &core.Step{
|
||||
ID: 1,
|
||||
StageID: 1,
|
||||
Schema: "https://myschema.com",
|
||||
}
|
||||
dummyCreateCard = &core.Card{
|
||||
Schema: "https://myschema.com",
|
||||
dummyCard = &card{
|
||||
Id: dummyStep.ID,
|
||||
Data: []byte("{\"type\": \"AdaptiveCard\"}"),
|
||||
}
|
||||
dummyCard = &core.Card{
|
||||
Id: 1,
|
||||
Build: 1,
|
||||
Stage: 1,
|
||||
Step: 1,
|
||||
Schema: "https://myschema.com",
|
||||
}
|
||||
dummyCardList = []*core.Card{
|
||||
dummyCard,
|
||||
}
|
||||
dummyCardData = ioutil.NopCloser(
|
||||
bytes.NewBuffer([]byte("{\"type\": \"AdaptiveCard\"}")),
|
||||
)
|
||||
)
|
||||
|
||||
func TestHandleCreate(t *testing.T) {
|
||||
|
@ -76,6 +69,7 @@ func TestHandleCreate(t *testing.T) {
|
|||
|
||||
step := mock.NewMockStepStore(controller)
|
||||
step.EXPECT().FindNumber(gomock.Any(), dummyStage.ID, gomock.Any()).Return(dummyStep, nil)
|
||||
step.EXPECT().Update(gomock.Any(), gomock.Any()).Return(nil)
|
||||
|
||||
card := mock.NewMockCardStore(controller)
|
||||
card.EXPECT().Create(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
|
||||
|
@ -88,7 +82,7 @@ func TestHandleCreate(t *testing.T) {
|
|||
c.URLParams.Add("step", "1")
|
||||
|
||||
in := new(bytes.Buffer)
|
||||
json.NewEncoder(in).Encode(dummyCreateCard)
|
||||
json.NewEncoder(in).Encode(dummyCard)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("POST", "/", in)
|
||||
|
@ -140,12 +134,12 @@ func TestHandleCreate_CreateError(t *testing.T) {
|
|||
stage := mock.NewMockStageStore(controller)
|
||||
stage.EXPECT().FindNumber(gomock.Any(), dummyBuild.ID, gomock.Any()).Return(dummyStage, nil)
|
||||
|
||||
step := mock.NewMockStepStore(controller)
|
||||
step.EXPECT().FindNumber(gomock.Any(), dummyStage.ID, gomock.Any()).Return(dummyStep, nil)
|
||||
|
||||
card := mock.NewMockCardStore(controller)
|
||||
card.EXPECT().Create(gomock.Any(), gomock.Any(), gomock.Any()).Return(errors.ErrNotFound)
|
||||
|
||||
step := mock.NewMockStepStore(controller)
|
||||
step.EXPECT().FindNumber(gomock.Any(), dummyStage.ID, gomock.Any()).Return(dummyStep, nil)
|
||||
|
||||
c := new(chi.Context)
|
||||
c.URLParams.Add("owner", "octocat")
|
||||
c.URLParams.Add("name", "hello-world")
|
||||
|
@ -153,7 +147,7 @@ func TestHandleCreate_CreateError(t *testing.T) {
|
|||
c.URLParams.Add("stage", "1")
|
||||
c.URLParams.Add("step", "1")
|
||||
in := new(bytes.Buffer)
|
||||
json.NewEncoder(in).Encode(dummyCreateCard)
|
||||
json.NewEncoder(in).Encode(dummyCard)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/", in)
|
||||
|
|
|
@ -71,12 +71,12 @@ func HandleDelete(
|
|||
return
|
||||
}
|
||||
|
||||
card, err := cardStore.Find(r.Context(), step.ID)
|
||||
_, err = cardStore.Find(r.Context(), step.ID)
|
||||
if err != nil {
|
||||
render.NotFound(w, err)
|
||||
return
|
||||
}
|
||||
err = cardStore.Delete(r.Context(), card.Id)
|
||||
err = cardStore.Delete(r.Context(), step.ID)
|
||||
if err != nil {
|
||||
render.InternalError(w, err)
|
||||
return
|
||||
|
|
|
@ -7,8 +7,10 @@
|
|||
package card
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
@ -38,7 +40,9 @@ func TestHandleDelete(t *testing.T) {
|
|||
step.EXPECT().FindNumber(gomock.Any(), dummyStage.ID, gomock.Any()).Return(dummyStep, nil)
|
||||
|
||||
card := mock.NewMockCardStore(controller)
|
||||
card.EXPECT().Find(gomock.Any(), dummyStep.ID).Return(dummyCard, nil)
|
||||
card.EXPECT().Find(gomock.Any(), dummyStep.ID).Return(ioutil.NopCloser(
|
||||
bytes.NewBuffer(dummyCard.Data),
|
||||
), nil)
|
||||
card.EXPECT().Delete(gomock.Any(), dummyCard.Id).Return(nil)
|
||||
|
||||
c := new(chi.Context)
|
||||
|
@ -121,7 +125,9 @@ func TestHandleDelete_DeleteError(t *testing.T) {
|
|||
step.EXPECT().FindNumber(gomock.Any(), dummyStage.ID, gomock.Any()).Return(dummyStep, nil)
|
||||
|
||||
card := mock.NewMockCardStore(controller)
|
||||
card.EXPECT().Find(gomock.Any(), dummyStep.ID).Return(dummyCard, nil)
|
||||
card.EXPECT().Find(gomock.Any(), dummyStep.ID).Return(ioutil.NopCloser(
|
||||
bytes.NewBuffer(dummyCard.Data),
|
||||
), nil)
|
||||
card.EXPECT().Delete(gomock.Any(), dummyCard.Id).Return(errors.ErrNotFound)
|
||||
|
||||
c := new(chi.Context)
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
package card
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
|
@ -69,11 +70,13 @@ func HandleFind(
|
|||
return
|
||||
}
|
||||
|
||||
card, err := cardStore.Find(r.Context(), step.ID)
|
||||
cardData, err := cardStore.Find(r.Context(), step.ID)
|
||||
if err != nil {
|
||||
render.NotFound(w, err)
|
||||
return
|
||||
}
|
||||
render.JSON(w, card, 200)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
io.Copy(w, cardData)
|
||||
cardData.Close()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Drone Non-Commercial License
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// +build !oss
|
||||
|
||||
package card
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/drone/drone/core"
|
||||
"github.com/drone/drone/handler/api/render"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
)
|
||||
|
||||
// HandleFindAll returns an http.HandlerFunc that writes a json-encoded
|
||||
func HandleFindAll(
|
||||
buildStore core.BuildStore,
|
||||
cardStore core.CardStore,
|
||||
repoStore core.RepositoryStore,
|
||||
) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
namespace = chi.URLParam(r, "owner")
|
||||
name = chi.URLParam(r, "name")
|
||||
)
|
||||
|
||||
buildNumber, err := strconv.ParseInt(chi.URLParam(r, "build"), 10, 64)
|
||||
if err != nil {
|
||||
render.BadRequest(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
repo, err := repoStore.FindName(r.Context(), namespace, name)
|
||||
if err != nil {
|
||||
render.NotFound(w, err)
|
||||
return
|
||||
}
|
||||
build, err := buildStore.FindNumber(r.Context(), repo.ID, buildNumber)
|
||||
if err != nil {
|
||||
render.NotFound(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
list, err := cardStore.FindByBuild(r.Context(), build.ID)
|
||||
if err != nil {
|
||||
render.NotFound(w, err)
|
||||
return
|
||||
}
|
||||
render.JSON(w, list, 200)
|
||||
}
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Drone Non-Commercial License
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// +build !oss
|
||||
|
||||
package card
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/drone/drone/handler/api/errors"
|
||||
"github.com/drone/drone/mock"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
)
|
||||
|
||||
func TestHandleFindAll(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
repos := mock.NewMockRepositoryStore(controller)
|
||||
repos.EXPECT().FindName(gomock.Any(), "octocat", "hello-world").Return(dummyRepo, nil)
|
||||
|
||||
build := mock.NewMockBuildStore(controller)
|
||||
build.EXPECT().FindNumber(gomock.Any(), dummyBuild.ID, gomock.Any()).Return(dummyBuild, nil)
|
||||
|
||||
card := mock.NewMockCardStore(controller)
|
||||
card.EXPECT().FindByBuild(gomock.Any(), dummyBuild.ID).Return(dummyCardList, nil)
|
||||
|
||||
c := new(chi.Context)
|
||||
c.URLParams.Add("owner", "octocat")
|
||||
c.URLParams.Add("name", "hello-world")
|
||||
c.URLParams.Add("build", "1")
|
||||
|
||||
in := new(bytes.Buffer)
|
||||
json.NewEncoder(in).Encode(dummyCreateCard)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/", in)
|
||||
r = r.WithContext(
|
||||
context.WithValue(context.Background(), chi.RouteCtxKey, c),
|
||||
)
|
||||
|
||||
HandleFindAll(build, card, repos).ServeHTTP(w, r)
|
||||
if got, want := w.Code, http.StatusOK; want != got {
|
||||
t.Errorf("Want response code %d, got %d", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleFindAll_CardsNotFound(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
repos := mock.NewMockRepositoryStore(controller)
|
||||
repos.EXPECT().FindName(gomock.Any(), "octocat", "hello-world").Return(dummyRepo, nil)
|
||||
|
||||
build := mock.NewMockBuildStore(controller)
|
||||
build.EXPECT().FindNumber(gomock.Any(), dummyBuild.ID, gomock.Any()).Return(dummyBuild, nil)
|
||||
|
||||
card := mock.NewMockCardStore(controller)
|
||||
card.EXPECT().FindByBuild(gomock.Any(), dummyBuild.ID).Return(nil, errors.ErrNotFound)
|
||||
|
||||
c := new(chi.Context)
|
||||
c.URLParams.Add("owner", "octocat")
|
||||
c.URLParams.Add("name", "hello-world")
|
||||
c.URLParams.Add("build", "1")
|
||||
c.URLParams.Add("stage", "1")
|
||||
c.URLParams.Add("step", "1")
|
||||
|
||||
in := new(bytes.Buffer)
|
||||
json.NewEncoder(in).Encode(dummyCreateCard)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/", in)
|
||||
r = r.WithContext(
|
||||
context.WithValue(context.Background(), chi.RouteCtxKey, c),
|
||||
)
|
||||
|
||||
HandleFindAll(build, card, repos).ServeHTTP(w, r)
|
||||
if got, want := w.Code, http.StatusNotFound; want != got {
|
||||
t.Errorf("Want response code %d, got %d", want, got)
|
||||
}
|
||||
|
||||
got, want := new(errors.Error), errors.ErrNotFound
|
||||
json.NewDecoder(w.Body).Decode(got)
|
||||
if diff := cmp.Diff(got, want); len(diff) != 0 {
|
||||
t.Errorf(diff)
|
||||
}
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Drone Non-Commercial License
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// +build !oss
|
||||
|
||||
package card
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/drone/drone/core"
|
||||
"github.com/drone/drone/handler/api/render"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
)
|
||||
|
||||
// HandleFindData returns an http.HandlerFunc that writes a json-encoded
|
||||
func HandleFindData(
|
||||
buildStore core.BuildStore,
|
||||
cardStore core.CardStore,
|
||||
stageStore core.StageStore,
|
||||
stepStore core.StepStore,
|
||||
repoStore core.RepositoryStore,
|
||||
) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
namespace = chi.URLParam(r, "owner")
|
||||
name = chi.URLParam(r, "name")
|
||||
)
|
||||
|
||||
buildNumber, err := strconv.ParseInt(chi.URLParam(r, "build"), 10, 64)
|
||||
if err != nil {
|
||||
render.BadRequest(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
stageNumber, err := strconv.Atoi(chi.URLParam(r, "stage"))
|
||||
if err != nil {
|
||||
render.BadRequest(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
stepNumber, err := strconv.Atoi(chi.URLParam(r, "step"))
|
||||
if err != nil {
|
||||
render.BadRequest(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
repo, err := repoStore.FindName(r.Context(), namespace, name)
|
||||
if err != nil {
|
||||
render.NotFound(w, err)
|
||||
return
|
||||
}
|
||||
build, err := buildStore.FindNumber(r.Context(), repo.ID, buildNumber)
|
||||
if err != nil {
|
||||
render.NotFound(w, err)
|
||||
return
|
||||
}
|
||||
stage, err := stageStore.FindNumber(r.Context(), build.ID, stageNumber)
|
||||
if err != nil {
|
||||
render.NotFound(w, err)
|
||||
return
|
||||
}
|
||||
step, err := stepStore.FindNumber(r.Context(), stage.ID, stepNumber)
|
||||
if err != nil {
|
||||
render.NotFound(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
card, err := cardStore.Find(r.Context(), step.ID)
|
||||
if err != nil {
|
||||
render.NotFound(w, err)
|
||||
return
|
||||
}
|
||||
cardData, err := cardStore.FindData(r.Context(), card.Id)
|
||||
if err != nil {
|
||||
render.NotFound(w, err)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
io.Copy(w, cardData)
|
||||
cardData.Close()
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Drone Non-Commercial License
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// +build !oss
|
||||
|
||||
package card
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/drone/drone/mock"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
func TestHandleFindCardData(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
repos := mock.NewMockRepositoryStore(controller)
|
||||
repos.EXPECT().FindName(gomock.Any(), "octocat", "hello-world").Return(dummyRepo, nil)
|
||||
|
||||
build := mock.NewMockBuildStore(controller)
|
||||
build.EXPECT().FindNumber(gomock.Any(), dummyBuild.ID, gomock.Any()).Return(dummyBuild, nil)
|
||||
|
||||
stage := mock.NewMockStageStore(controller)
|
||||
stage.EXPECT().FindNumber(gomock.Any(), dummyBuild.ID, gomock.Any()).Return(dummyStage, nil)
|
||||
|
||||
step := mock.NewMockStepStore(controller)
|
||||
step.EXPECT().FindNumber(gomock.Any(), dummyStage.ID, gomock.Any()).Return(dummyStep, nil)
|
||||
|
||||
card := mock.NewMockCardStore(controller)
|
||||
card.EXPECT().Find(gomock.Any(), dummyStep.ID).Return(dummyCard, nil)
|
||||
card.EXPECT().FindData(gomock.Any(), dummyCard.Id).Return(dummyCardData, nil)
|
||||
|
||||
c := new(chi.Context)
|
||||
c.URLParams.Add("owner", "octocat")
|
||||
c.URLParams.Add("name", "hello-world")
|
||||
c.URLParams.Add("build", "1")
|
||||
c.URLParams.Add("stage", "1")
|
||||
c.URLParams.Add("step", "1")
|
||||
|
||||
in := new(bytes.Buffer)
|
||||
json.NewEncoder(in).Encode(dummyCreateCard)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/", in)
|
||||
r = r.WithContext(
|
||||
context.WithValue(context.Background(), chi.RouteCtxKey, c),
|
||||
)
|
||||
|
||||
HandleFindData(build, card, stage, step, repos).ServeHTTP(w, r)
|
||||
if got, want := w.Code, http.StatusOK; want != got {
|
||||
t.Errorf("Want response code %d, got %d", want, got)
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ import (
|
|||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
@ -39,7 +40,9 @@ func TestHandleFind(t *testing.T) {
|
|||
step.EXPECT().FindNumber(gomock.Any(), dummyStage.ID, gomock.Any()).Return(dummyStep, nil)
|
||||
|
||||
card := mock.NewMockCardStore(controller)
|
||||
card.EXPECT().Find(gomock.Any(), dummyStep.ID).Return(dummyCard, nil)
|
||||
card.EXPECT().Find(gomock.Any(), dummyStep.ID).Return(ioutil.NopCloser(
|
||||
bytes.NewBuffer(dummyCard.Data),
|
||||
), nil)
|
||||
|
||||
c := new(chi.Context)
|
||||
c.URLParams.Add("owner", "octocat")
|
||||
|
@ -49,7 +52,7 @@ func TestHandleFind(t *testing.T) {
|
|||
c.URLParams.Add("step", "1")
|
||||
|
||||
in := new(bytes.Buffer)
|
||||
json.NewEncoder(in).Encode(dummyCreateCard)
|
||||
json.NewEncoder(in).Encode(dummyCard)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/", in)
|
||||
|
@ -90,7 +93,7 @@ func TestHandleFind_CardNotFound(t *testing.T) {
|
|||
c.URLParams.Add("step", "1")
|
||||
|
||||
in := new(bytes.Buffer)
|
||||
json.NewEncoder(in).Encode(dummyCreateCard)
|
||||
json.NewEncoder(in).Encode(dummyCard)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/", in)
|
||||
|
|
|
@ -2919,7 +2919,7 @@ func (m *MockCardStore) EXPECT() *MockCardStoreMockRecorder {
|
|||
}
|
||||
|
||||
// Create mocks base method.
|
||||
func (m *MockCardStore) Create(arg0 context.Context, arg1 *core.Card, arg2 io.ReadCloser) error {
|
||||
func (m *MockCardStore) Create(arg0 context.Context, arg1 int64, arg2 io.Reader) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Create", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(error)
|
||||
|
@ -2947,10 +2947,10 @@ func (mr *MockCardStoreMockRecorder) Delete(arg0, arg1 interface{}) *gomock.Call
|
|||
}
|
||||
|
||||
// Find mocks base method.
|
||||
func (m *MockCardStore) Find(arg0 context.Context, arg1 int64) (*core.Card, error) {
|
||||
func (m *MockCardStore) Find(arg0 context.Context, arg1 int64) (io.ReadCloser, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Find", arg0, arg1)
|
||||
ret0, _ := ret[0].(*core.Card)
|
||||
ret0, _ := ret[0].(io.ReadCloser)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
@ -2961,32 +2961,16 @@ func (mr *MockCardStoreMockRecorder) Find(arg0, arg1 interface{}) *gomock.Call {
|
|||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Find", reflect.TypeOf((*MockCardStore)(nil).Find), arg0, arg1)
|
||||
}
|
||||
|
||||
// FindByBuild mocks base method.
|
||||
func (m *MockCardStore) FindByBuild(arg0 context.Context, arg1 int64) ([]*core.Card, error) {
|
||||
// Update mocks base method.
|
||||
func (m *MockCardStore) Update(arg0 context.Context, arg1 int64, arg2 io.Reader) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "FindByBuild", arg0, arg1)
|
||||
ret0, _ := ret[0].([]*core.Card)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
ret := m.ctrl.Call(m, "Update", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// FindByBuild indicates an expected call of FindByBuild.
|
||||
func (mr *MockCardStoreMockRecorder) FindByBuild(arg0, arg1 interface{}) *gomock.Call {
|
||||
// Update indicates an expected call of Update.
|
||||
func (mr *MockCardStoreMockRecorder) Update(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindByBuild", reflect.TypeOf((*MockCardStore)(nil).FindByBuild), arg0, arg1)
|
||||
}
|
||||
|
||||
// FindData mocks base method.
|
||||
func (m *MockCardStore) FindData(arg0 context.Context, arg1 int64) (io.ReadCloser, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "FindData", arg0, arg1)
|
||||
ret0, _ := ret[0].(io.ReadCloser)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// FindData indicates an expected call of FindData.
|
||||
func (mr *MockCardStoreMockRecorder) FindData(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindData", reflect.TypeOf((*MockCardStore)(nil).FindData), arg0, arg1)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockCardStore)(nil).Update), arg0, arg1, arg2)
|
||||
}
|
||||
|
|
|
@ -26,113 +26,78 @@ type cardStore struct {
|
|||
db *db.DB
|
||||
}
|
||||
|
||||
func (c *cardStore) FindByBuild(ctx context.Context, build int64) ([]*core.Card, error) {
|
||||
var out []*core.Card
|
||||
err := c.db.View(func(queryer db.Queryer, binder db.Binder) error {
|
||||
params := map[string]interface{}{
|
||||
"card_build": build,
|
||||
}
|
||||
stmt, args, err := binder.BindNamed(queryByBuild, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rows, err := queryer.Query(stmt, args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out, err = scanRows(rows)
|
||||
return err
|
||||
})
|
||||
return out, err
|
||||
type card struct {
|
||||
Id int64 `json:"id,omitempty"`
|
||||
Data []byte `json:"card_data"`
|
||||
}
|
||||
|
||||
func (c cardStore) Find(ctx context.Context, step int64) (*core.Card, error) {
|
||||
out := &core.Card{Step: step}
|
||||
func (c cardStore) Find(ctx context.Context, step int64) (io.ReadCloser, error) {
|
||||
out := &card{Id: step}
|
||||
err := c.db.View(func(queryer db.Queryer, binder db.Binder) error {
|
||||
params, err := toParams(out)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
query, args, err := binder.BindNamed(queryByStep, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
row := queryer.QueryRow(query, args...)
|
||||
return scanRow(row, out)
|
||||
})
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c cardStore) FindData(ctx context.Context, id int64) (io.ReadCloser, error) {
|
||||
out := &core.CardData{}
|
||||
err := c.db.View(func(queryer db.Queryer, binder db.Binder) error {
|
||||
params := map[string]interface{}{
|
||||
"card_id": id,
|
||||
}
|
||||
query, args, err := binder.BindNamed(queryKey, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
row := queryer.QueryRow(query, args...)
|
||||
return scanRowCardDataOnly(row, out)
|
||||
return scanRow(row, out)
|
||||
})
|
||||
|
||||
return ioutil.NopCloser(
|
||||
bytes.NewBuffer(out.Data),
|
||||
), err
|
||||
}
|
||||
|
||||
func (c cardStore) Create(ctx context.Context, card *core.Card, data io.ReadCloser) error {
|
||||
if c.db.Driver() == db.Postgres {
|
||||
return c.createPostgres(ctx, card, data)
|
||||
func (c cardStore) Create(ctx context.Context, step int64, r io.Reader) error {
|
||||
data, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.create(ctx, card, data)
|
||||
}
|
||||
|
||||
func (c *cardStore) create(ctx context.Context, card *core.Card, data io.ReadCloser) error {
|
||||
return c.db.Lock(func(execer db.Execer, binder db.Binder) error {
|
||||
cardData, err := ioutil.ReadAll(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params, err := toSaveCardParams(card, cardData)
|
||||
if err != nil {
|
||||
return err
|
||||
in := &card{
|
||||
Id: step,
|
||||
Data: data,
|
||||
}
|
||||
params, err := toParams(in)
|
||||
stmt, args, err := binder.BindNamed(stmtInsert, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
res, err := execer.Exec(stmt, args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
card.Id, err = res.LastInsertId()
|
||||
_, err = execer.Exec(stmt, args...)
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
func (c *cardStore) createPostgres(ctx context.Context, card *core.Card, data io.ReadCloser) error {
|
||||
func (c *cardStore) Update(ctx context.Context, step int64, r io.Reader) error {
|
||||
data, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.db.Lock(func(execer db.Execer, binder db.Binder) error {
|
||||
cardData, err := ioutil.ReadAll(data)
|
||||
card := &card{
|
||||
Id: step,
|
||||
Data: data,
|
||||
}
|
||||
params, err := toParams(card)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params, err := toSaveCardParams(card, cardData)
|
||||
stmt, args, err := binder.BindNamed(stmtUpdate, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
stmt, args, err := binder.BindNamed(stmtInsertPostgres, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return execer.QueryRow(stmt, args...).Scan(&card.Id)
|
||||
_, err = execer.Exec(stmt, args...)
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
func (c cardStore) Delete(ctx context.Context, id int64) error {
|
||||
func (c cardStore) Delete(ctx context.Context, step int64) error {
|
||||
return c.db.Lock(func(execer db.Execer, binder db.Binder) error {
|
||||
params := map[string]interface{}{
|
||||
"card_id": id,
|
||||
params := &card{
|
||||
Id: step,
|
||||
}
|
||||
stmt, args, err := binder.BindNamed(stmtDelete, params)
|
||||
if err != nil {
|
||||
|
@ -144,32 +109,12 @@ func (c cardStore) Delete(ctx context.Context, id int64) error {
|
|||
}
|
||||
|
||||
const queryBase = `
|
||||
SELECT
|
||||
card_id
|
||||
,card_build
|
||||
,card_stage
|
||||
,card_step
|
||||
,card_schema
|
||||
`
|
||||
|
||||
const queryCardData = `
|
||||
SELECT
|
||||
card_id
|
||||
,card_data
|
||||
`
|
||||
|
||||
const queryByBuild = queryBase + `
|
||||
FROM cards
|
||||
WHERE card_build = :card_build
|
||||
`
|
||||
|
||||
const queryByStep = queryBase + `
|
||||
FROM cards
|
||||
WHERE card_step = :card_step
|
||||
LIMIT 1
|
||||
`
|
||||
|
||||
const queryKey = queryCardData + `
|
||||
const queryKey = queryBase + `
|
||||
FROM cards
|
||||
WHERE card_id = :card_id
|
||||
LIMIT 1
|
||||
|
@ -177,20 +122,20 @@ LIMIT 1
|
|||
|
||||
const stmtInsert = `
|
||||
INSERT INTO cards (
|
||||
card_build
|
||||
,card_stage
|
||||
,card_step
|
||||
,card_schema
|
||||
card_id
|
||||
,card_data
|
||||
) VALUES (
|
||||
:card_build
|
||||
,:card_stage
|
||||
,:card_step
|
||||
,:card_schema
|
||||
:card_id
|
||||
,:card_data
|
||||
)
|
||||
`
|
||||
|
||||
const stmtUpdate = `
|
||||
UPDATE cards
|
||||
SET card_data = :card_data
|
||||
WHERE card_id = :card_id
|
||||
`
|
||||
|
||||
const stmtDelete = `
|
||||
DELETE FROM cards
|
||||
WHERE card_id = :card_id
|
||||
|
|
|
@ -30,22 +30,18 @@ func New(db *db.DB) core.CardStore {
|
|||
|
||||
type noop struct{}
|
||||
|
||||
func (noop) FindByBuild(ctx context.Context, build int64) ([]*core.Card, error) {
|
||||
func (noop) Find(ctx context.Context, step int64) (io.ReadCloser, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (noop) Find(ctx context.Context, step int64) (*core.Card, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (noop) FindData(ctx context.Context, id int64) (io.ReadCloser, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (noop) Create(ctx context.Context, card *core.Card, data io.ReadCloser) error {
|
||||
func (noop) Create(ctx context.Context, step int64, r io.Reader) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (noop) Delete(ctx context.Context, id int64) error {
|
||||
func (noop) Update(ctx context.Context, step int64, r io.Reader) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (noop) Delete(ctx context.Context, step int64) error {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -8,7 +8,10 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/drone/drone/core"
|
||||
"github.com/drone/drone/store/build"
|
||||
"github.com/drone/drone/store/repos"
|
||||
"github.com/drone/drone/store/shared/db/dbtest"
|
||||
"github.com/drone/drone/store/step"
|
||||
)
|
||||
|
||||
var noContext = context.TODO()
|
||||
|
@ -24,79 +27,46 @@ func TestCard(t *testing.T) {
|
|||
dbtest.Disconnect(conn)
|
||||
}()
|
||||
|
||||
// seed with a dummy repository
|
||||
dummyRepo := &core.Repository{UID: "1", Slug: "octocat/hello-world"}
|
||||
repos := repos.New(conn)
|
||||
repos.Create(noContext, dummyRepo)
|
||||
|
||||
// seed with a dummy stage
|
||||
stage := &core.Stage{Number: 1}
|
||||
stages := []*core.Stage{stage}
|
||||
|
||||
// seed with a dummy build
|
||||
dummyBuild := &core.Build{Number: 1, RepoID: dummyRepo.ID}
|
||||
builds := build.New(conn)
|
||||
builds.Create(noContext, dummyBuild, stages)
|
||||
|
||||
// seed with a dummy step
|
||||
dummyStep := &core.Step{Number: 1, StageID: stage.ID}
|
||||
steps := step.New(conn)
|
||||
steps.Create(noContext, dummyStep)
|
||||
|
||||
store := New(conn).(*cardStore)
|
||||
t.Run("Create", testCardCreate(store))
|
||||
t.Run("Create", testCardCreate(store, dummyStep))
|
||||
t.Run("Find", testFindCard(store, dummyStep))
|
||||
t.Run("Update", testLogsUpdate(store, dummyStep))
|
||||
}
|
||||
|
||||
func testCard(item *core.Card) func(t *testing.T) {
|
||||
func testCardCreate(store *cardStore, step *core.Step) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
if got, want := item.Schema, "https://myschema.com"; got != want {
|
||||
t.Errorf("Want card schema %q, got %q", want, got)
|
||||
}
|
||||
if got, want := item.Build, int64(1); got != want {
|
||||
t.Errorf("Want card build number %q, got %q", want, got)
|
||||
}
|
||||
if got, want := item.Stage, int64(2); got != want {
|
||||
t.Errorf("Want card stage number %q, got %q", want, got)
|
||||
}
|
||||
if got, want := item.Step, int64(3); got != want {
|
||||
t.Errorf("Want card step number %q, got %q", want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testCardCreate(store *cardStore) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
item := &core.Card{
|
||||
Id: 1,
|
||||
Build: 1,
|
||||
Stage: 2,
|
||||
Step: 3,
|
||||
Schema: "https://myschema.com",
|
||||
}
|
||||
buf := ioutil.NopCloser(
|
||||
bytes.NewBuffer([]byte("{\"type\": \"AdaptiveCard\"}")),
|
||||
)
|
||||
err := store.Create(noContext, item, buf)
|
||||
err := store.Create(noContext, step.ID, buf)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if item.Id == 0 {
|
||||
t.Errorf("Want card Id assigned, got %d", item.Id)
|
||||
}
|
||||
|
||||
t.Run("FindByBuild", testFindCardByBuild(store))
|
||||
t.Run("Find", testFindCard(store))
|
||||
t.Run("FindData", testFindCardData(store))
|
||||
t.Run("Delete", testCardDelete(store))
|
||||
}
|
||||
}
|
||||
|
||||
func testFindCardByBuild(card *cardStore) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
item, err := card.FindByBuild(noContext, 1)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
t.Run("Fields", testCard(item[0]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testFindCard(card *cardStore) func(t *testing.T) {
|
||||
func testFindCard(card *cardStore, step *core.Step) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
item, err := card.Find(noContext, 3)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
t.Run("Fields", testCard(item))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testFindCardData(card *cardStore) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
r, err := card.FindData(noContext, 1)
|
||||
r, err := card.Find(noContext, step.ID)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
|
@ -112,19 +82,38 @@ func testFindCardData(card *cardStore) func(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func testCardDelete(store *cardStore) func(t *testing.T) {
|
||||
func testLogsUpdate(store *cardStore, step *core.Step) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
card, err := store.Find(noContext, 3)
|
||||
buf := bytes.NewBufferString("hola mundo")
|
||||
err := store.Update(noContext, step.ID, buf)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
err = store.Delete(noContext, card.Id)
|
||||
r, err := store.Find(noContext, step.ID)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
_, err = store.Find(noContext, card.Step)
|
||||
data, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
if got, want := string(data), "hola mundo"; got != want {
|
||||
t.Errorf("Want updated log output stream %q, got %q", want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testLogsDelete(store *cardStore, step *core.Step) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
err := store.Delete(noContext, step.ID)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
_, err = store.Find(noContext, step.ID)
|
||||
if got, want := sql.ErrNoRows, err; got != want {
|
||||
t.Errorf("Want sql.ErrNoRows, got %v", got)
|
||||
return
|
||||
|
|
|
@ -7,73 +7,27 @@
|
|||
package card
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
"github.com/drone/drone/core"
|
||||
"github.com/drone/drone/store/shared/db"
|
||||
)
|
||||
|
||||
// helper function converts the card structure to a set
|
||||
// of named query parameters.
|
||||
func toParams(card *core.Card) (map[string]interface{}, error) {
|
||||
func toParams(card *card) (map[string]interface{}, error) {
|
||||
return map[string]interface{}{
|
||||
"card_id": card.Id,
|
||||
"card_build": card.Build,
|
||||
"card_stage": card.Stage,
|
||||
"card_step": card.Step,
|
||||
"card_schema": card.Schema,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// helper function converts the card structure to a set
|
||||
// of named query parameters.
|
||||
func toSaveCardParams(card *core.Card, data []byte) (map[string]interface{}, error) {
|
||||
return map[string]interface{}{
|
||||
"card_id": card.Id,
|
||||
"card_build": card.Build,
|
||||
"card_stage": card.Stage,
|
||||
"card_step": card.Step,
|
||||
"card_schema": card.Schema,
|
||||
"card_data": data,
|
||||
"card_id": card.Id,
|
||||
"card_data": card.Data,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// helper function scans the sql.Row and copies the column
|
||||
// values to the destination object.
|
||||
func scanRow(scanner db.Scanner, dst *core.Card) error {
|
||||
func scanRow(scanner db.Scanner, dst *card) error {
|
||||
err := scanner.Scan(
|
||||
&dst.Id,
|
||||
&dst.Build,
|
||||
&dst.Stage,
|
||||
&dst.Step,
|
||||
&dst.Schema,
|
||||
&dst.Data,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func scanRowCardDataOnly(scanner db.Scanner, dst *core.CardData) error {
|
||||
return scanner.Scan(
|
||||
&dst.Id,
|
||||
&dst.Data,
|
||||
)
|
||||
}
|
||||
|
||||
// helper function scans the sql.Row and copies the column
|
||||
// values to the destination object.
|
||||
func scanRows(rows *sql.Rows) ([]*core.Card, error) {
|
||||
defer rows.Close()
|
||||
|
||||
card := []*core.Card{}
|
||||
for rows.Next() {
|
||||
tem := new(core.Card)
|
||||
err := scanRow(rows, tem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
card = append(card, tem)
|
||||
}
|
||||
return card, nil
|
||||
}
|
||||
|
|
|
@ -185,8 +185,24 @@ var migrations = []struct {
|
|||
stmt: createTableCards,
|
||||
},
|
||||
{
|
||||
name: "create-index-cards-card_build",
|
||||
stmt: createIndexCardsCardbuild,
|
||||
name: "create-index-cards-card-build",
|
||||
stmt: createIndexCardsCardBuild,
|
||||
},
|
||||
{
|
||||
name: "create-index-cards-card_step",
|
||||
stmt: createIndexCardsCardstep,
|
||||
},
|
||||
{
|
||||
name: "drop-table-cards",
|
||||
stmt: dropTableCards,
|
||||
},
|
||||
{
|
||||
name: "alter-table-steps-add-column-step_schema",
|
||||
stmt: alterTableStepsAddColumnStepschema,
|
||||
},
|
||||
{
|
||||
name: "create-new-table-cards",
|
||||
stmt: createNewTableCards,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -746,6 +762,32 @@ CREATE TABLE IF NOT EXISTS cards (
|
|||
);
|
||||
`
|
||||
|
||||
var createIndexCardsCardbuild = `
|
||||
var createIndexCardsCardBuild = `
|
||||
CREATE INDEX ix_cards_build ON cards (card_build);
|
||||
`
|
||||
|
||||
var createIndexCardsCardstep = `
|
||||
CREATE UNIQUE INDEX ix_cards_step ON cards (card_step);
|
||||
`
|
||||
|
||||
//
|
||||
// 018_amend_table_cards.sql
|
||||
//
|
||||
|
||||
var dropTableCards = `
|
||||
DROP TABLE IF EXISTS cards;
|
||||
`
|
||||
|
||||
var alterTableStepsAddColumnStepschema = `
|
||||
ALTER TABLE steps
|
||||
ADD COLUMN step_schema VARCHAR(2000) NOT NULL DEFAULT '';
|
||||
`
|
||||
|
||||
var createNewTableCards = `
|
||||
CREATE TABLE IF NOT EXISTS cards
|
||||
(
|
||||
card_id INTEGER PRIMARY KEY,
|
||||
card_data BLOB,
|
||||
FOREIGN KEY (card_id) REFERENCES steps (step_id) ON DELETE CASCADE
|
||||
);
|
||||
`
|
||||
|
|
16
store/shared/migrate/mysql/files/018_amend_table_cards.sql
Normal file
16
store/shared/migrate/mysql/files/018_amend_table_cards.sql
Normal file
|
@ -0,0 +1,16 @@
|
|||
-- name: drop-table-cards
|
||||
|
||||
DROP TABLE IF EXISTS cards;
|
||||
|
||||
-- name: alter-table-steps-add-column-step_schema
|
||||
|
||||
ALTER TABLE steps
|
||||
ADD COLUMN step_schema VARCHAR(2000) NOT NULL DEFAULT '';
|
||||
|
||||
-- name: create-new-table-cards
|
||||
CREATE TABLE IF NOT EXISTS cards
|
||||
(
|
||||
card_id INTEGER PRIMARY KEY,
|
||||
card_data BLOB,
|
||||
FOREIGN KEY (card_id) REFERENCES steps (step_id) ON DELETE CASCADE
|
||||
);
|
|
@ -180,6 +180,22 @@ var migrations = []struct {
|
|||
name: "create-index-cards-card_build",
|
||||
stmt: createIndexCardsCardbuild,
|
||||
},
|
||||
{
|
||||
name: "create-index-cards-card_step",
|
||||
stmt: createIndexCardsCardstep,
|
||||
},
|
||||
{
|
||||
name: "drop-table-cards",
|
||||
stmt: dropTableCards,
|
||||
},
|
||||
{
|
||||
name: "alter-table-steps-add-column-step_schema",
|
||||
stmt: alterTableStepsAddColumnStepschema,
|
||||
},
|
||||
{
|
||||
name: "create-new-table-cards",
|
||||
stmt: createNewTableCards,
|
||||
},
|
||||
}
|
||||
|
||||
// Migrate performs the database migration. If the migration fails
|
||||
|
@ -721,3 +737,29 @@ CREATE TABLE IF NOT EXISTS cards (
|
|||
var createIndexCardsCardbuild = `
|
||||
CREATE INDEX IF NOT EXISTS ix_cards_build ON cards (card_build);
|
||||
`
|
||||
|
||||
var createIndexCardsCardstep = `
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS ix_cards_step ON cards (card_step);
|
||||
`
|
||||
|
||||
//
|
||||
// 019_amend_table_cards.sql
|
||||
//
|
||||
|
||||
var dropTableCards = `
|
||||
DROP TABLE IF EXISTS cards;
|
||||
`
|
||||
|
||||
var alterTableStepsAddColumnStepschema = `
|
||||
ALTER TABLE steps
|
||||
ADD COLUMN step_schema VARCHAR(2000) NOT NULL DEFAULT '';
|
||||
`
|
||||
|
||||
var createNewTableCards = `
|
||||
CREATE TABLE IF NOT EXISTS cards
|
||||
(
|
||||
card_id SERIAL PRIMARY KEY,
|
||||
card_data BYTEA,
|
||||
FOREIGN KEY (card_id) REFERENCES steps (step_id) ON DELETE CASCADE
|
||||
);
|
||||
`
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
-- name: drop-table-cards
|
||||
|
||||
DROP TABLE IF EXISTS cards;
|
||||
|
||||
-- name: alter-table-steps-add-column-step_schema
|
||||
|
||||
ALTER TABLE steps
|
||||
ADD COLUMN step_schema VARCHAR(2000) NOT NULL DEFAULT '';
|
||||
|
||||
-- name: create-new-table-cards
|
||||
CREATE TABLE IF NOT EXISTS cards
|
||||
(
|
||||
card_id SERIAL PRIMARY KEY,
|
||||
card_data BYTEA,
|
||||
FOREIGN KEY (card_id) REFERENCES steps (step_id) ON DELETE CASCADE
|
||||
);
|
|
@ -180,6 +180,22 @@ var migrations = []struct {
|
|||
name: "create-index-cards-card_build",
|
||||
stmt: createIndexCardsCardbuild,
|
||||
},
|
||||
{
|
||||
name: "create-index-cards-card_step",
|
||||
stmt: createIndexCardsCardstep,
|
||||
},
|
||||
{
|
||||
name: "drop-table-cards",
|
||||
stmt: dropTableCards,
|
||||
},
|
||||
{
|
||||
name: "alter-table-steps-add-column-step_schema",
|
||||
stmt: alterTableStepsAddColumnStepschema,
|
||||
},
|
||||
{
|
||||
name: "create-new-table-cards",
|
||||
stmt: createNewTableCards,
|
||||
},
|
||||
}
|
||||
|
||||
// Migrate performs the database migration. If the migration fails
|
||||
|
@ -723,3 +739,29 @@ CREATE TABLE IF NOT EXISTS cards (
|
|||
var createIndexCardsCardbuild = `
|
||||
CREATE INDEX IF NOT EXISTS ix_cards_build ON cards (card_build);
|
||||
`
|
||||
|
||||
var createIndexCardsCardstep = `
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS ix_cards_step ON cards (card_step);
|
||||
`
|
||||
|
||||
//
|
||||
// 018_amend_table_cards.sql
|
||||
//
|
||||
|
||||
var dropTableCards = `
|
||||
DROP TABLE IF EXISTS cards;
|
||||
`
|
||||
|
||||
var alterTableStepsAddColumnStepschema = `
|
||||
ALTER TABLE steps
|
||||
ADD COLUMN step_schema TEXT NOT NULL DEFAULT '';
|
||||
`
|
||||
|
||||
var createNewTableCards = `
|
||||
CREATE TABLE IF NOT EXISTS cards
|
||||
(
|
||||
card_id INTEGER PRIMARY KEY,
|
||||
card_data BLOB,
|
||||
FOREIGN KEY (card_id) REFERENCES steps (step_id) ON DELETE CASCADE
|
||||
);
|
||||
`
|
||||
|
|
16
store/shared/migrate/sqlite/files/018_amend_table_cards.sql
Normal file
16
store/shared/migrate/sqlite/files/018_amend_table_cards.sql
Normal file
|
@ -0,0 +1,16 @@
|
|||
-- name: drop-table-cards
|
||||
|
||||
DROP TABLE IF EXISTS cards;
|
||||
|
||||
-- name: alter-table-steps-add-column-step_schema
|
||||
|
||||
ALTER TABLE steps
|
||||
ADD COLUMN step_schema TEXT NOT NULL DEFAULT '';
|
||||
|
||||
-- name: create-new-table-cards
|
||||
CREATE TABLE IF NOT EXISTS cards
|
||||
(
|
||||
card_id INTEGER PRIMARY KEY,
|
||||
card_data BLOB,
|
||||
FOREIGN KEY (card_id) REFERENCES steps (step_id) ON DELETE CASCADE
|
||||
);
|
|
@ -155,6 +155,7 @@ func scanRowStep(scanner db.Scanner, stage *core.Stage, step *nullStep) error {
|
|||
&stepDepJSON,
|
||||
&step.Image,
|
||||
&step.Detached,
|
||||
&step.Schema,
|
||||
)
|
||||
json.Unmarshal(depJSON, &stage.DependsOn)
|
||||
json.Unmarshal(labJSON, &stage.Labels)
|
||||
|
|
|
@ -326,6 +326,7 @@ SELECT
|
|||
,step_depends_on
|
||||
,step_image
|
||||
,step_detached
|
||||
,step_schema
|
||||
FROM stages
|
||||
LEFT JOIN steps
|
||||
ON stages.stage_id=steps.step_stage_id
|
||||
|
|
|
@ -37,6 +37,7 @@ type nullStep struct {
|
|||
DependsOn types.JSONText
|
||||
Image sql.NullString
|
||||
Detached sql.NullBool
|
||||
Schema sql.NullString
|
||||
}
|
||||
|
||||
func (s *nullStep) value() *core.Step {
|
||||
|
@ -58,6 +59,7 @@ func (s *nullStep) value() *core.Step {
|
|||
DependsOn: dependsOn,
|
||||
Image: s.Image.String,
|
||||
Detached: s.Detached.Bool,
|
||||
Schema: s.Schema.String,
|
||||
}
|
||||
|
||||
return step
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
|
||||
"github.com/drone/drone/core"
|
||||
"github.com/drone/drone/store/shared/db"
|
||||
|
||||
"github.com/jmoiron/sqlx/types"
|
||||
)
|
||||
|
||||
|
@ -41,6 +42,7 @@ func toParams(from *core.Step) map[string]interface{} {
|
|||
"step_depends_on": encodeSlice(from.DependsOn),
|
||||
"step_image": from.Image,
|
||||
"step_detached": from.Detached,
|
||||
"step_schema": from.Schema,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,6 +70,7 @@ func scanRow(scanner db.Scanner, dest *core.Step) error {
|
|||
&depJSON,
|
||||
&dest.Image,
|
||||
&dest.Detached,
|
||||
&dest.Schema,
|
||||
)
|
||||
json.Unmarshal(depJSON, &dest.DependsOn)
|
||||
return err
|
||||
|
|
|
@ -159,6 +159,7 @@ SELECT
|
|||
,step_depends_on
|
||||
,step_image
|
||||
,step_detached
|
||||
,step_schema
|
||||
`
|
||||
|
||||
const queryKey = queryBase + `
|
||||
|
@ -191,6 +192,7 @@ SET
|
|||
,step_depends_on = :step_depends_on
|
||||
,step_image = :step_image
|
||||
,step_detached = :step_detached
|
||||
,step_schema = :step_schema
|
||||
WHERE step_id = :step_id
|
||||
AND step_version = :step_version_old
|
||||
`
|
||||
|
@ -210,6 +212,7 @@ INSERT INTO steps (
|
|||
,step_depends_on
|
||||
,step_image
|
||||
,step_detached
|
||||
,step_schema
|
||||
) VALUES (
|
||||
:step_stage_id
|
||||
,:step_number
|
||||
|
@ -224,6 +227,7 @@ INSERT INTO steps (
|
|||
,:step_depends_on
|
||||
,:step_image
|
||||
,:step_detached
|
||||
,:step_schema
|
||||
)
|
||||
`
|
||||
|
||||
|
|
Loading…
Reference in a new issue