Skip to content
This repository was archived by the owner on May 30, 2024. It is now read-only.

Commit 36495f7

Browse files
author
Noah Lee
authored
Add 'RespondReview' method (#351)
1 parent cc02b63 commit 36495f7

File tree

8 files changed

+148
-35
lines changed

8 files changed

+148
-35
lines changed

internal/interactor/interactor.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ type (
2525
*LicenseInteractor
2626
*LockInteractor
2727
*RepoInteractor
28+
*ReviewInteractor
2829
*UserInteractor
2930
}
3031

@@ -86,6 +87,7 @@ func NewInteractor(c *InteractorConfig) *Interactor {
8687
WebhookSSL: c.ServerProxyProto == "https",
8788
WebhookSecret: c.WebhookSecret,
8889
}
90+
i.ReviewInteractor = (*ReviewInteractor)(i.common)
8991
i.UserInteractor = &UserInteractor{
9092
service: i.common,
9193
admins: c.AdminUsers,

internal/interactor/interface.go

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,6 @@ type (
4747
SyncDeploymentStatus(ctx context.Context, ds *ent.DeploymentStatus) (*ent.DeploymentStatus, error)
4848
}
4949

50-
// ReviewStore defines operations for working with reviews.
51-
ReviewStore interface {
52-
SearchReviews(ctx context.Context, u *ent.User) ([]*ent.Review, error)
53-
ListReviews(ctx context.Context, d *ent.Deployment) ([]*ent.Review, error)
54-
FindReviewOfUser(ctx context.Context, u *ent.User, d *ent.Deployment) (*ent.Review, error)
55-
FindReviewByID(ctx context.Context, id int) (*ent.Review, error)
56-
CreateReview(ctx context.Context, rv *ent.Review) (*ent.Review, error)
57-
UpdateReview(ctx context.Context, rv *ent.Review) (*ent.Review, error)
58-
}
59-
6050
SCM interface {
6151
UserSCM
6252
RepoSCM

internal/interactor/review.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package interactor
2+
3+
import (
4+
"context"
5+
6+
"go.uber.org/zap"
7+
8+
"github.com/gitploy-io/gitploy/model/ent"
9+
"github.com/gitploy-io/gitploy/model/ent/event"
10+
)
11+
12+
type (
13+
ReviewInteractor service
14+
15+
// ReviewStore defines operations for working with reviews.
16+
ReviewStore interface {
17+
SearchReviews(ctx context.Context, u *ent.User) ([]*ent.Review, error)
18+
ListReviews(ctx context.Context, d *ent.Deployment) ([]*ent.Review, error)
19+
FindReviewOfUser(ctx context.Context, u *ent.User, d *ent.Deployment) (*ent.Review, error)
20+
FindReviewByID(ctx context.Context, id int) (*ent.Review, error)
21+
// CreateReview creates a review of which status is pending.
22+
CreateReview(ctx context.Context, rv *ent.Review) (*ent.Review, error)
23+
// UpdateReview update the status and comment of the review.
24+
UpdateReview(ctx context.Context, rv *ent.Review) (*ent.Review, error)
25+
}
26+
)
27+
28+
// RespondReview update the status of review.
29+
func (i *ReviewInteractor) RespondReview(ctx context.Context, rv *ent.Review) (*ent.Review, error) {
30+
rv, err := i.store.UpdateReview(ctx, rv)
31+
if err != nil {
32+
return nil, err
33+
}
34+
35+
if _, err := i.store.CreateEvent(ctx, &ent.Event{
36+
Kind: event.KindReview,
37+
Type: event.TypeCreated,
38+
ReviewID: rv.ID,
39+
}); err != nil {
40+
i.log.Error("Failed to create a review event.", zap.Error(err))
41+
}
42+
43+
return rv, nil
44+
}

internal/interactor/review_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package interactor_test
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
gm "github.com/golang/mock/gomock"
8+
9+
i "github.com/gitploy-io/gitploy/internal/interactor"
10+
"github.com/gitploy-io/gitploy/internal/interactor/mock"
11+
"github.com/gitploy-io/gitploy/model/ent"
12+
)
13+
14+
func TestInteractor_RespondReview(t *testing.T) {
15+
t.Run("Return the review.", func(t *testing.T) {
16+
t.Log("Start mocking:")
17+
ctrl := gm.NewController(t)
18+
store := mock.NewMockStore(ctrl)
19+
20+
t.Log("\tUpdates the review and dispatches a event.")
21+
store.EXPECT().
22+
UpdateReview(gm.Any(), gm.AssignableToTypeOf(&ent.Review{})).
23+
Return(&ent.Review{}, nil)
24+
25+
store.EXPECT().
26+
CreateEvent(gm.Any(), gm.AssignableToTypeOf(&ent.Event{})).
27+
Return(&ent.Event{}, nil)
28+
29+
it := i.NewInteractor(&i.InteractorConfig{
30+
Store: store,
31+
})
32+
_, err := it.RespondReview(context.Background(), &ent.Review{})
33+
if err != nil {
34+
t.Fatalf("RespondReview returns an error: %v", err)
35+
}
36+
})
37+
38+
}

internal/server/api/v1/repos/interface.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ type (
3939
ListReviews(ctx context.Context, d *ent.Deployment) ([]*ent.Review, error)
4040
FindReviewOfUser(ctx context.Context, u *ent.User, d *ent.Deployment) (*ent.Review, error)
4141
UpdateReview(ctx context.Context, rv *ent.Review) (*ent.Review, error)
42+
RespondReview(ctx context.Context, rv *ent.Review) (*ent.Review, error)
4243

4344
ListLocksOfRepo(ctx context.Context, r *ent.Repo) ([]*ent.Lock, error)
4445
HasLockOfRepoForEnv(ctx context.Context, r *ent.Repo, env string) (bool, error)

internal/server/api/v1/repos/mock/interactor.go

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/server/api/v1/repos/review_update.go

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import (
1616

1717
gb "github.com/gitploy-io/gitploy/internal/server/global"
1818
"github.com/gitploy-io/gitploy/model/ent"
19-
"github.com/gitploy-io/gitploy/model/ent/event"
2019
"github.com/gitploy-io/gitploy/model/ent/review"
2120
"github.com/gitploy-io/gitploy/pkg/e"
2221
)
@@ -80,19 +79,12 @@ func (s *ReviewAPI) UpdateMine(c *gin.Context) {
8079
rv.Comment = *p.Comment
8180
}
8281

83-
if rv, err = s.i.UpdateReview(ctx, rv); err != nil {
82+
if rv, err = s.i.RespondReview(ctx, rv); err != nil {
8483
s.log.Check(gb.GetZapLogLevel(err), "Failed to update the review.").Write(zap.Error(err))
8584
gb.ResponseWithError(c, err)
8685
return
8786
}
8887

89-
if _, err := s.i.CreateEvent(ctx, &ent.Event{
90-
Kind: event.KindReview,
91-
Type: event.TypeUpdated,
92-
ReviewID: rv.ID,
93-
}); err != nil {
94-
s.log.Error("Failed to create the event.", zap.Error(err))
95-
}
96-
88+
s.log.Info("Respond the review successfully.", zap.Int("review_id", rv.ID))
9789
gb.Response(c, http.StatusOK, rv)
9890
}

internal/server/api/v1/repos/review_update_test.go

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ import (
1717
"go.uber.org/zap"
1818

1919
"github.com/gitploy-io/gitploy/internal/server/api/v1/repos/mock"
20-
"github.com/golang/mock/gomock"
20+
"github.com/gitploy-io/gitploy/internal/server/global"
21+
"github.com/gitploy-io/gitploy/model/ent"
22+
gm "github.com/golang/mock/gomock"
2123
)
2224

2325
func init() {
@@ -26,30 +28,59 @@ func init() {
2628

2729
func TestReviewAPI_UpdateMine(t *testing.T) {
2830
t.Run("Return 400 code when the status is invalid", func(t *testing.T) {
29-
input := struct {
30-
payload *ReviewPatchPayload
31-
}{
32-
payload: &ReviewPatchPayload{
33-
Status: "INVALID",
34-
},
35-
}
36-
37-
ctrl := gomock.NewController(t)
38-
m := mock.NewMockInteractor(ctrl)
31+
ctrl := gm.NewController(t)
32+
s := &ReviewAPI{i: mock.NewMockInteractor(ctrl), log: zap.L()}
3933

4034
router := gin.New()
41-
42-
s := &ReviewAPI{i: m, log: zap.L()}
4335
router.PATCH("/deployments/:number/review", s.UpdateMine)
4436

45-
p, _ := json.Marshal(input.payload)
37+
p, _ := json.Marshal(&ReviewPatchPayload{
38+
Status: "INVALID",
39+
})
4640
req, _ := http.NewRequest("PATCH", "/deployments/1/review", bytes.NewBuffer(p))
4741
w := httptest.NewRecorder()
48-
4942
router.ServeHTTP(w, req)
5043

5144
if w.Code != http.StatusBadRequest {
5245
t.Fatalf("Code = %v, wanted %v", w.Code, http.StatusBadRequest)
5346
}
5447
})
48+
49+
t.Run("Return 200 when the update has succeeded.", func(t *testing.T) {
50+
t.Log("Start mocking:")
51+
ctrl := gm.NewController(t)
52+
i := mock.NewMockInteractor(ctrl)
53+
54+
t.Log("\tFind the user's review.")
55+
i.EXPECT().
56+
FindDeploymentOfRepoByNumber(gm.Any(), gm.AssignableToTypeOf(&ent.Repo{}), gm.AssignableToTypeOf(1)).
57+
Return(&ent.Deployment{}, nil)
58+
59+
i.EXPECT().
60+
FindReviewOfUser(gm.Any(), gm.Any(), gm.AssignableToTypeOf(&ent.Deployment{})).
61+
Return(&ent.Review{}, nil)
62+
63+
t.Log("\tRespond the review.")
64+
i.EXPECT().
65+
RespondReview(gm.Any(), gm.AssignableToTypeOf(&ent.Review{})).
66+
Return(&ent.Review{}, nil)
67+
68+
s := &ReviewAPI{i: i, log: zap.L()}
69+
router := gin.New()
70+
router.PATCH("/deployments/:number/review", func(c *gin.Context) {
71+
c.Set(global.KeyUser, &ent.User{})
72+
c.Set(KeyRepo, &ent.Repo{})
73+
}, s.UpdateMine)
74+
75+
p, _ := json.Marshal(&ReviewPatchPayload{
76+
Status: "approved",
77+
})
78+
req, _ := http.NewRequest("PATCH", "/deployments/1/review", bytes.NewBuffer(p))
79+
w := httptest.NewRecorder()
80+
router.ServeHTTP(w, req)
81+
82+
if w.Code != http.StatusOK {
83+
t.Fatalf("Code = %v, wanted %v", w.Code, http.StatusOK)
84+
}
85+
})
5586
}

0 commit comments

Comments
 (0)