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
2 changes: 1 addition & 1 deletion backend/core/models/domainlayer/code/pull_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ type PullRequest struct {
MergedDate *time.Time
ClosedDate *time.Time
Type string `gorm:"type:varchar(100)"`
Component string `gorm:"type:varchar(100)"`
Component string `gorm:"type:text"`
MergeCommitSha string `gorm:"type:varchar(40)"`
HeadRef string `gorm:"type:varchar(255)"`
BaseRef string `gorm:"type:varchar(255)"`
Expand Down
2 changes: 1 addition & 1 deletion backend/core/models/domainlayer/codequality/cq_issues.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type CqIssue struct {
domainlayer.DomainEntity
Rule string `gorm:"type:varchar(255)"`
Severity string `gorm:"type:varchar(100)"`
Component string
Component string `gorm:"type:text"`
ProjectKey string `gorm:"index;type:varchar(500)"` //domain project key
Line int
Status string `gorm:"type:varchar(20)"`
Expand Down
2 changes: 1 addition & 1 deletion backend/core/models/domainlayer/ticket/incident.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ type Incident struct {
Priority string `gorm:"type:varchar(255)"`
Severity string `gorm:"type:varchar(255)"`
Urgency string `gorm:"type:varchar(255)"`
Component string `gorm:"type:varchar(255)"`
Component string `gorm:"type:text"`
OriginalProject string `gorm:"type:varchar(255)"`
Table string `gorm:"index:idx_table_scope_id;type:varchar(255)"`
ScopeId string `gorm:"index:idx_table_scope_id;type:varchar(255)"`
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
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 = (*changeIncidentComponentToText)(nil)

type changeIncidentComponentToText struct{}

func (*changeIncidentComponentToText) Up(basicRes context.BasicRes) errors.Error {
return basicRes.GetDal().ModifyColumnType("incidents", "component", "text")
}

func (*changeIncidentComponentToText) Version() uint64 {
return 20260722120001
}

func (*changeIncidentComponentToText) Name() string {
return "change incidents.component type to text"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
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 = (*changePullRequestComponentToText)(nil)

type changePullRequestComponentToText struct{}

func (*changePullRequestComponentToText) Up(basicRes context.BasicRes) errors.Error {
return basicRes.GetDal().ModifyColumnType("pull_requests", "component", "text")
}

func (*changePullRequestComponentToText) Version() uint64 {
return 20260722120000
}

func (*changePullRequestComponentToText) Name() string {
return "change pull_requests.component type to text"
}
2 changes: 2 additions & 0 deletions backend/core/models/migrationscripts/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,5 +148,7 @@ func All() []plugin.MigrationScript {
new(changeIssueComponentToText),
new(changeCqIssueCodeBlocksComponentToText),
new(addCqProjectMetricsHistory),
new(changePullRequestComponentToText),
new(changeIncidentComponentToText),
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
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 = (*changePrComponentToText)(nil)

type changePrComponentToText struct{}

func (*changePrComponentToText) Up(basicRes context.BasicRes) errors.Error {
return basicRes.GetDal().ModifyColumnType("_tool_bitbucket_pull_requests", "component", "text")
}

func (*changePrComponentToText) Version() uint64 {
return 20260722120000
}

func (*changePrComponentToText) Name() string {
return "change _tool_bitbucket_pull_requests.component type to text"
}
2 changes: 1 addition & 1 deletion backend/plugins/bitbucket/models/pr.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ type BitbucketPullRequest struct {
MergedAt *time.Time
Body string
Type string `gorm:"type:varchar(255)"`
Component string `gorm:"type:varchar(255)"`
Component string `gorm:"type:text"`
MergeCommitSha string `gorm:"type:varchar(40)"`
HeadRef string `gorm:"type:varchar(255)"`
BaseRef string `gorm:"type:varchar(255)"`
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
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 = (*changePrComponentToText)(nil)

type changePrComponentToText struct{}

func (*changePrComponentToText) Up(basicRes context.BasicRes) errors.Error {
return basicRes.GetDal().ModifyColumnType("_tool_bitbucket_server_pull_requests", "component", "text")
}

func (*changePrComponentToText) Version() uint64 {
return 20260722120000
}

func (*changePrComponentToText) Name() string {
return "change _tool_bitbucket_server_pull_requests.component type to text"
}
2 changes: 1 addition & 1 deletion backend/plugins/bitbucket_server/models/pr.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ type BitbucketServerPullRequest struct {
MergedAt *time.Time
Body string
Type string `gorm:"type:varchar(255)"`
Component string `gorm:"type:varchar(255)"`
Component string `gorm:"type:text"`
MergeCommitSha string `gorm:"type:varchar(40)"`
HeadRef string `gorm:"type:varchar(255)"`
BaseRef string `gorm:"type:varchar(255)"`
Expand Down
66 changes: 59 additions & 7 deletions backend/plugins/gh-copilot/models/enterprise_metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,13 @@ type CopilotCodeMetrics struct {

// CopilotCliMetrics contains CLI usage breakdown metrics.
type CopilotCliMetrics struct {
CliSessionCount int `json:"cliSessionCount" gorm:"comment:Number of CLI sessions"`
CliRequestCount int `json:"cliRequestCount" gorm:"comment:Number of CLI requests"`
CliPromptCount int `json:"cliPromptCount" gorm:"comment:Number of CLI prompts"`
CliOutputTokenSum int `json:"cliOutputTokenSum" gorm:"comment:Total output tokens from CLI"`
CliPromptTokenSum int `json:"cliPromptTokenSum" gorm:"comment:Total prompt tokens from CLI"`
CliSessionCount int `json:"cliSessionCount" gorm:"comment:Number of CLI sessions"`
CliRequestCount int `json:"cliRequestCount" gorm:"comment:Number of CLI requests"`
CliPromptCount int `json:"cliPromptCount" gorm:"comment:Number of CLI prompts"`
CliOutputTokenSum int `json:"cliOutputTokenSum" gorm:"comment:Total output tokens from CLI"`
CliPromptTokenSum int `json:"cliPromptTokenSum" gorm:"comment:Total prompt tokens from CLI"`
CliLastKnownVersion string `json:"cliLastKnownVersion" gorm:"type:varchar(50);comment:Last known Copilot CLI version"`
CliAvgTokensPerRequest float64 `json:"cliAvgTokensPerRequest" gorm:"comment:Average tokens consumed per CLI request"`
}

// GhCopilotEnterpriseDailyMetrics captures daily enterprise-level aggregate Copilot metrics.
Expand All @@ -59,7 +61,12 @@ type GhCopilotEnterpriseDailyMetrics struct {
ScopeId string `gorm:"primaryKey;type:varchar(255)" json:"scopeId"`
Day time.Time `gorm:"primaryKey;type:date" json:"day"`

EnterpriseId string `json:"enterpriseId" gorm:"type:varchar(100)"`
EnterpriseId string `json:"enterpriseId" gorm:"type:varchar(100)"`
// OrganizationId identifies the owning org for org-level connections/rows.
// Previously always written as "" by ExtractOrgMetrics, making org-level
// rows in this shared table unidentifiable without a join back to the
// connection/scope config.
OrganizationId string `json:"organizationId" gorm:"type:varchar(100)"`
DailyActiveUsers int `json:"dailyActiveUsers"`
WeeklyActiveUsers int `json:"weeklyActiveUsers"`
MonthlyActiveUsers int `json:"monthlyActiveUsers"`
Expand All @@ -69,6 +76,11 @@ type GhCopilotEnterpriseDailyMetrics struct {
// CLI active users
DailyActiveCliUsers int `json:"dailyActiveCliUsers" gorm:"comment:Daily active CLI users"`

// Copilot cloud agent (coding agent) active user counts
DailyActiveCopilotCloudAgentUsers int `json:"dailyActiveCopilotCloudAgentUsers" gorm:"comment:Daily active Copilot cloud/coding agent users"`
WeeklyActiveCopilotCloudAgentUsers int `json:"weeklyActiveCopilotCloudAgentUsers" gorm:"comment:Weekly active Copilot cloud/coding agent users"`
MonthlyActiveCopilotCloudAgentUsers int `json:"monthlyActiveCopilotCloudAgentUsers" gorm:"comment:Monthly active Copilot cloud/coding agent users"`

// Code review user counts
DailyActiveCopilotCodeReviewUsers int `json:"dailyActiveCopilotCodeReviewUsers"`
DailyPassiveCopilotCodeReviewUsers int `json:"dailyPassiveCopilotCodeReviewUsers"`
Expand Down Expand Up @@ -100,7 +112,11 @@ type GhCopilotEnterpriseDailyMetrics struct {
PRMedianMinToMergeCopilotReviewed float64 `json:"prMedianMinToMergeCopilotReviewed" gorm:"comment:Median min to merge Copilot-reviewed PRs"`
PRTotalCopilotSuggestions int `json:"prTotalCopilotSuggestions" gorm:"comment:Total Copilot review suggestions"`
PRTotalCopilotAppliedSuggestions int `json:"prTotalCopilotAppliedSuggestions" gorm:"comment:Total Copilot applied suggestions"`

// PRCopilotSuggestionsByCommentType is a JSON-encoded array of
// {comment_type, total_suggestions, total_applied_suggestions}, e.g. the
// split between "suggestion" and "explanation" style review comments.
PRCopilotSuggestionsByCommentType string `json:"prCopilotSuggestionsByCommentType" gorm:"type:text;comment:JSON breakdown of Copilot PR suggestions by comment type"`

CopilotActivityMetrics `mapstructure:",squash"`
CopilotCliMetrics `mapstructure:",squash"`
common.NoPKModel
Expand Down Expand Up @@ -187,3 +203,39 @@ type GhCopilotMetricsByModelFeature struct {
func (GhCopilotMetricsByModelFeature) TableName() string {
return "_tool_copilot_metrics_by_model_feature"
}

// GhCopilotMetricsByAiAdoptionPhase stores enterprise/org metrics broken down
// by AI adoption cohort (phase 0-3, see GitHub's totals_by_ai_adoption_phase).
// Unlike CopilotActivityMetrics elsewhere in this file, most of these fields
// are per-user averages within the phase rather than sums.
type GhCopilotMetricsByAiAdoptionPhase struct {
ConnectionId uint64 `gorm:"primaryKey" json:"connectionId"`
ScopeId string `gorm:"primaryKey;type:varchar(255)" json:"scopeId"`
Day time.Time `gorm:"primaryKey;type:date" json:"day"`
Phase int `gorm:"primaryKey" json:"phase"`

PhaseVersion int `json:"phaseVersion" gorm:"comment:Adoption-phase classification version, starts at 1"`
EngagedUsers int `json:"engagedUsers" gorm:"comment:Users engaged in this phase (2-day-in-28 window)"`

AvgUserInitiatedInteractionCount float64 `json:"avgUserInitiatedInteractionCount"`
AvgCodeGenerationActivityCount float64 `json:"avgCodeGenerationActivityCount"`
AvgCodeAcceptanceActivityCount float64 `json:"avgCodeAcceptanceActivityCount"`
AvgLocAddedSum float64 `json:"avgLocAddedSum"`
AvgLocDeletedSum float64 `json:"avgLocDeletedSum"`

AvgPullRequestsCreated float64 `json:"avgPullRequestsCreated"`
AvgPullRequestsMerged float64 `json:"avgPullRequestsMerged"`
AvgPullRequestsReviewed float64 `json:"avgPullRequestsReviewed"`
AvgMedianMinutesToMerge float64 `json:"avgMedianMinutesToMerge"`

AvgPullRequestsMinutesToReview float64 `json:"avgPullRequestsMinutesToReview" gorm:"comment:Added 2026-07-07"`
AvgPullRequestsReviewCycles float64 `json:"avgPullRequestsReviewCycles" gorm:"comment:Added 2026-07-07"`

TotalPullRequestsMerged int `json:"totalPullRequestsMerged" gorm:"comment:True sum (not average), added 2026-06-26"`

common.NoPKModel
}

func (GhCopilotMetricsByAiAdoptionPhase) TableName() string {
return "_tool_copilot_metrics_by_ai_adoption_phase"
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,7 @@ func All() []plugin.MigrationScript {
new(addPRFieldsToEnterpriseMetrics),
new(addOrganizationIdToUserMetrics),
new(addCopilotMetricsGaps),
new(addCopilotMetricsGapsV2),
new(addCopilot28DayReports),
}
}
4 changes: 4 additions & 0 deletions backend/plugins/gh-copilot/models/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ func GetTablesInfo() []dal.Tabler {
&GhCopilotMetricsByLanguageFeature{},
&GhCopilotMetricsByLanguageModel{},
&GhCopilotMetricsByModelFeature{},
&GhCopilotMetricsByAiAdoptionPhase{},
// User-level metrics (from enterprise user reports)
&GhCopilotUserDailyMetrics{},
&GhCopilotUserMetricsByIde{},
Expand All @@ -47,5 +48,8 @@ func GetTablesInfo() []dal.Tabler {
&GhCopilotSeat{},
// User-team mappings
&GhCopilotUserTeam{},
// 28-day rolling-window snapshots (separate cadence from the daily tables above)
&GhCopilotEnterprise28DayMetrics{},
&GhCopilotUser28DayMetrics{},
}
}
7 changes: 7 additions & 0 deletions backend/plugins/gh-copilot/models/user_metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ type GhCopilotUserDailyMetrics struct {
UsedCli bool `json:"usedCli" gorm:"comment:Whether user used Copilot CLI"`
UsedCopilotCodeReviewActive bool `json:"usedCopilotCodeReviewActive" gorm:"comment:Whether user actively used code review"`
UsedCopilotCodeReviewPassive bool `json:"usedCopilotCodeReviewPassive" gorm:"comment:Whether user passively used code review"`
UsedCopilotCodingAgent bool `json:"usedCopilotCodingAgent" gorm:"comment:Whether user used the Copilot coding agent"`
UsedCopilotCloudAgent bool `json:"usedCopilotCloudAgent" gorm:"comment:Whether user used the Copilot cloud agent"`

// AI adoption cohort classification (phase 0-3), added 2026-05-29.
AiAdoptionPhase int `json:"aiAdoptionPhase" gorm:"comment:0=no cohort,1=code-first,2=agent-first,3=multi-agent"`
AiAdoptionPhaseVersion int `json:"aiAdoptionPhaseVersion" gorm:"comment:Classification logic version, starts at 1"`


CopilotActivityMetrics `mapstructure:",squash"`
CopilotCliMetrics `mapstructure:",squash"`
Expand Down
Loading