Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
connection_id,scope_id,year,month,day,enterprise,model,organization,user,product,cost_center_id,cost_center_name,gross_quantity,discount_quantity,net_quantity,price_per_unit,gross_amount,discount_amount,net_amount
1,octodemo,2025,12,10,octodemo,gpt-4.1,,,copilot,,,100.5,10.0,90.5,1.0,100.5,10.0,90.5
1,octodemo,2025,12,10,octodemo,gpt-4o,,,copilot,cc-eng,Engineering,50.0,5.0,45.0,1.0,50.0,5.0,45.0
1,octodemo,2025,12,10,octodemo,claude-3,,,copilot,cc-ml,Machine Learning,30.0,2.0,28.0,1.0,30.0,2.0,28.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
connection_id,scope_id,year,month,day,organization,model,user,product,gross_quantity,discount_quantity,net_quantity,price_per_unit,gross_amount,discount_amount,net_amount
1,octodemo,2025,12,10,octodemo,gpt-4.1,alice,copilot,50.0,5.0,45.0,1.0,50.0,5.0,45.0
1,octodemo,2025,12,10,octodemo,gpt-4o,bob,copilot,30.0,3.0,27.0,1.0,30.0,3.0,27.0
1,octodemo,2025,12,10,octodemo,claude-3,charlie,copilot,20.0,0.0,20.0,1.0,20.0,0.0,20.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
connection_id,scope_id,year,month,day,user,model,product,gross_quantity,discount_quantity,net_quantity,price_per_unit,gross_amount,discount_amount,net_amount
1,octodemo,2025,12,10,alice,gpt-4.1,copilot,50.0,5.0,45.0,1.0,50.0,5.0,45.0
1,octodemo,2025,12,10,alice,gpt-4o,copilot,30.0,3.0,27.0,1.0,30.0,3.0,27.0
1,octodemo,2025,12,10,bob,claude-3,copilot,20.0,2.0,18.0,1.0,20.0,2.0,18.0
56 changes: 56 additions & 0 deletions backend/plugins/gh-copilot/models/enterprise_ai_credit_usage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
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 models

import (
"github.com/apache/incubator-devlake/core/models/common"
)

// GhCopilotEnterpriseAiCreditUsage tracks AI credit consumption at the enterprise level.
// One row per time period per model per entity (user, org, or cost center).
type GhCopilotEnterpriseAiCreditUsage struct {
ConnectionId uint64 `gorm:"primaryKey" json:"connectionId"`
ScopeId string `gorm:"primaryKey;type:varchar(191)" json:"scopeId"`
Year int `gorm:"primaryKey" json:"year"`
Month int `gorm:"primaryKey" json:"month"`
Day int `gorm:"primaryKey" json:"day"`

Enterprise string `gorm:"primaryKey;type:varchar(191);comment:Enterprise slug" json:"enterprise"`
Model string `gorm:"primaryKey;type:varchar(191);comment:AI model name (e.g., gpt-4.1)" json:"model"`
Organization string `gorm:"index;type:varchar(255);comment:Organization within enterprise, if specified" json:"organization"`
User string `gorm:"index;type:varchar(255);comment:Username, if specified" json:"user"`

Product string `gorm:"type:varchar(32);comment:Product name (e.g., copilot)" json:"product"`
CostCenterId string `gorm:"index;type:varchar(255);comment:Cost center identifier" json:"costCenterId"`
CostCenterName string `gorm:"type:varchar(255);comment:Cost center display name" json:"costCenterName"`

// Credit usage breakdown
GrossQuantity float64 `json:"grossQuantity" gorm:"comment:Raw credits consumed"`
DiscountQuantity float64 `json:"discountQuantity" gorm:"comment:Credits discounted"`
NetQuantity float64 `json:"netQuantity" gorm:"comment:Credits after discount"`
PricePerUnit float64 `json:"pricePerUnit" gorm:"comment:Price per credit unit"`
GrossAmount float64 `json:"grossAmount" gorm:"comment:Gross cost before discount"`
DiscountAmount float64 `json:"discountAmount" gorm:"comment:Discount amount"`
NetAmount float64 `json:"netAmount" gorm:"comment:Net cost after discount"`

common.NoPKModel
}

func (GhCopilotEnterpriseAiCreditUsage) TableName() string {
return "_tool_copilot_enterprise_ai_credit_usage"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/*
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 (
"time"

"github.com/apache/incubator-devlake/core/context"
"github.com/apache/incubator-devlake/core/errors"
"github.com/apache/incubator-devlake/core/models/migrationscripts/archived"
"github.com/apache/incubator-devlake/helpers/migrationhelper"
)

type addAiCreditUsageMetrics struct{}

// --- Snapshot structs for migration (avoid importing models package to prevent drift) ---

type creditUsageBreakdown20260708 struct {
GrossQuantity float64
DiscountQuantity float64
NetQuantity float64
PricePerUnit float64
GrossAmount float64
DiscountAmount float64
NetAmount float64
}

type enterpriseAiCreditUsage20260708 struct {
ConnectionId uint64 `gorm:"primaryKey"`
ScopeId string `gorm:"primaryKey;type:varchar(191)"`
Year int `gorm:"primaryKey"`
Month int `gorm:"primaryKey"`
Day int `gorm:"primaryKey"`

Enterprise string `gorm:"primaryKey;type:varchar(191)"`
Model string `gorm:"primaryKey;type:varchar(191)"`
Organization string `gorm:"index;type:varchar(255)"`
User string `gorm:"index;type:varchar(255)"`

Product string `gorm:"type:varchar(32)"`
CostCenterId string `gorm:"index;type:varchar(255)"`
CostCenterName string `gorm:"type:varchar(255)"`

creditUsageBreakdown20260708 `gorm:"embedded"`
archived.NoPKModel
}

func (enterpriseAiCreditUsage20260708) TableName() string {
return "_tool_copilot_enterprise_ai_credit_usage"
}

type orgAiCreditUsage20260708 struct {
ConnectionId uint64 `gorm:"primaryKey"`
ScopeId string `gorm:"primaryKey;type:varchar(191)"`
Year int `gorm:"primaryKey"`
Month int `gorm:"primaryKey"`
Day int `gorm:"primaryKey"`

Organization string `gorm:"primaryKey;type:varchar(191)"`
Model string `gorm:"primaryKey;type:varchar(191)"`
User string `gorm:"index;type:varchar(255)"`

Product string `gorm:"type:varchar(32)"`

creditUsageBreakdown20260708 `gorm:"embedded"`
archived.NoPKModel
}

func (orgAiCreditUsage20260708) TableName() string {
return "_tool_copilot_org_ai_credit_usage"
}

type userAiCreditUsage20260708 struct {
ConnectionId uint64 `gorm:"primaryKey"`
ScopeId string `gorm:"primaryKey;type:varchar(191)"`
Year int `gorm:"primaryKey"`
Month int `gorm:"primaryKey"`
Day int `gorm:"primaryKey"`

User string `gorm:"primaryKey;type:varchar(191)"`
Model string `gorm:"primaryKey;type:varchar(191)"`

Product string `gorm:"type:varchar(32)"`

creditUsageBreakdown20260708 `gorm:"embedded"`
archived.NoPKModel
}

func (userAiCreditUsage20260708) TableName() string {
return "_tool_copilot_user_ai_credit_usage"
}

// userDailyMetrics20260708 adds AI credit, CLI and code-review columns to the existing table.
type userDailyMetrics20260708 struct {
ConnectionId uint64 `gorm:"primaryKey"`
ScopeId string `gorm:"primaryKey;type:varchar(255)"`
Day time.Time `gorm:"primaryKey;type:date"`
UserId int64 `gorm:"primaryKey"`

OrganizationId string `gorm:"type:varchar(100)"`
EnterpriseId string `gorm:"type:varchar(100)"`
UserLogin string `gorm:"type:varchar(255);index"`
UsedAgent bool
UsedChat bool
UsedCli bool `gorm:"comment:Whether user used Copilot CLI"`
UsedCopilotCodeReviewActive bool `gorm:"comment:Whether user actively used code review"`
UsedCopilotCodeReviewPassive bool `gorm:"comment:Whether user passively used code review"`
AiCreditsUsed float64 `gorm:"comment:AI credits consumed on this day"`

UserInitiatedInteractionCount int
CodeGenerationActivityCount int
CodeAcceptanceActivityCount int
LocSuggestedToAddSum int
LocSuggestedToDeleteSum int
LocAddedSum int
LocDeletedSum int

CliSessionCount int
CliRequestCount int
CliPromptCount int
CliOutputTokenSum int
CliPromptTokenSum int

archived.NoPKModel
}

func (userDailyMetrics20260708) TableName() string {
return "_tool_copilot_user_daily_metrics"
}

func (u *addAiCreditUsageMetrics) Up(basicRes context.BasicRes) errors.Error {
return migrationhelper.AutoMigrateTables(
basicRes,
&enterpriseAiCreditUsage20260708{},
&orgAiCreditUsage20260708{},
&userAiCreditUsage20260708{},
&userDailyMetrics20260708{},
)
}

func (u *addAiCreditUsageMetrics) Version() uint64 {
return 20260708000000
}

func (u *addAiCreditUsageMetrics) Name() string {
return "add AI credit usage billing tables"
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,6 @@ func All() []plugin.MigrationScript {
new(addPRFieldsToEnterpriseMetrics),
new(addOrganizationIdToUserMetrics),
new(addCopilotMetricsGaps),
new(addAiCreditUsageMetrics),
}
}
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 @@ -47,5 +47,9 @@ func GetTablesInfo() []dal.Tabler {
&GhCopilotSeat{},
// User-team mappings
&GhCopilotUserTeam{},
// AI credit usage billing (enterprise, org, user levels)
&GhCopilotEnterpriseAiCreditUsage{},
&GhCopilotOrgAiCreditUsage{},
&GhCopilotUserAiCreditUsage{},
}
}
3 changes: 3 additions & 0 deletions backend/plugins/gh-copilot/models/models_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ func TestGetTablesInfo(t *testing.T) {
(&GhCopilotUserMetricsByModelFeature{}).TableName(): false,
(&GhCopilotSeat{}).TableName(): false,
(&GhCopilotUserTeam{}).TableName(): false,
(&GhCopilotEnterpriseAiCreditUsage{}).TableName(): false,
(&GhCopilotOrgAiCreditUsage{}).TableName(): false,
(&GhCopilotUserAiCreditUsage{}).TableName(): false,
}

if len(tables) != len(expected) {
Expand Down
53 changes: 53 additions & 0 deletions backend/plugins/gh-copilot/models/org_ai_credit_usage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
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 models

import (
"github.com/apache/incubator-devlake/core/models/common"
)

// GhCopilotOrgAiCreditUsage tracks AI credit consumption at the organization level.
// One row per time period per model per user (within the organization).
type GhCopilotOrgAiCreditUsage struct {
ConnectionId uint64 `gorm:"primaryKey" json:"connectionId"`
ScopeId string `gorm:"primaryKey;type:varchar(191)" json:"scopeId"`
Year int `gorm:"primaryKey" json:"year"`
Month int `gorm:"primaryKey" json:"month"`
Day int `gorm:"primaryKey" json:"day"`

Organization string `gorm:"primaryKey;type:varchar(191);comment:Organization name" json:"organization"`
Model string `gorm:"primaryKey;type:varchar(191);comment:AI model name (e.g., gpt-4.1)" json:"model"`
User string `gorm:"index;type:varchar(255);comment:Username consuming the credits" json:"user"`

Product string `gorm:"type:varchar(32);comment:Product name (e.g., copilot)" json:"product"`

// Credit usage breakdown
GrossQuantity float64 `json:"grossQuantity" gorm:"comment:Raw credits consumed"`
DiscountQuantity float64 `json:"discountQuantity" gorm:"comment:Credits discounted"`
NetQuantity float64 `json:"netQuantity" gorm:"comment:Credits after discount"`
PricePerUnit float64 `json:"pricePerUnit" gorm:"comment:Price per credit unit"`
GrossAmount float64 `json:"grossAmount" gorm:"comment:Gross cost before discount"`
DiscountAmount float64 `json:"discountAmount" gorm:"comment:Discount amount"`
NetAmount float64 `json:"netAmount" gorm:"comment:Net cost after discount"`

common.NoPKModel
}

func (GhCopilotOrgAiCreditUsage) TableName() string {
return "_tool_copilot_org_ai_credit_usage"
}
52 changes: 52 additions & 0 deletions backend/plugins/gh-copilot/models/user_ai_credit_usage.go
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 models

import (
"github.com/apache/incubator-devlake/core/models/common"
)

// GhCopilotUserAiCreditUsage tracks AI credit consumption at the individual user level.
// One row per time period per model per authenticated user.
type GhCopilotUserAiCreditUsage struct {
ConnectionId uint64 `gorm:"primaryKey" json:"connectionId"`
ScopeId string `gorm:"primaryKey;type:varchar(191)" json:"scopeId"`
Year int `gorm:"primaryKey" json:"year"`
Month int `gorm:"primaryKey" json:"month"`
Day int `gorm:"primaryKey" json:"day"`

User string `gorm:"primaryKey;type:varchar(191);comment:GitHub username" json:"user"`
Model string `gorm:"primaryKey;type:varchar(191);comment:AI model name (e.g., gpt-4.1)" json:"model"`

Product string `gorm:"type:varchar(32);comment:Product name (e.g., copilot)" json:"product"`

// Credit usage breakdown
GrossQuantity float64 `json:"grossQuantity" gorm:"comment:Raw credits consumed"`
DiscountQuantity float64 `json:"discountQuantity" gorm:"comment:Credits discounted"`
NetQuantity float64 `json:"netQuantity" gorm:"comment:Credits after discount"`
PricePerUnit float64 `json:"pricePerUnit" gorm:"comment:Price per credit unit"`
GrossAmount float64 `json:"grossAmount" gorm:"comment:Gross cost before discount"`
DiscountAmount float64 `json:"discountAmount" gorm:"comment:Discount amount"`
NetAmount float64 `json:"netAmount" gorm:"comment:Net cost after discount"`

common.NoPKModel
}

func (GhCopilotUserAiCreditUsage) TableName() string {
return "_tool_copilot_user_ai_credit_usage"
}
17 changes: 9 additions & 8 deletions backend/plugins/gh-copilot/models/user_metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,15 @@ type GhCopilotUserDailyMetrics struct {
Day time.Time `gorm:"primaryKey;type:date" json:"day"`
UserId int64 `gorm:"primaryKey" json:"userId"`

OrganizationId string `json:"organizationId" gorm:"type:varchar(100)"`
EnterpriseId string `json:"enterpriseId" gorm:"type:varchar(100)"`
UserLogin string `json:"userLogin" gorm:"type:varchar(255);index"`
UsedAgent bool `json:"usedAgent"`
UsedChat bool `json:"usedChat"`
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"`
OrganizationId string `json:"organizationId" gorm:"type:varchar(100)"`
EnterpriseId string `json:"enterpriseId" gorm:"type:varchar(100)"`
UserLogin string `json:"userLogin" gorm:"type:varchar(255);index"`
UsedAgent bool `json:"usedAgent"`
UsedChat bool `json:"usedChat"`
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"`
AiCreditsUsed float64 `json:"aiCreditsUsed" gorm:"comment:AI credits consumed on this day"`

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