Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
204e784
feat: added claude cursor codex plugins and dashboards
irfanuddinahmad Mar 31, 2026
f1d8d4d
fix: updated claude dashboard to use unified ai_activities
irfanuddinahmad Apr 1, 2026
948f57f
fix: fixed license header
irfanuddinahmad Apr 1, 2026
75d201e
fix: fixed tests
irfanuddinahmad Apr 1, 2026
9d114c9
fix: fixed type filters
irfanuddinahmad Apr 1, 2026
262daaf
fix: fixed pipelines
irfanuddinahmad Apr 2, 2026
c0e5e4d
fix: fixed lint issues
irfanuddinahmad Apr 2, 2026
f8e8c49
fix: fixed migrations
irfanuddinahmad Apr 2, 2026
610a674
fix: fixed fetch time limit
irfanuddinahmad Apr 2, 2026
674f25c
feat: added user project mapping dashboard
irfanuddinahmad Apr 3, 2026
3ea028d
fix: fixed collector
irfanuddinahmad Apr 3, 2026
26b0d1e
fix: fixed collector for 30 day window
irfanuddinahmad Apr 3, 2026
6e9f659
feat: added token usage dashboard
irfanuddinahmad Apr 6, 2026
2994d0d
fix: fixed token usage dashboard
irfanuddinahmad Apr 6, 2026
3305078
fix: fixed developer output chart
irfanuddinahmad Apr 6, 2026
b1c6a4a
feat: added hubspot and notion plugins
irfanuddinahmad Apr 7, 2026
5b1025f
feat: added tests
irfanuddinahmad Apr 7, 2026
73db246
fix: fixed plugin issues
irfanuddinahmad Apr 7, 2026
f9db493
feat: align activity collection with available CRM object scopes
irfanuddinahmad Apr 9, 2026
0aeb9bc
fix: add missing test-connection API routes
irfanuddinahmad Apr 9, 2026
0087768
fix: add data scope api routes
irfanuddinahmad Apr 9, 2026
462f818
fix: add data scope api routes
irfanuddinahmad Apr 9, 2026
583375e
fix: fixed hubspot and notion blueprints
irfanuddinahmad Apr 9, 2026
8970477
fix: fixed collector for hubspot
irfanuddinahmad Apr 10, 2026
51ca706
fix: fixed tests
irfanuddinahmad Apr 10, 2026
1463d6a
fix: fix pie charts using proven Gitlab dashboard config
irfanuddinahmad Apr 14, 2026
e6e86d3
feat: distinguish created vs edited action types in extractor
irfanuddinahmad Apr 14, 2026
9103745
feat(notion): collect workspace users and resolve UUIDs to display names
irfanuddinahmad Apr 14, 2026
f9e6e56
fix(hubspot): stabilize search pagination with fixed upper time bound
irfanuddinahmad Apr 15, 2026
2043cac
fix(hubspot): stop gracefully at search pagination ceiling
irfanuddinahmad Apr 15, 2026
97cb3be
fix: fixed hubspot large data collection issue
irfanuddinahmad Apr 15, 2026
e2132f5
fix: fixed user mapping for hubspot and notion
irfanuddinahmad Apr 15, 2026
0f5751b
fix: fixed hubspot-notion dashboard
irfanuddinahmad Apr 16, 2026
791c665
fix: fixed claude test connection url
irfanuddinahmad Apr 20, 2026
bb96ce0
feat: Added agent collaboration quality dashboard
irfanuddinahmad Apr 21, 2026
4a9a550
feat(grafana): add draft PR statistics to GitHub dashboard
aimanmuzaffar95 Apr 28, 2026
6f58365
feat(grafana): add draft PR statistics to GitHub dashboard (#5)
aimanmuzaffar95 Apr 29, 2026
268a727
feat(plane): add connection API and related functionality (Phase 1)
aimanmuzaffar95 Apr 16, 2026
41c1a6e
feat(plane): add Plane plugin integration with connection fields and …
aimanmuzaffar95 Apr 16, 2026
a0b0f2d
feat(plane): implement project collection, extraction, and conversion…
aimanmuzaffar95 Apr 17, 2026
d09d78e
feat(plane): add models and tasks for Plane integration (Phase 4) (#3)
aimanmuzaffar95 Apr 20, 2026
2be16c8
feat(plane): enhance work item collection and conversion with paginat…
aimanmuzaffar95 Apr 20, 2026
791a265
feat(plane): implement epic support including data models, sync logic…
aimanmuzaffar95 Apr 21, 2026
1ae1261
feat(plane): add grafana dashboard for Plane and estimate point handl…
aimanmuzaffar95 Apr 23, 2026
982506e
feat: add estimate point functionality to Plane plugin (#7)
aimanmuzaffar95 Apr 23, 2026
94fcab7
fix: update Plane dashboard metrics and integrate include users in wo…
aimanmuzaffar95 Apr 27, 2026
43d0f0b
fix: resolve migration-script-lint and golangci-lint failures in Plan…
aimanmuzaffar95 Apr 29, 2026
89b25c5
feat(plane): add Plane plugin with work items, epics, cycles, estimat…
aimanmuzaffar95 Apr 29, 2026
0707891
feat: added Salesforce user activity plugin
raza-bukhari Apr 20, 2026
54d2ba4
feat: Added e2e test cases
raza-bukhari Apr 21, 2026
17c2c20
feat: Added Grafana Salesforce dashboard
raza-bukhari Apr 28, 2026
dabfb3c
fix(salesforce): address HIGH-severity review findings
raza-bukhari Apr 29, 2026
9bb0011
fix(salesforce): address remaining PR review issues
raza-bukhari Apr 29, 2026
34f6280
feat: Added test coverage dashboard for GitHub
raza-bukhari Apr 28, 2026
3d3c88a
fix(salesforce): Fix empty form issue for saved form.
raza-bukhari Apr 30, 2026
021b842
fix: limit GitHub dashboard changes to test coverage
raza-bukhari May 5, 2026
2a2d6da
feat: Added test coverage dashboard for GitHub (#4)
aimanmuzaffar95 May 5, 2026
a807ba1
feat: add Salesforce user activity plugin (#3)
aimanmuzaffar95 May 5, 2026
81c4e97
fix(salesforce): added mask for secrets and tokens
raza-bukhari May 7, 2026
e3603a7
fix(salesforce): added mask for secrets and tokens (#7)
aimanmuzaffar95 May 7, 2026
b2c778d
fix: include default connection values on save
raza-bukhari May 6, 2026
072e3d6
fix(github): preserve plugin defaults when saving connections
raza-bukhari May 7, 2026
7a3548c
fix(github): tighten save-payload helper and run tests in CI
raza-bukhari May 7, 2026
a556549
fix: include default connection values on save (#8)
aimanmuzaffar95 May 8, 2026
18a74bd
fix(github): preserve saved masked credentials on connection edit
raza-bukhari May 14, 2026
fdb2193
fix(github): preserve saved masked credentials on connection edit (#9)
aimanmuzaffar95 May 15, 2026
e162717
fix(github): Fix blueprint data scope selection UX
raza-bukhari May 22, 2026
93ee396
feat(grafana): Configure Grafana SMTP for password reset emails and f…
raza-bukhari Jun 5, 2026
edb3eb8
fix(grafana): avoid sharing SMTP password in env examples
raza-bukhari Jun 5, 2026
32d11a9
fix(config-ui): guard data scope select-all state
raza-bukhari Jun 5, 2026
fabfb6c
fix(grafana): clarify smtp secret configuration
raza-bukhari Jun 8, 2026
f1250cc
Merge pull request #12 from raza-bukhari/fix/github-blueprint-datasco…
aimanmuzaffar95 Jun 8, 2026
13d9571
fix(github): stop default project blueprints limiting historical sync
raza-bukhari Jun 6, 2026
b9cfaa3
Merge pull request #14 from raza-bukhari/fix/github-blueprint-timeaft…
aimanmuzaffar95 Jun 9, 2026
bb77215
fix(grafana): document smtp security edge cases
raza-bukhari Jun 9, 2026
c9bec99
Merge pull request #13 from raza-bukhari/feature/grafana-forgot-passw…
aimanmuzaffar95 Jun 17, 2026
73d3b87
fix(github): full sync no longer inherits stale time_after cutoff
aimanmuzaffar95 Jun 18, 2026
c4572ec
fix(github): CollectorStateManager also ignores stale time_after on f…
aimanmuzaffar95 Jun 18, 2026
7ee10dc
fix(github): ensure stored TimeAfter is not restored on config change…
aimanmuzaffar95 Jun 19, 2026
ff1cd0d
Merge pull request #15 from aimanmuzaffar95/fix/github-fullsync-ignor…
aimanmuzaffar95 Jun 19, 2026
5291d2c
fix(github): refactor issue handling in CollectIssues function
aimanmuzaffar95 Jun 23, 2026
2f6e3ad
Merge pull request #16 from aimanmuzaffar95/bugfix/fix-edly-pipeline-…
aimanmuzaffar95 Jun 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
973 changes: 973 additions & 0 deletions .agents/skills/devlake-plugin/SKILL.md

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions .github/workflows/config-ui.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,5 @@ jobs:
run: cd config-ui; yarn
- name: Run Lint
run: cd config-ui; yarn tsc && yarn lint
- name: Run Tests
run: cd config-ui; yarn test
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ lake
*.so

NOTES.md
.plans/

main
vendor
Expand All @@ -168,4 +169,4 @@ venv
/backend/plugins/gitextractor/parser/output*
/backend/plugins/gitextractor/parser/demo_repo/

__debug_bin*
__debug_bin*
8 changes: 8 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ limitations under the License.
-->
# Apache DevLake - AI Coding Agent Instructions

## Response Style
- Keep plans and responses concise by default
- Prefer short bullets and short paragraphs over long explanations
- For simple requests, give the minimum useful answer only
- If brevity and polished grammar conflict, choose brevity
- Avoid repeating context, restating the prompt, or adding filler
- Summaries should be direct and approval-friendly so they are fast to scan

## Project Overview
Apache DevLake is a dev data platform that ingests data from DevOps tools (GitHub, GitLab, Jira, Jenkins, etc.), transforms it into standardized domain models, and enables metrics/dashboards via Grafana.

Expand Down
Binary file added backend/api.test
Binary file not shown.
77 changes: 77 additions & 0 deletions backend/core/models/domainlayer/ai/ai_activity.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
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 ai holds domain-layer models for AI coding assistant activity.
package ai

import (
"time"

"github.com/apache/incubator-devlake/core/models/domainlayer"
)

// AiActivity records a single day of AI-assisted coding activity for one developer.
// It is the normalised domain-layer representation shared by all AI tool plugins
// (Claude, GitHub Copilot, Cursor, Codex, etc.).
type AiActivity struct {
domainlayer.DomainEntity

// Provider identifies the AI tool (e.g. "claude", "gh-copilot", "cursor", "codex").
Provider string `gorm:"type:varchar(100);index" json:"provider"`

// AccountId is the global DevLake account resolved from UserEmail.
// May be empty if no matching account was found.
AccountId string `gorm:"type:varchar(255);index" json:"accountId"`

// UserEmail is the raw email (or login) as returned by the provider.
UserEmail string `gorm:"type:varchar(255)" json:"userEmail"`

// Date is the calendar day the activity was recorded.
Date time.Time `gorm:"type:date;index" json:"date"`

// Type categorises the activity (e.g. "CODE_EDIT", "CHAT").
Type string `gorm:"type:varchar(100)" json:"type"`

// Model is the AI model variant used (e.g. "claude-sonnet-4-5", "gpt-4o").
Model string `gorm:"type:varchar(100)" json:"model"`

// InterfaceType describes how the developer interacts with the tool.
// Known values: "cli", "ide_plugin", "web_ui".
InterfaceType string `gorm:"type:varchar(50)" json:"interfaceType"`

// Volume & autocomplete metrics (Copilot / Cursor style)
NumSessions int `json:"numSessions"`
SuggestionsCount int `json:"suggestionsCount"` // suggestions shown to the developer
AcceptanceCount int `json:"acceptanceCount"` // suggestions accepted by the developer

// Code change metrics
LinesAdded int `json:"linesAdded"`
LinesRemoved int `json:"linesRemoved"`

// Agentic outcome metrics (Claude / Codex style)
CommitsCreated int `json:"commitsCreated"`
PrsCreated int `json:"prsCreated"`

// Cost & token metrics
InputTokens int64 `json:"inputTokens"`
OutputTokens int64 `json:"outputTokens"`
EstimatedCostUsd float64 `json:"estimatedCostUsd"`
}

func (AiActivity) TableName() string {
return "ai_activities"
}
56 changes: 56 additions & 0 deletions backend/core/models/domainlayer/crossdomain/user_activity.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 crossdomain

import (
"time"

"github.com/apache/incubator-devlake/core/models/domainlayer"
)

// UserActivity is a generic cross-tool activity table for non-code, non-ticket
// user actions collected from external collaboration platforms such as HubSpot
// and Notion. It intentionally mirrors the shared-domain pattern used by
// ai_activities while preserving activity-specific fields.
type UserActivity struct {
domainlayer.DomainEntity

ConnectionId uint64 `gorm:"index" json:"connectionId"`
ScopeId string `gorm:"type:varchar(255);index" json:"scopeId"`

SourceSystem string `gorm:"type:varchar(100);index" json:"sourceSystem"`
SourceEventId string `gorm:"type:varchar(255)" json:"sourceEventId"`

AccountId string `gorm:"type:varchar(255);index" json:"accountId"`
UserEmail string `gorm:"type:varchar(255);index" json:"userEmail"`
UserDisplay string `gorm:"type:varchar(255)" json:"userDisplay"`
NativeUserId string `gorm:"type:varchar(255)" json:"nativeUserId"`

ActionType string `gorm:"type:varchar(100);index" json:"actionType"`
ObjectType string `gorm:"type:varchar(100)" json:"objectType"`
ObjectId string `gorm:"type:varchar(255)" json:"objectId"`
ObjectRef string `gorm:"type:varchar(512)" json:"objectRef"`

ActionTime time.Time `gorm:"type:timestamp;index" json:"actionTime"`
ActionDay time.Time `gorm:"type:date;index" json:"actionDay"`
Summary string `gorm:"type:text" json:"summary"`
}

func (UserActivity) TableName() string {
return "user_activities"
}
4 changes: 4 additions & 0 deletions backend/core/models/domainlayer/domaininfo/domaininfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package domaininfo

import (
"github.com/apache/incubator-devlake/core/dal"
"github.com/apache/incubator-devlake/core/models/domainlayer/ai"
"github.com/apache/incubator-devlake/core/models/domainlayer/code"
"github.com/apache/incubator-devlake/core/models/domainlayer/codequality"
"github.com/apache/incubator-devlake/core/models/domainlayer/crossdomain"
Expand Down Expand Up @@ -70,6 +71,7 @@ func GetDomainTablesInfo() []dal.Tabler {
&crossdomain.TeamUser{},
&crossdomain.User{},
&crossdomain.UserAccount{},
&crossdomain.UserActivity{},
// devops
&devops.CICDPipeline{},
&devops.CICDTask{},
Expand Down Expand Up @@ -100,5 +102,7 @@ func GetDomainTablesInfo() []dal.Tabler {
&qa.QaApi{},
&qa.QaTestCase{},
&qa.QaTestCaseExecution{},
// ai
&ai.AiActivity{},
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
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/models/migrationscripts/archived"
"github.com/apache/incubator-devlake/core/plugin"
"github.com/apache/incubator-devlake/helpers/migrationhelper"
)

var _ plugin.MigrationScript = (*addUserProjectMapping)(nil)

type addUserProjectMapping struct{}

type userProjectMapping20260311 struct {
UserLogin string `gorm:"primaryKey;type:varchar(255)"`
ProjectName string `gorm:"primaryKey;type:varchar(255);index"`
archived.NoPKModel
}

func (userProjectMapping20260311) TableName() string {
return "user_project_mapping"
}

func (script *addUserProjectMapping) Up(basicRes context.BasicRes) errors.Error {
return migrationhelper.AutoMigrateTables(
basicRes,
&userProjectMapping20260311{},
)
}

func (*addUserProjectMapping) Version() uint64 {
return 20260311120000
}

func (*addUserProjectMapping) Name() string {
return "add user_project_mapping table"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
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/core/plugin"
)

var _ plugin.MigrationScript = (*addAiActivitiesUnifiedSchema)(nil)

type aiActivity20260331 struct {
archived.DomainEntity
Provider string `gorm:"type:varchar(100);index"`
AccountId string `gorm:"type:varchar(255);index"`
UserEmail string `gorm:"type:varchar(255)"`
Date time.Time `gorm:"type:date;index"`
Type string `gorm:"type:varchar(100)"`
Model string `gorm:"type:varchar(100)"`
InterfaceType string `gorm:"type:varchar(50)"`
NumSessions int
SuggestionsCount int
AcceptanceCount int
LinesAdded int
LinesRemoved int
CommitsCreated int
PrsCreated int
InputTokens int64
OutputTokens int64
EstimatedCostUsd float64
}

func (aiActivity20260331) TableName() string {
return "ai_activities"
}

type addAiActivitiesUnifiedSchema struct{}

// Up runs the migration.
//
// Changes to ai_activities:
// - Rename commits_by_claude → commits_created
// - Rename prs_by_claude → prs_created
// - Add interface_type varchar(50)
// - Add suggestions_count int (default 0)
// - Add acceptance_count int (default 0)
//
// The RENAME is implemented as ADD+COPY+DROP so it works across MySQL, PostgreSQL,
// and SQLite without dialect-specific RENAME COLUMN support issues.
// AutoMigrate (called after all migration scripts) will then reconcile any remaining
// column differences against the updated Go struct.
func (script *addAiActivitiesUnifiedSchema) Up(basicRes context.BasicRes) errors.Error {
db := basicRes.GetDal()

// If the table doesn't exist (fresh install or e2e tests), completely create it
// using AutoMigrate, bypassing the need to rename missing legacy columns.
if !db.HasTable("ai_activities") {
return db.AutoMigrate(&aiActivity20260331{})
}

// 1. Rename commits_by_claude → commits_created
if err := db.AddColumn("ai_activities", "commits_created", "bigint"); err != nil {
// column may already exist if migration was partially applied — ignore duplicate
_ = err
}
_ = db.Exec("UPDATE ai_activities SET commits_created = commits_by_claude WHERE commits_by_claude IS NOT NULL")
_ = db.DropColumns("ai_activities", "commits_by_claude")

// 2. Rename prs_by_claude → prs_created
if err := db.AddColumn("ai_activities", "prs_created", "bigint"); err != nil {
_ = err
}
_ = db.Exec("UPDATE ai_activities SET prs_created = prs_by_claude WHERE prs_by_claude IS NOT NULL")
_ = db.DropColumns("ai_activities", "prs_by_claude")

// 3. Add new columns (AddColumn is idempotent-friendly — errors on duplicate are silently ignored)
_ = db.AddColumn("ai_activities", "interface_type", "varchar(50)")
_ = db.AddColumn("ai_activities", "suggestions_count", "bigint")
_ = db.AddColumn("ai_activities", "acceptance_count", "bigint")

return nil
}

func (*addAiActivitiesUnifiedSchema) Version() uint64 {
return 20260331000001
}

func (*addAiActivitiesUnifiedSchema) Name() string {
return "add unified schema fields to ai_activities (rename commits/prs, add interface_type, suggestions, acceptance)"
}
Loading
Loading