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.
- Raw Layer (
_raw_*tables): JSON data collected from APIs, stored for replay/debugging - Tool Layer (
_tool_*tables): Plugin-specific models extracted from raw data - Domain Layer (standardized tables): Normalized models in backend/core/models/domainlayer/ - CODE, TICKET, CICD, CODEREVIEW, CODEQUALITY, CROSS
- backend/: Go server + plugins (main codebase)
- backend/python/: Python plugin framework via RPC
- config-ui/: React frontend (TypeScript, Vite, Ant Design)
- grafana/: Dashboard definitions
Each plugin in backend/plugins/<name>/ follows this layout:
api/ # REST endpoints (connections, scopes, scope-configs)
impl/ # Plugin implementation (implements core interfaces)
models/ # Tool layer models + migrationscripts/
tasks/ # Collectors, Extractors, Converters
e2e/ # Integration tests with CSV fixtures
See backend/plugins/gitlab/impl/impl.go for reference:
PluginMeta: Name, Description, RootPkgPathPluginTask: SubTaskMetas(), PrepareTaskData()PluginModel: GetTablesInfo() - must list all models or CI failsPluginMigration: MigrationScripts() for DB schema evolutionPluginSource: Connection(), Scope(), ScopeConfig()
PluginInit: Optional initialization hook withInit(basicRes)method for resource setupPluginOpenApiSpec: Remote plugins can expose OpenAPI specs viaOpenApiSpec()methodPluginMetric: For metrics plugins requiringRequiredDataEntities(),IsProjectMetric(),RunAfter(),Settings()DataSourcePluginBlueprintV200: Project-aware pipeline generation withMakeDataSourcePipelinePlanV200()for cross-plugin scope mappingMetricPluginBlueprintV200: Similar to DataSourcePluginBlueprintV200 for metric calculation plugins
Plugins can support multiple authentication methods via these interfaces:
CacheableConnection: ExtendsApiConnectionwithGetHash()for connection cachingMultiAuthenticator: Base interface withGetAuthMethod()returningBasicAuth,AccessToken, orAppKeyBasicAuthenticator: ImplementGetBasicAuthenticator()for HTTP Basic authAccessTokenAuthenticator: ImplementGetAccessTokenAuthenticator()for Bearer token authAppKeyAuthenticator: ImplementGetAppKeyAuthenticator()for API key/secret pairsPrepareApiClient: Hook in connection for initialization (e.g., token refresh) viaPrepareApiClient(apiClient)
DynamicTablerinterface: For runtime-generated models with methodsUnwrap(),NewValue(),From(),To()
// 1. Register subtask in tasks/register.go via init()
func init() {
RegisterSubtaskMeta(&CollectIssuesMeta)
}
// 2. Define dependencies for execution order
var CollectIssuesMeta = plugin.SubTaskMeta{
Name: "Collect Issues",
Dependencies: []*plugin.SubTaskMeta{}, // or reference other metas
}- Use
helper.NewStatefulApiCollectorfor incremental collection with time-based bookmarking - See backend/plugins/gitlab/tasks/issue_collector.go
- Located in
models/migrationscripts/ - Register all scripts in
register.go'sAll()function - Version format:
YYYYMMDD_description.go
# From repo root
make dep # Install Go + Python dependencies
make build # Build plugins + server
make dev # Build + run server
make godev # Go-only dev (no Python remote plugins)
make unit-test # Run all unit tests
make e2e-test # Run E2E tests
# From backend/
make swag # Regenerate Swagger docs (required after API changes)
make lint # Run golangci-lint
make mock # Regenerate mocks from interfaces
make migration-script-lint # Validate migration script format
make build-plugin-debug # Build plugins with debug symbols (DEVLAKE_DEBUG=1)
make build-pydevlake # Install/sync Python plugin framework dependencies
make e2e-test-go-plugins # Run E2E tests for Go plugins onlydocker-compose -f docker-compose-dev.yml up mysql grafana # Start deps
make dev # Run server on :8080
cd config-ui && yarn && yarn start # UI on :4000Place *_test.go files alongside source. Use mocks from backend/mocks/. Mocks are auto-generated via make mock from all interfaces in core/ and helpers/.
Use CSV fixtures in e2e/ directory. See backend/test/helper/ for the Go test client that can spin up an in-memory DevLake instance.
helper.ConnectLocalServer(t, &helper.LocalClientConfig{
ServerPort: 8080,
DbURL: "mysql://merico:merico@127.0.0.1:3306/lake",
CreateServer: true,
Plugins: []plugin.PluginMeta{gitlab.Gitlab{}},
})Run make migration-script-lint from backend/ to validate all migration scripts follow the correct format (YYYYMMDD_description.go).
Located in backend/python/plugins/. Use Poetry for dependencies. See backend/python/README.md.
- Tool model table names:
_tool_<plugin>_<entity>(e.g.,_tool_gitlab_issues) - Domain model IDs: Use
didgen.NewDomainIdGeneratorfor consistent cross-plugin IDs - All plugins must be independent - no cross-plugin imports
- Apache 2.0 license header required on all source files
- Mocks are auto-generated: don't edit files in
backend/mocks/, regenerate withmake mock - Optional plugin interfaces (PluginInit, PluginOpenApiSpec, PluginMetric) should only be implemented if functionality is needed
- Authentication: Use
CacheableConnectioninterface if connection needs caching; implement appropriate*Authenticatorfor each auth method supported
- Forgetting to add models to
GetTablesInfo()failsplugins/table_info_test.go - Migration scripts must be added to
All()inregister.goAND followYYYYMMDD_description.gonaming (validate withmake migration-script-lint) - API changes require running
make swagto update Swagger docs (this runsmake mockfirst) - Python plugins require
libgit2for gitextractor functionality - New Plugin interfaces like
PluginInitorPluginOpenApiSpecare optional - only implement if needed - Blueprint V2.0 implementation required for plugins that support project-aware scope mapping