Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dop): iteration support label relation #5992

Merged
merged 1 commit into from
Jul 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions apistructs/iteration.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ type IterationCreateRequest struct {

ManHour *IssueManHour `json:"manHour"`

Labels []string `json:"labels"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be labelIDs


// internal use, get from *http.Request
IdentityInfo
}
Expand Down Expand Up @@ -85,6 +87,8 @@ type IterationUpdateRequest struct {

ManHour *IssueManHour `json:"manHour"`

Labels []string `json:"labels"`

// internal use, get from *http.Request
IdentityInfo
}
Expand All @@ -110,6 +114,8 @@ type IterationPagingRequest struct {
WithoutIssueSummary bool `schema:"withoutIssueSummary"`
// +optional
IDs []uint64 `json:"ids" schema:"id"`
// +optional
LabelIDs []uint64 `json:"labelIDs" schema:"labelIDs"`
}

type IterationPagingResponse struct {
Expand Down Expand Up @@ -143,6 +149,8 @@ type Iteration struct {
State IterationState `json:"state"`
IssueSummary ISummary `json:"issueSummary"`
ManHour *IssueManHour `json:"manHour"`
Labels []string `json:"labels"`
LabelDetails []ProjectLabel `json:"labelDetails"`
}

// ISummary 与迭代相关的事件完成状态的统计信息
Expand Down
5 changes: 3 additions & 2 deletions apistructs/label.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ import (
type ProjectLabelType string

const (
LabelTypeIssue ProjectLabelType = "issue" // issue 标签类型
LabelTypeRelease ProjectLabelType = "release" // release 标签类型
LabelTypeIssue ProjectLabelType = "issue" // issue 标签类型
LabelTypeRelease ProjectLabelType = "release" // release 标签类型
LabelTypeIteration ProjectLabelType = "iteration" // iteration 标签类型
)

// ProjectLabel 标签
Expand Down
26 changes: 14 additions & 12 deletions internal/apps/dop/dao/iteration.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,21 @@ func (Iteration) TableName() string {
return "dice_iterations"
}

func (i *Iteration) Convert() apistructs.Iteration {
func (i *Iteration) Convert(labels []string, labelDetails []apistructs.ProjectLabel) apistructs.Iteration {
return apistructs.Iteration{
ID: int64(i.ID),
CreatedAt: i.CreatedAt,
UpdatedAt: i.UpdatedAt,
StartedAt: i.StartedAt,
FinishedAt: i.FinishedAt,
ProjectID: i.ProjectID,
Title: i.Title,
Content: i.Content,
Creator: i.Creator,
State: i.State,
ManHour: new(apistructs.IssueManHour).FromString(i.ManHour),
ID: int64(i.ID),
CreatedAt: i.CreatedAt,
UpdatedAt: i.UpdatedAt,
StartedAt: i.StartedAt,
FinishedAt: i.FinishedAt,
ProjectID: i.ProjectID,
Title: i.Title,
Content: i.Content,
Creator: i.Creator,
State: i.State,
ManHour: new(apistructs.IssueManHour).FromString(i.ManHour),
Labels: labels,
LabelDetails: labelDetails,
}
}

Expand Down
41 changes: 41 additions & 0 deletions internal/apps/dop/dao/iteration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (c) 2021 Terminus, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package dao

import (
"testing"

"github.com/stretchr/testify/assert"

"github.com/erda-project/erda/apistructs"
"github.com/erda-project/erda/pkg/database/dbengine"
)

func TestConvert(t *testing.T) {
i := &Iteration{
BaseModel: dbengine.BaseModel{
ID: 1,
},
ProjectID: 1,
Title: "iteration1",
}
iter := i.Convert([]string{"label1"}, []apistructs.ProjectLabel{
{
ID: 1,
Name: "label1",
},
})
assert.Equal(t, []string{"label1"}, iter.Labels)
}
90 changes: 88 additions & 2 deletions internal/apps/dop/endpoints/iteration.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@
"context"
"encoding/json"
"net/http"
"reflect"
"strconv"
"time"

"github.com/pkg/errors"
"github.com/sirupsen/logrus"

"github.com/erda-project/erda/apistructs"
"github.com/erda-project/erda/internal/apps/dop/dao"
"github.com/erda-project/erda/internal/apps/dop/services/apierrors"
"github.com/erda-project/erda/internal/pkg/user"
"github.com/erda-project/erda/pkg/http/httpserver"
Expand Down Expand Up @@ -83,6 +85,21 @@
return errorresp.ErrResp(err)
}

labels, err := e.bdl.ListLabelByNameAndProjectID(createReq.ProjectID, createReq.Labels)
if err != nil {
return nil, apierrors.ErrCreateIteration.InternalError(err)

Check warning on line 90 in internal/apps/dop/endpoints/iteration.go

View check run for this annotation

Codecov / codecov/patch

internal/apps/dop/endpoints/iteration.go#L88-L90

Added lines #L88 - L90 were not covered by tests
}
for _, v := range labels {
lr := &dao.LabelRelation{
LabelID: uint64(v.ID),
RefType: apistructs.LabelTypeIteration,
RefID: strconv.FormatUint(id.ID, 10),

Check warning on line 96 in internal/apps/dop/endpoints/iteration.go

View check run for this annotation

Codecov / codecov/patch

internal/apps/dop/endpoints/iteration.go#L92-L96

Added lines #L92 - L96 were not covered by tests
}
if err := e.db.CreateLabelRelation(lr); err != nil {
return nil, apierrors.ErrCreateIssue.InternalError(err)

Check warning on line 99 in internal/apps/dop/endpoints/iteration.go

View check run for this annotation

Codecov / codecov/patch

internal/apps/dop/endpoints/iteration.go#L98-L99

Added lines #L98 - L99 were not covered by tests
}
}

// 更新项目活跃时间
if err := e.bdl.UpdateProjectActiveTime(apistructs.ProjectActiveTimeUpdateRequest{
ProjectID: createReq.ProjectID,
Expand Down Expand Up @@ -137,6 +154,37 @@
return errorresp.ErrResp(err)
}

// update labels
currentLabelMap := make(map[string]bool)
newLabelMap := make(map[string]bool)
currentLabels, _ := e.getIterationLabelDetails(iterationID)
for _, v := range currentLabels {
currentLabelMap[v] = true

Check warning on line 162 in internal/apps/dop/endpoints/iteration.go

View check run for this annotation

Codecov / codecov/patch

internal/apps/dop/endpoints/iteration.go#L158-L162

Added lines #L158 - L162 were not covered by tests
}
for _, v := range updateReq.Labels {
newLabelMap[v] = true

Check warning on line 165 in internal/apps/dop/endpoints/iteration.go

View check run for this annotation

Codecov / codecov/patch

internal/apps/dop/endpoints/iteration.go#L164-L165

Added lines #L164 - L165 were not covered by tests
}
if len(updateReq.Labels) > 0 && !reflect.DeepEqual(currentLabelMap, newLabelMap) {
if err = e.db.DeleteLabelRelations(apistructs.LabelTypeIteration, strconv.FormatUint(iterationID, 10), nil); err != nil {
return apierrors.ErrUpdateIteration.InternalError(err).ToResp(), nil

Check warning on line 169 in internal/apps/dop/endpoints/iteration.go

View check run for this annotation

Codecov / codecov/patch

internal/apps/dop/endpoints/iteration.go#L167-L169

Added lines #L167 - L169 were not covered by tests
}
labels, err := e.bdl.ListLabelByNameAndProjectID(iteration.ProjectID, updateReq.Labels)
if err != nil {
return apierrors.ErrUpdateIteration.InternalError(err).ToResp(), nil

Check warning on line 173 in internal/apps/dop/endpoints/iteration.go

View check run for this annotation

Codecov / codecov/patch

internal/apps/dop/endpoints/iteration.go#L171-L173

Added lines #L171 - L173 were not covered by tests
}
labelRelations := make([]dao.LabelRelation, 0, len(labels))
for _, v := range labels {
labelRelations = append(labelRelations, dao.LabelRelation{
LabelID: uint64(v.ID),
RefType: apistructs.LabelTypeIteration,
RefID: strconv.FormatUint(iterationID, 10),
})

Check warning on line 181 in internal/apps/dop/endpoints/iteration.go

View check run for this annotation

Codecov / codecov/patch

internal/apps/dop/endpoints/iteration.go#L175-L181

Added lines #L175 - L181 were not covered by tests
}
if err := e.db.BatchCreateLabelRelations(labelRelations); err != nil {
return apierrors.ErrUpdateIteration.InternalError(err).ToResp(), nil

Check warning on line 184 in internal/apps/dop/endpoints/iteration.go

View check run for this annotation

Codecov / codecov/patch

internal/apps/dop/endpoints/iteration.go#L183-L184

Added lines #L183 - L184 were not covered by tests
}
}

// 更新项目活跃时间
if err := e.bdl.UpdateProjectActiveTime(apistructs.ProjectActiveTimeUpdateRequest{
ProjectID: iteration.ProjectID,
Expand Down Expand Up @@ -187,6 +235,11 @@
return errorresp.ErrResp(err)
}

// delete relation labels
if err = e.db.DeleteLabelRelations(apistructs.LabelTypeIteration, strconv.FormatUint(iterationID, 10), nil); err != nil {
return apierrors.ErrDeleteIteration.InternalError(err).ToResp(), nil

Check warning on line 240 in internal/apps/dop/endpoints/iteration.go

View check run for this annotation

Codecov / codecov/patch

internal/apps/dop/endpoints/iteration.go#L239-L240

Added lines #L239 - L240 were not covered by tests
}

// 更新项目活跃时间
if err := e.bdl.UpdateProjectActiveTime(apistructs.ProjectActiveTimeUpdateRequest{
ProjectID: iteration.ProjectID,
Expand Down Expand Up @@ -238,7 +291,7 @@
}

userIDs := []string{iteration.Creator}
return httpserver.OkResp(iteration.Convert(), userIDs)
return httpserver.OkResp(iteration.Convert(e.getIterationLabelDetails(iterationID)), userIDs)

Check warning on line 294 in internal/apps/dop/endpoints/iteration.go

View check run for this annotation

Codecov / codecov/patch

internal/apps/dop/endpoints/iteration.go#L294

Added line #L294 was not covered by tests
}

// PagingIterations 分页查询迭代
Expand Down Expand Up @@ -291,14 +344,31 @@
}
}
}
if len(pageReq.LabelIDs) > 0 {
lrs, err := e.db.GetLabelRelationsByLabels(apistructs.LabelTypeIteration, pageReq.LabelIDs)
if err != nil {
return apierrors.ErrPagingIterations.InternalError(err).ToResp(), nil

Check warning on line 350 in internal/apps/dop/endpoints/iteration.go

View check run for this annotation

Codecov / codecov/patch

internal/apps/dop/endpoints/iteration.go#L347-L350

Added lines #L347 - L350 were not covered by tests
}
if pageReq.IDs == nil {
pageReq.IDs = make([]uint64, 0)

Check warning on line 353 in internal/apps/dop/endpoints/iteration.go

View check run for this annotation

Codecov / codecov/patch

internal/apps/dop/endpoints/iteration.go#L352-L353

Added lines #L352 - L353 were not covered by tests
}
for _, v := range lrs {
id, err := strconv.ParseUint(v.RefID, 10, 64)
if err != nil {
logrus.Errorf("failed to parse refID for label relation %d, %v", v.ID, err)
continue

Check warning on line 359 in internal/apps/dop/endpoints/iteration.go

View check run for this annotation

Codecov / codecov/patch

internal/apps/dop/endpoints/iteration.go#L355-L359

Added lines #L355 - L359 were not covered by tests
}
pageReq.IDs = append(pageReq.IDs, id)

Check warning on line 361 in internal/apps/dop/endpoints/iteration.go

View check run for this annotation

Codecov / codecov/patch

internal/apps/dop/endpoints/iteration.go#L361

Added line #L361 was not covered by tests
}
}
// 分页查询
iterationModels, total, err := e.iteration.Paging(pageReq)
if err != nil {
return errorresp.ErrResp(err)
}
iterationMap := make(map[int64]*apistructs.Iteration, len(iterationModels))
for _, itr := range iterationModels {
iteration := itr.Convert()
iteration := itr.Convert(e.getIterationLabelDetails(itr.ID))

Check warning on line 371 in internal/apps/dop/endpoints/iteration.go

View check run for this annotation

Codecov / codecov/patch

internal/apps/dop/endpoints/iteration.go#L371

Added line #L371 was not covered by tests
iterationMap[iteration.ID] = &iteration
}
if !pageReq.WithoutIssueSummary {
Expand All @@ -324,3 +394,19 @@
List: iterations,
}, userIDs)
}

func (e *Endpoints) getIterationLabelDetails(iterationID uint64) ([]string, []apistructs.ProjectLabel) {
lrs, _ := e.db.GetLabelRelationsByRef(apistructs.LabelTypeIteration, strconv.FormatUint(iterationID, 10))
labelIDs := make([]uint64, 0, len(lrs))
for _, v := range lrs {
labelIDs = append(labelIDs, v.LabelID)
}
var labelNames []string
var labels []apistructs.ProjectLabel
labels, _ = e.bdl.ListLabelByIDs(labelIDs)
labelNames = make([]string, 0, len(labels))
for _, v := range labels {
labelNames = append(labelNames, v.Name)
}
return labelNames, labels
}
30 changes: 30 additions & 0 deletions internal/apps/dop/endpoints/iteration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/stretchr/testify/assert"

"github.com/erda-project/erda/apistructs"
"github.com/erda-project/erda/bundle"
"github.com/erda-project/erda/internal/apps/dop/dao"
"github.com/erda-project/erda/internal/apps/dop/services/iteration"
"github.com/erda-project/erda/internal/pkg/user"
Expand Down Expand Up @@ -54,7 +55,36 @@ func TestPagingIterations(t *testing.T) {
r.Header.Set("Org-ID", "1")
q := r.URL.Query()
q.Add("projectID", "1")
q.Add("labels", "area")
r.URL.RawQuery = q.Encode()
_, err := ep.PagingIterations(context.Background(), r, map[string]string{"projectID": "1"})
assert.NoError(t, err)
}

func Test_getIterationLabelDetails(t *testing.T) {
bdl := bundle.New()
db := &dao.DBClient{}
pm1 := monkey.PatchInstanceMethod(reflect.TypeOf(db), "GetLabelRelationsByRef", func(db *dao.DBClient, refType apistructs.ProjectLabelType, refID string) ([]dao.LabelRelation, error) {
return []dao.LabelRelation{
{
LabelID: 1,
},
}, nil
})
defer pm1.Unpatch()

pm2 := monkey.PatchInstanceMethod(reflect.TypeOf(bdl), "ListLabelByIDs", func(bdl *bundle.Bundle, ids []uint64) ([]apistructs.ProjectLabel, error) {
return []apistructs.ProjectLabel{
{
ID: 1,
Name: "area",
},
}, nil
})
defer pm2.Unpatch()

e := &Endpoints{bdl: bdl, db: db}
labels, labelDetails := e.getIterationLabelDetails(1)
assert.Equal(t, []string{"area"}, labels)
assert.Equal(t, int64(1), labelDetails[0].ID)
}
Loading