Skip to content
Draft
Show file tree
Hide file tree
Changes from 3 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
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ type ProjectPrMetric struct {
PrCreatedDate *time.Time
PrMergedDate *time.Time
PrDeployedDate *time.Time

IsAuthoredByBot bool
}

func (ProjectPrMetric) TableName() string {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
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 = (*addDateFieldsToProjectPrMetric)(nil)

type projectPrMetric20250617 struct {
IsAuthoredByBot bool
}

func (projectPrMetric20250617) TableName() string {
return "project_pr_metrics"
}

type addIsAuthoredByBotToProjectPrMetric struct{}

func (*addIsAuthoredByBotToProjectPrMetric) Up(basicRes context.BasicRes) errors.Error {
db := basicRes.GetDal()
if err := db.AutoMigrate(&projectPrMetric20250617{}); err != nil {
return err
}
return nil
}

func (*addIsAuthoredByBotToProjectPrMetric) Version() uint64 {
return 20250617123431
}

func (*addIsAuthoredByBotToProjectPrMetric) Name() string {
return "add is_authored_by_bot to project_pr_metrics according to #8381"
}
1 change: 1 addition & 0 deletions backend/core/models/migrationscripts/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,5 +138,6 @@ func All() []plugin.MigrationScript {
new(createQaTables),
new(increaseCqIssueComponentLength),
new(extendFieldSizeForCq),
new(addIsAuthoredByBotToProjectPrMetric),
}
}
3 changes: 3 additions & 0 deletions backend/plugins/dora/e2e/calculate_change_lead_time_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ func TestCalculateCLTimeDataFlow(t *testing.T) {
var plugin impl.Dora
dataflowTester := e2ehelper.NewDataFlowTester(t, "dora", plugin)

t.Setenv("ENABLE_BOT_FILTERING", "true")
Copy link
Member Author

Choose a reason for hiding this comment

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

The feature is supposed to be be opt-in, thus by default these 2 variables are not set and the whole filtering is skipped.

I'm setting these env vars in the test to be able to test it in the integration tests, but I'm not sure if that's the best way to test it.

t.Setenv("BOT_FILTERING_PATTERN", ".*Renovate|Dependabot.*")

taskData := &tasks.DoraTaskData{
Options: &tasks.DoraOptions{
ProjectName: "project1",
Expand Down
14 changes: 7 additions & 7 deletions backend/plugins/dora/e2e/change_lead_time/project_pr_metrics.csv
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
id,project_name,first_commit_sha,pr_coding_time,first_review_id,pr_pickup_time,pr_review_time,deployment_commit_id,pr_deploy_time,pr_cycle_time,first_commit_authored_date,first_comment_date,pr_created_date,pr_merged_date,pr_deployed_date
pr0,project1,pr0_commit0,1440,,,,,,44640,2022-01-10T04:51:47.000+00:00,,2022-01-11T04:51:47.000+00:00,2022-02-10T04:51:47.000+00:00,
pr1,project1,08d2f2b6de0fa8de4d0e2b55b4b9a2e244214029,1440,comment02,5,55,5,2978,4478,2023-04-10T04:51:47.000+00:00,2023-04-11T04:56:47.000+00:00,2023-04-11T04:51:47.000+00:00,2023-04-11T05:51:47.000+00:00,2023-04-13T07:29:14.000+00:00
pr2,project1,2537845559d8db99e9cda6190f32b50ec979c722,,comment04,1,60,5,1538,1598,2023-04-13T04:51:47.000+00:00,2023-04-12T04:51:49.000+00:00,2023-04-12T04:51:47.000+00:00,2023-04-12T05:51:47.000+00:00,2023-04-13T07:29:14.000+00:00
pr3,project1,55f445997abbd5918da59d202d28762cd56fbd44,5883,comment07,,5760,6,,10203,2023-04-07T04:51:47.000+00:00,2023-04-10T06:53:51.000+00:00,2023-04-11T06:53:51.000+00:00,2023-04-14T06:53:51.000+00:00,2023-04-13T07:30:34.000+00:00
pr4,project1,5ad0c09c447c19338f1dfbb65d89a3728962b3b7,11704,comment10,1500,,,,11764,2023-04-05T04:51:47.000+00:00,2023-04-14T08:55:01.000+00:00,2023-04-13T07:55:01.000+00:00,2023-04-13T08:55:01.000+00:00,
pr5,project1,62535543802631a0d3daf0b0b78c6a7e05e508fb,13144,comment12,,313068,,,13204,2023-04-04T04:51:47.000+00:00,2022-09-07T23:07:13.000+00:00,2023-04-13T07:55:01.000+00:00,2023-04-13T08:55:01.000+00:00,
id,project_name,first_commit_sha,pr_coding_time,first_review_id,pr_pickup_time,pr_review_time,deployment_commit_id,pr_deploy_time,pr_cycle_time,first_commit_authored_date,first_comment_date,pr_created_date,pr_merged_date,pr_deployed_date,is_authored_by_bot
pr0,project1,pr0_commit0,1440,,,,,,44640,2022-01-10T04:51:47.000+00:00,,2022-01-11T04:51:47.000+00:00,2022-02-10T04:51:47.000+00:00,,0
pr1,project1,08d2f2b6de0fa8de4d0e2b55b4b9a2e244214029,1440,comment02,5,55,5,2978,4478,2023-04-10T04:51:47.000+00:00,2023-04-11T04:56:47.000+00:00,2023-04-11T04:51:47.000+00:00,2023-04-11T05:51:47.000+00:00,2023-04-13T07:29:14.000+00:00,0
pr2,project1,2537845559d8db99e9cda6190f32b50ec979c722,,comment04,1,60,5,1538,1598,2023-04-13T04:51:47.000+00:00,2023-04-12T04:51:49.000+00:00,2023-04-12T04:51:47.000+00:00,2023-04-12T05:51:47.000+00:00,2023-04-13T07:29:14.000+00:00,1
pr3,project1,55f445997abbd5918da59d202d28762cd56fbd44,5883,comment07,,5760,6,,10203,2023-04-07T04:51:47.000+00:00,2023-04-10T06:53:51.000+00:00,2023-04-11T06:53:51.000+00:00,2023-04-14T06:53:51.000+00:00,2023-04-13T07:30:34.000+00:00,1
pr4,project1,5ad0c09c447c19338f1dfbb65d89a3728962b3b7,11704,comment10,1500,,,,11764,2023-04-05T04:51:47.000+00:00,2023-04-14T08:55:01.000+00:00,2023-04-13T07:55:01.000+00:00,2023-04-13T08:55:01.000+00:00,,0
pr5,project1,62535543802631a0d3daf0b0b78c6a7e05e508fb,13144,comment12,,313068,,,13204,2023-04-04T04:51:47.000+00:00,2022-09-07T23:07:13.000+00:00,2023-04-13T07:55:01.000+00:00,2023-04-13T08:55:01.000+00:00,,0
16 changes: 8 additions & 8 deletions backend/plugins/dora/e2e/change_lead_time/pull_requests.csv
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
id,base_repo_id,author_id,merge_commit_sha,created_date,merged_date,_raw_data_remark,base_commit_sha,head_commit_sha
pr0,repo1,a,pr_merge_commit0,2022-1-11 4:51:47,2022-2-10 4:51:47,deployment_commit 0,,
pr1,repo1,a,pr_merge_commit1,2023-4-11 4:51:47,2023-4-11 5:51:47,deployment_commit 5,,
pr2,repo1,a,pr_merge_commit2,2023-4-12 4:51:47,2023-4-12 5:51:47,deployment_commit 5,,
pr3,repo1,a,pr_merge_commit3,2023-4-11 6:53:51,2023-4-14 6:53:51,deployment_commit 6,,
pr4,repo1,,pr_merge_commit4,2023-4-13 7:55:01,2023-4-13 8:55:01,,,
pr5,repo1,,pr_merge_commit5,2023-4-13 7:55:01,2023-4-13 8:55:01,,,
pr6,repo1,,pr_merge_commit6,2023-4-13 7:55:01,,,,
id,base_repo_id,author_id,author_name,merge_commit_sha,created_date,merged_date,_raw_data_remark,base_commit_sha,head_commit_sha
pr0,repo1,a,John Doe,pr_merge_commit0,2022-1-11 4:51:47,2022-2-10 4:51:47,deployment_commit 0,,
pr1,repo1,a,John Doe,pr_merge_commit1,2023-4-11 4:51:47,2023-4-11 5:51:47,deployment_commit 5,,
pr2,repo1,a,Renovate,pr_merge_commit2,2023-4-12 4:51:47,2023-4-12 5:51:47,deployment_commit 5,,
pr3,repo1,a,Dependabot,pr_merge_commit3,2023-4-11 6:53:51,2023-4-14 6:53:51,deployment_commit 6,,
pr4,repo1,,,pr_merge_commit4,2023-4-13 7:55:01,2023-4-13 8:55:01,,,
pr5,repo1,,,pr_merge_commit5,2023-4-13 7:55:01,2023-4-13 8:55:01,,,
pr6,repo1,,,pr_merge_commit6,2023-4-13 7:55:01,,,,
28 changes: 27 additions & 1 deletion backend/plugins/dora/tasks/change_lead_time_calculator.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ package tasks
import (
"math"
"reflect"
"regexp"
"time"

"github.com/apache/incubator-devlake/core/config"
"github.com/apache/incubator-devlake/core/dal"
"github.com/apache/incubator-devlake/core/errors"
"github.com/apache/incubator-devlake/core/models/domainlayer/code"
Expand Down Expand Up @@ -52,9 +54,25 @@ func CalculateChangeLeadTime(taskCtx plugin.SubTaskContext) errors.Error {
return errors.Default.Wrap(err, "error deleting previous project_pr_metrics")
}

// Get env vars
cfg := config.GetConfig()
enableBotFiltering := cfg.GetBool("ENABLE_BOT_FILTERING")
botFilteringPattern := cfg.GetString("BOT_FILTERING_PATTERN")

// Precompile bot filtering regex if enabled and pattern is set
var botFilteringRegex *regexp.Regexp
if enableBotFiltering && botFilteringPattern != "" {
var err error
botFilteringRegex, err = regexp.Compile(botFilteringPattern)
if err != nil {
logger.Warn(err, "Invalid bot filtering pattern: %s", botFilteringPattern)
botFilteringRegex = nil
}
}

// Get pull requests by repo project_name
var clauses = []dal.Clause{
dal.Select("pr.id, pr.pull_request_key, pr.author_id, pr.merge_commit_sha, pr.created_date, pr.merged_date"),
dal.Select("pr.id, pr.pull_request_key, pr.author_id, pr.author_name, pr.merge_commit_sha, pr.created_date, pr.merged_date"),
dal.From("pull_requests pr"),
dal.Join(`LEFT JOIN project_mapping pm ON (pm.row_id = pr.base_repo_id)`),
dal.Where("pr.merged_date IS NOT NULL AND pm.project_name = ? AND pm.table = 'repos'", data.Options.ProjectName),
Expand Down Expand Up @@ -95,6 +113,7 @@ func CalculateChangeLeadTime(taskCtx plugin.SubTaskContext) errors.Error {
projectPrMetric.FirstCommitSha = firstCommit.CommitSha
projectPrMetric.FirstCommitAuthoredDate = &firstCommit.CommitAuthoredDate
}
projectPrMetric.IsAuthoredByBot = matchesBotFilter(botFilteringRegex, pr.AuthorName)

// Get the first review for the PR
firstReview, err := getFirstReview(pr.Id, pr.AuthorId, db)
Expand Down Expand Up @@ -244,3 +263,10 @@ func computeTimeSpan(start, end *time.Time) *int64 {
}
return &minutes
}

func matchesBotFilter(botFilterRegex *regexp.Regexp, name string) bool {
if botFilterRegex == nil {
return false
}
return botFilterRegex.MatchString(name)
}
8 changes: 7 additions & 1 deletion env.example
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,10 @@ SKIP_COMMIT_FILES=true
WRAP_RESPONSE_ERROR=

# Enable subtasks by default: plugin_name:subtask_name:enabled
ENABLE_SUBTASKS_BY_DEFAULT="jira:collectIssueChangelogs:true,jira:extractIssueChangelogs:true,jira:convertIssueChangelogs:true,tapd:collectBugChangelogs:true,tapd:extractBugChangelogs:true,tapd:convertBugChangelogs:true,zentao:collectBugRepoCommits:true,zentao:extractBugRepoCommits:true,zentao:convertBugRepoCommits:true,zentao:collectStoryRepoCommits:true,zentao:extractStoryRepoCommits:true,zentao:convertStoryRepoCommits:true,zentao:collectTaskRepoCommits:true,zentao:extractTaskRepoCommits:true,zentao:convertTaskRepoCommits:true"
ENABLE_SUBTASKS_BY_DEFAULT="jira:collectIssueChangelogs:true,jira:extractIssueChangelogs:true,jira:convertIssueChangelogs:true,tapd:collectBugChangelogs:true,tapd:extractBugChangelogs:true,tapd:convertBugChangelogs:true,zentao:collectBugRepoCommits:true,zentao:extractBugRepoCommits:true,zentao:convertBugRepoCommits:true,zentao:collectStoryRepoCommits:true,zentao:extractStoryRepoCommits:true,zentao:convertStoryRepoCommits:true,zentao:collectTaskRepoCommits:true,zentao:extractTaskRepoCommits:true,zentao:convertTaskRepoCommits:true"

# Enable filtering of bot-authored changes in DORA metrics (e.g., to exclude commits from Renovate, Dependabot)
ENABLE_BOT_FILTERING=

# Regex pattern to identify bot users by display name or username in DORA plugin
BOT_FILTERING_PATTERN=
Loading