diff --git a/backend/plugins/gitlab/models/migrationscripts/add_additions_deletions_to_mr.go b/backend/plugins/gitlab/models/migrationscripts/add_additions_deletions_to_mr.go new file mode 100644 index 00000000000..f59b662f3c7 --- /dev/null +++ b/backend/plugins/gitlab/models/migrationscripts/add_additions_deletions_to_mr.go @@ -0,0 +1,49 @@ +/* +Licensed to the Apache Software Foundation (ASF) under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The ASF licenses this file to You 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 migrationscripts + +import ( + "github.com/apache/incubator-devlake/core/context" + "github.com/apache/incubator-devlake/core/errors" + "github.com/apache/incubator-devlake/core/plugin" +) + +var _ plugin.MigrationScript = (*addAdditionsDeletionsToMr)(nil) + +type mrAdditionsDeletions struct { + Additions *int + Deletions *int +} + +func (mrAdditionsDeletions) TableName() string { + return "_tool_gitlab_merge_requests" +} + +type addAdditionsDeletionsToMr struct{} + +func (*addAdditionsDeletionsToMr) Up(basicRes context.BasicRes) errors.Error { + return errors.Convert(basicRes.GetDal().AutoMigrate(&mrAdditionsDeletions{})) +} + +func (*addAdditionsDeletionsToMr) Version() uint64 { + return 20260615000001 +} + +func (*addAdditionsDeletionsToMr) Name() string { + return "gitlab: add additions and deletions to merge requests" +} diff --git a/backend/plugins/gitlab/models/migrationscripts/register.go b/backend/plugins/gitlab/models/migrationscripts/register.go index 30a76f63ed9..e684c953064 100644 --- a/backend/plugins/gitlab/models/migrationscripts/register.go +++ b/backend/plugins/gitlab/models/migrationscripts/register.go @@ -53,5 +53,6 @@ func All() []plugin.MigrationScript { new(changeIssueComponentType), new(addIsChildToPipelines240906), new(addPrSizeExcludedFileExtensions), + new(addAdditionsDeletionsToMr), } } diff --git a/backend/plugins/gitlab/models/mr.go b/backend/plugins/gitlab/models/mr.go index c25df4ba07f..4d8e63ec5a6 100644 --- a/backend/plugins/gitlab/models/mr.go +++ b/backend/plugins/gitlab/models/mr.go @@ -51,6 +51,8 @@ type GitlabMergeRequest struct { AuthorUsername string `gorm:"type:varchar(255)"` AuthorUserId int Component string `gorm:"type:varchar(255)"` + Additions *int `gorm:"comment:Lines added in this MR diff only"` + Deletions *int `gorm:"comment:Lines deleted in this MR diff only"` common.NoPKModel } diff --git a/backend/plugins/gitlab/tasks/mr_detail_collector.go b/backend/plugins/gitlab/tasks/mr_detail_collector.go index bfb64f031b5..d20e96a1ec9 100644 --- a/backend/plugins/gitlab/tasks/mr_detail_collector.go +++ b/backend/plugins/gitlab/tasks/mr_detail_collector.go @@ -62,6 +62,7 @@ func CollectApiMergeRequestDetails(taskCtx plugin.SubTaskContext) errors.Error { Query: func(reqData *helper.RequestData) (url.Values, errors.Error) { query := url.Values{} query.Set("with_stats", "true") + query.Set("include_diff_stats", "true") return query, nil }, ResponseParser: GetOneRawMessageFromResponse, diff --git a/backend/plugins/gitlab/tasks/mr_extractor.go b/backend/plugins/gitlab/tasks/mr_extractor.go index 3a8457b0cf0..e20dd8bbdfa 100644 --- a/backend/plugins/gitlab/tasks/mr_extractor.go +++ b/backend/plugins/gitlab/tasks/mr_extractor.go @@ -19,6 +19,7 @@ package tasks import ( "regexp" + "strconv" "strings" "github.com/apache/incubator-devlake/core/dal" @@ -65,6 +66,11 @@ type MergeRequestRes struct { Assignees []Assignee FirstCommentTime common.Iso8601Time Labels []string `json:"labels"` + DiffStats *struct { + Additions int `json:"additions"` + Deletions int `json:"deletions"` + } `json:"diff_stats"` + ChangesCount string `json:"changes_count"` } type Reviewer struct { @@ -246,6 +252,20 @@ func convertMergeRequest(mr *MergeRequestRes) (*models.GitlabMergeRequest, error AuthorUsername: mr.Author.Username, AuthorUserId: mr.Author.Id, } + // Use diff_stats when available (GitLab 13.0+); fall back to changes_count + // for older self-managed instances that don't support include_diff_stats + if mr.DiffStats != nil { + additions := mr.DiffStats.Additions + deletions := mr.DiffStats.Deletions + gitlabMergeRequest.Additions = &additions + gitlabMergeRequest.Deletions = &deletions + } else if mr.ChangesCount != "" && mr.ChangesCount != "0" { + count, err := strconv.Atoi(mr.ChangesCount) + if err == nil { + // changes_count is cumulative (bug source), but better than zero + gitlabMergeRequest.Additions = &count + } + } return gitlabMergeRequest, nil }