Skip to content
Open
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
5 changes: 3 additions & 2 deletions backend/core/models/domainlayer/ticket/board_issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ import (
)

type BoardIssue struct {
BoardId string `gorm:"primaryKey;type:varchar(255)"`
IssueId string `gorm:"primaryKey;type:varchar(255)"`
BoardId string `gorm:"primaryKey;type:varchar(255)"`
IssueId string `gorm:"primaryKey;type:varchar(255)"`
ProjectName string `gorm:"primaryKey;type:varchar(255);default:''"`
common.NoPKModel
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
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/devlake/core/context"
"github.com/apache/devlake/core/errors"
"github.com/apache/devlake/helpers/migrationhelper"
)

type boardIssue20260820 struct {
ProjectName string `gorm:"primaryKey;type:varchar(255);default:''"`
}

func (boardIssue20260820) TableName() string {
return "board_issues"
}

type addProjectNameToBoardIssue struct{}

func (*addProjectNameToBoardIssue) Up(basicRes context.BasicRes) errors.Error {
return migrationhelper.AutoMigrateTables(basicRes, &boardIssue20260820{})
}

func (*addProjectNameToBoardIssue) Version() uint64 {
return 20260820000000
}

func (*addProjectNameToBoardIssue) Name() string {
return "add project_name to board_issues"
}
1 change: 1 addition & 0 deletions backend/core/models/migrationscripts/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,5 +155,6 @@ func All() []plugin.MigrationScript {
new(backfillSubProjectFromMonorepo),
new(addBlueprintIdIndexToPipelines),
new(expandDomainTextColumns),
new(addProjectNameToBoardIssue),
}
}
2 changes: 2 additions & 0 deletions backend/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ require (
gorm.io/datatypes v1.2.7
gorm.io/driver/mysql v1.6.0
gorm.io/driver/postgres v1.6.3
gorm.io/driver/sqlite v1.6.0
gorm.io/gorm v1.31.2
)

Expand Down Expand Up @@ -100,6 +101,7 @@ require (
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-sqlite3 v1.14.22 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
Expand Down
62 changes: 31 additions & 31 deletions backend/plugins/bitbucket/e2e/snapshot_tables/board_issues.csv
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
board_id,issue_id,_raw_data_params,_raw_data_table,_raw_data_id,_raw_data_remark
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:1,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,60,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:10,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,52,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:11,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,51,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:12,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,50,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:13,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,49,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:14,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,48,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:15,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,47,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:16,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,46,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:17,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,45,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:18,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,44,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:19,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,43,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:2,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,59,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:20,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,42,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:21,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,41,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:22,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,40,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:23,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,39,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:24,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,38,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:25,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,36,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:26,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,35,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:27,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,31,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:28,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,34,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:29,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,33,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:3,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,58,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:30,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,32,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:4,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,57,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:5,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,56,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:6,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,37,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:7,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,55,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:8,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,54,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:9,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,53,
board_id,issue_id,_raw_data_params,_raw_data_table,_raw_data_id,_raw_data_remark,project_name
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:1,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,60,,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:10,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,52,,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:11,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,51,,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:12,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,50,,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:13,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,49,,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:14,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,48,,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:15,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,47,,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:16,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,46,,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:17,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,45,,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:18,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,44,,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:19,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,43,,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:2,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,59,,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:20,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,42,,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:21,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,41,,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:22,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,40,,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:23,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,39,,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:24,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,38,,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:25,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,36,,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:26,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,35,,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:27,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,31,,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:28,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,34,,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:29,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,33,,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:3,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,58,,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:30,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,32,,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:4,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,57,,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:5,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,56,,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:6,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,37,,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:7,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,55,,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:8,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,54,,
bitbucket:BitbucketRepo:1:likyh/likyhphp,bitbucket:BitbucketIssue:1:likyh/likyhphp:9,"{""ConnectionId"":1,""FullName"":""likyh/likyhphp""}",_raw_bitbucket_api_issues,53,,
18 changes: 9 additions & 9 deletions backend/plugins/customize/e2e/snapshot_tables/board_issues.csv
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
board_id,issue_id,_raw_data_params,_raw_data_table,_raw_data_id,_raw_data_remark
csv-board,csv:1,,,0,
csv-board,csv:10,,,0,
csv-board,csv:11,,,0,
csv-board,csv:12,,,0,
csv-board,csv:13,,,0,
csv-board,csv:14,,,0,
csv-board2,csv:1,,,0,
csv-board2,csv:10,,,0,
board_id,issue_id,_raw_data_params,_raw_data_table,_raw_data_id,_raw_data_remark,project_name
csv-board,csv:1,,,0,,
csv-board,csv:10,,,0,,
csv-board,csv:11,,,0,,
csv-board,csv:12,,,0,,
csv-board,csv:13,,,0,,
csv-board,csv:14,,,0,,
csv-board2,csv:1,,,0,,
csv-board2,csv:10,,,0,,
39 changes: 33 additions & 6 deletions backend/plugins/dora/tasks/incident_deploy_connector.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,37 @@ type simpleCicdDeploymentCommit struct {
FinishedDate *time.Time
}

// connectIncidentInScopeClauses selects the incidents that belong to a single
// DevLake project's slice of a (possibly shared) Jira board.
//
// An incident is scoped only by scope_id (= board id), so joining it to
// project_mapping alone matches EVERY project pointing at that board. When
// several projects share a board, that leaks one project's incidents into
// another's Change Failure Rate. We therefore additionally join board_issues
// (which carries the per-project slice stamped at collection time via ExtraJQL)
// and keep only the incidents whose underlying issue was collected for this
// project. The empty/NULL board_issues.project_name fallback preserves
// pre-feature / single-project data.
func connectIncidentInScopeClauses(db dal.Dal, projectName string) []dal.Clause {
return []dal.Clause{
dal.From(`incidents i`),
dal.Join("join project_mapping pm on pm.row_id = i.scope_id and " + quoteTableColumn(db, "pm") + " = " + quoteTableColumn(db, "i")),
dal.Join(`left join board_issues bi on bi.issue_id = i.id and bi.board_id = i.scope_id`),
dal.Where(
`pm.project_name = ?
and (
bi.project_name = ?
or not exists (
select 1 from board_issues b2
where b2.board_id = i.scope_id
and b2.project_name is not null and b2.project_name <> ''
)
)`,
projectName, projectName,
),
}
}

// ConnectIncidentToDeployment will generate data to crossdomain.ProjectIncidentDeploymentRelationship.
func ConnectIncidentToDeployment(taskCtx plugin.SubTaskContext) errors.Error {
db := taskCtx.GetDal()
Expand All @@ -55,12 +86,8 @@ func ConnectIncidentToDeployment(taskCtx plugin.SubTaskContext) errors.Error {
return errors.Default.Wrap(err, "error deleting previous project_incident_deployment_relationships")
}
logger.Info("delete previous project_incident_deployment_relationships")
// select all issues belongs to the board
clauses := []dal.Clause{
dal.From(`incidents i`),
dal.Join(`left join project_mapping pm on pm.row_id = i.scope_id and pm.table = i.table`),
dal.Where("pm.project_name = ?", data.Options.ProjectName),
}
// select all incidents belonging to this project's slice of the board
clauses := connectIncidentInScopeClauses(db, data.Options.ProjectName)

//count, err := db.Count(
// dal.From(`incidents i`),
Expand Down
Loading