Skip to content

Commit ab9ea5d

Browse files
committed
feat: add ConvertQDevUserMetrics
1 parent 6ebaf9b commit ab9ea5d

2 files changed

Lines changed: 200 additions & 0 deletions

File tree

backend/plugins/q_dev/impl/impl.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ func (p QDev) SubTaskMetas() []plugin.SubTaskMeta {
8181
return []plugin.SubTaskMeta{
8282
tasks.CollectQDevS3FilesMeta,
8383
tasks.ExtractQDevS3DataMeta,
84+
tasks.ConvertQDevUserMetricsMeta,
8485
}
8586
}
8687

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
/*
2+
Licensed to the Apache Software Foundation (ASF) under one or more
3+
contributor license agreements. See the NOTICE file distributed with
4+
this work for additional information regarding copyright ownership.
5+
The ASF licenses this file to You under the Apache License, Version 2.0
6+
(the "License"); you may not use this file except in compliance with
7+
the License. You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
*/
17+
18+
package tasks
19+
20+
import (
21+
"github.com/apache/incubator-devlake/core/dal"
22+
"github.com/apache/incubator-devlake/core/errors"
23+
"github.com/apache/incubator-devlake/core/plugin"
24+
"github.com/apache/incubator-devlake/plugins/q_dev/models"
25+
"math"
26+
"time"
27+
)
28+
29+
var _ plugin.SubTaskEntryPoint = ConvertQDevUserMetrics
30+
31+
// ConvertQDevUserMetrics 按用户聚合指标
32+
func ConvertQDevUserMetrics(taskCtx plugin.SubTaskContext) errors.Error {
33+
data := taskCtx.GetData().(*QDevTaskData)
34+
db := taskCtx.GetDal()
35+
36+
// 清空之前聚合的数据
37+
clauses := []dal.Clause{
38+
dal.Where("connection_id = ?", data.Options.ConnectionId),
39+
}
40+
err := db.Delete(&models.QDevUserMetrics{}, clauses...)
41+
if err != nil {
42+
return errors.Default.Wrap(err, "failed to delete previous user metrics")
43+
}
44+
45+
// 聚合数据
46+
userDataMap := make(map[string]*UserMetricsAggregation)
47+
48+
cursor, err := db.Cursor(
49+
dal.From(&models.QDevUserData{}),
50+
dal.Where("connection_id = ?", data.Options.ConnectionId),
51+
)
52+
if err != nil {
53+
return errors.Default.Wrap(err, "failed to get user data cursor")
54+
}
55+
defer cursor.Close()
56+
57+
taskCtx.SetProgress(0, -1)
58+
59+
// 汇总每个用户的数据
60+
for cursor.Next() {
61+
userData := &models.QDevUserData{}
62+
err = db.Fetch(cursor, userData)
63+
if err != nil {
64+
return errors.Default.Wrap(err, "failed to fetch user data")
65+
}
66+
67+
// 获取或创建用户聚合
68+
aggregation, ok := userDataMap[userData.UserId]
69+
if !ok {
70+
aggregation = &UserMetricsAggregation{
71+
ConnectionId: userData.ConnectionId,
72+
UserId: userData.UserId,
73+
FirstDate: userData.Date,
74+
LastDate: userData.Date,
75+
DataCount: 0,
76+
}
77+
userDataMap[userData.UserId] = aggregation
78+
}
79+
80+
// 更新日期范围
81+
if userData.Date.Before(aggregation.FirstDate) {
82+
aggregation.FirstDate = userData.Date
83+
}
84+
if userData.Date.After(aggregation.LastDate) {
85+
aggregation.LastDate = userData.Date
86+
}
87+
88+
// 累加指标
89+
aggregation.DataCount++
90+
aggregation.TotalCodeReview_FindingsCount += userData.CodeReview_FindingsCount
91+
aggregation.TotalCodeReview_SucceededEventCount += userData.CodeReview_SucceededEventCount
92+
aggregation.TotalInlineChat_AcceptanceEventCount += userData.InlineChat_AcceptanceEventCount
93+
aggregation.TotalInlineChat_AcceptedLineAdditions += userData.InlineChat_AcceptedLineAdditions
94+
aggregation.TotalInlineChat_AcceptedLineDeletions += userData.InlineChat_AcceptedLineDeletions
95+
aggregation.TotalInlineChat_DismissalEventCount += userData.InlineChat_DismissalEventCount
96+
aggregation.TotalInlineChat_DismissedLineAdditions += userData.InlineChat_DismissedLineAdditions
97+
aggregation.TotalInlineChat_DismissedLineDeletions += userData.InlineChat_DismissedLineDeletions
98+
aggregation.TotalInlineChat_RejectedLineAdditions += userData.InlineChat_RejectedLineAdditions
99+
aggregation.TotalInlineChat_RejectedLineDeletions += userData.InlineChat_RejectedLineDeletions
100+
aggregation.TotalInlineChat_RejectionEventCount += userData.InlineChat_RejectionEventCount
101+
aggregation.TotalInlineChat_TotalEventCount += userData.InlineChat_TotalEventCount
102+
aggregation.TotalInline_AICodeLines += userData.Inline_AICodeLines
103+
aggregation.TotalInline_AcceptanceCount += userData.Inline_AcceptanceCount
104+
aggregation.TotalInline_SuggestionsCount += userData.Inline_SuggestionsCount
105+
}
106+
107+
// 计算每个用户的平均指标和总天数
108+
for _, aggregation := range userDataMap {
109+
// 创建指标记录
110+
metrics := &models.QDevUserMetrics{
111+
ConnectionId: aggregation.ConnectionId,
112+
UserId: aggregation.UserId,
113+
FirstDate: aggregation.FirstDate,
114+
LastDate: aggregation.LastDate,
115+
}
116+
117+
// 计算总天数
118+
metrics.TotalDays = int(math.Round(aggregation.LastDate.Sub(aggregation.FirstDate).Hours()/24)) + 1
119+
120+
// 设置总计指标
121+
metrics.TotalCodeReview_FindingsCount = aggregation.TotalCodeReview_FindingsCount
122+
metrics.TotalCodeReview_SucceededEventCount = aggregation.TotalCodeReview_SucceededEventCount
123+
metrics.TotalInlineChat_AcceptanceEventCount = aggregation.TotalInlineChat_AcceptanceEventCount
124+
metrics.TotalInlineChat_AcceptedLineAdditions = aggregation.TotalInlineChat_AcceptedLineAdditions
125+
metrics.TotalInlineChat_AcceptedLineDeletions = aggregation.TotalInlineChat_AcceptedLineDeletions
126+
metrics.TotalInlineChat_DismissalEventCount = aggregation.TotalInlineChat_DismissalEventCount
127+
metrics.TotalInlineChat_DismissedLineAdditions = aggregation.TotalInlineChat_DismissedLineAdditions
128+
metrics.TotalInlineChat_DismissedLineDeletions = aggregation.TotalInlineChat_DismissedLineDeletions
129+
metrics.TotalInlineChat_RejectedLineAdditions = aggregation.TotalInlineChat_RejectedLineAdditions
130+
metrics.TotalInlineChat_RejectedLineDeletions = aggregation.TotalInlineChat_RejectedLineDeletions
131+
metrics.TotalInlineChat_RejectionEventCount = aggregation.TotalInlineChat_RejectionEventCount
132+
metrics.TotalInlineChat_TotalEventCount = aggregation.TotalInlineChat_TotalEventCount
133+
metrics.TotalInline_AICodeLines = aggregation.TotalInline_AICodeLines
134+
metrics.TotalInline_AcceptanceCount = aggregation.TotalInline_AcceptanceCount
135+
metrics.TotalInline_SuggestionsCount = aggregation.TotalInline_SuggestionsCount
136+
137+
// 计算平均值指标
138+
if metrics.TotalDays > 0 {
139+
metrics.AvgCodeReview_FindingsCount = float64(aggregation.TotalCodeReview_FindingsCount) / float64(metrics.TotalDays)
140+
metrics.AvgCodeReview_SucceededEventCount = float64(aggregation.TotalCodeReview_SucceededEventCount) / float64(metrics.TotalDays)
141+
metrics.AvgInlineChat_AcceptanceEventCount = float64(aggregation.TotalInlineChat_AcceptanceEventCount) / float64(metrics.TotalDays)
142+
metrics.AvgInlineChat_TotalEventCount = float64(aggregation.TotalInlineChat_TotalEventCount) / float64(metrics.TotalDays)
143+
metrics.AvgInline_AICodeLines = float64(aggregation.TotalInline_AICodeLines) / float64(metrics.TotalDays)
144+
metrics.AvgInline_AcceptanceCount = float64(aggregation.TotalInline_AcceptanceCount) / float64(metrics.TotalDays)
145+
metrics.AvgInline_SuggestionsCount = float64(aggregation.TotalInline_SuggestionsCount) / float64(metrics.TotalDays)
146+
}
147+
148+
// 计算接受率
149+
totalEvents := aggregation.TotalInlineChat_AcceptanceEventCount +
150+
aggregation.TotalInlineChat_DismissalEventCount +
151+
aggregation.TotalInlineChat_RejectionEventCount
152+
153+
if totalEvents > 0 {
154+
metrics.AcceptanceRate = float64(aggregation.TotalInlineChat_AcceptanceEventCount) / float64(totalEvents)
155+
}
156+
157+
// 存储聚合指标
158+
err = db.Create(metrics)
159+
if err != nil {
160+
return errors.Default.Wrap(err, "failed to create user metrics")
161+
}
162+
163+
taskCtx.IncProgress(1)
164+
}
165+
166+
return nil
167+
}
168+
169+
// UserMetricsAggregation 聚合过程中用于保存用户指标的结构
170+
type UserMetricsAggregation struct {
171+
ConnectionId uint64
172+
UserId string
173+
FirstDate time.Time
174+
LastDate time.Time
175+
DataCount int
176+
TotalCodeReview_FindingsCount int
177+
TotalCodeReview_SucceededEventCount int
178+
TotalInlineChat_AcceptanceEventCount int
179+
TotalInlineChat_AcceptedLineAdditions int
180+
TotalInlineChat_AcceptedLineDeletions int
181+
TotalInlineChat_DismissalEventCount int
182+
TotalInlineChat_DismissedLineAdditions int
183+
TotalInlineChat_DismissedLineDeletions int
184+
TotalInlineChat_RejectedLineAdditions int
185+
TotalInlineChat_RejectedLineDeletions int
186+
TotalInlineChat_RejectionEventCount int
187+
TotalInlineChat_TotalEventCount int
188+
TotalInline_AICodeLines int
189+
TotalInline_AcceptanceCount int
190+
TotalInline_SuggestionsCount int
191+
}
192+
193+
var ConvertQDevUserMetricsMeta = plugin.SubTaskMeta{
194+
Name: "convertQDevUserMetrics",
195+
EntryPoint: ConvertQDevUserMetrics,
196+
EnabledByDefault: true,
197+
Description: "Convert user data to metrics by each user",
198+
DomainTypes: []string{plugin.DOMAIN_TYPE_CROSS},
199+
}

0 commit comments

Comments
 (0)