|
| 1 | +<!-- |
| 2 | +Licensed to the Apache Software Foundation (ASF) under one or more |
| 3 | +contributor license agreements. See the NOTICE file distributed with |
| 4 | +this work for additional information regarding copyright ownership. |
| 5 | +The ASF licenses this file to You under the Apache License, Version 2.0 |
| 6 | +(the "License"); you may not use this file except in compliance with |
| 7 | +the License. You may obtain a copy of the License at |
| 8 | +
|
| 9 | + http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | +
|
| 11 | +Unless required by applicable law or agreed to in writing, software |
| 12 | +distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | +See the License for the specific language governing permissions and |
| 15 | +limitations under the License. |
| 16 | +--> |
| 17 | +# Apache DevLake - AI Coding Agent Instructions |
| 18 | + |
| 19 | +## Project Overview |
| 20 | +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. |
| 21 | + |
| 22 | +## Architecture |
| 23 | + |
| 24 | +### Three-Layer Data Model |
| 25 | +1. **Raw Layer** (`_raw_*` tables): JSON data collected from APIs, stored for replay/debugging |
| 26 | +2. **Tool Layer** (`_tool_*` tables): Plugin-specific models extracted from raw data |
| 27 | +3. **Domain Layer** (standardized tables): Normalized models in [backend/core/models/domainlayer/](backend/core/models/domainlayer/) - CODE, TICKET, CICD, CODEREVIEW, CODEQUALITY, CROSS |
| 28 | + |
| 29 | +### Key Components |
| 30 | +- **backend/**: Go server + plugins (main codebase) |
| 31 | +- **backend/python/**: Python plugin framework via RPC |
| 32 | +- **config-ui/**: React frontend (TypeScript, Vite, Ant Design) |
| 33 | +- **grafana/**: Dashboard definitions |
| 34 | + |
| 35 | +## Plugin Development (Go) |
| 36 | + |
| 37 | +### Plugin Structure |
| 38 | +Each plugin in `backend/plugins/<name>/` follows this layout: |
| 39 | +``` |
| 40 | +api/ # REST endpoints (connections, scopes, scope-configs) |
| 41 | +impl/ # Plugin implementation (implements core interfaces) |
| 42 | +models/ # Tool layer models + migrationscripts/ |
| 43 | +tasks/ # Collectors, Extractors, Converters |
| 44 | +e2e/ # Integration tests with CSV fixtures |
| 45 | +``` |
| 46 | + |
| 47 | +### Required Interfaces |
| 48 | +See [backend/plugins/gitlab/impl/impl.go](backend/plugins/gitlab/impl/impl.go) for reference: |
| 49 | +- `PluginMeta`: Name, Description, RootPkgPath |
| 50 | +- `PluginTask`: SubTaskMetas(), PrepareTaskData() |
| 51 | +- `PluginModel`: GetTablesInfo() - **must list all models or CI fails** |
| 52 | +- `PluginMigration`: MigrationScripts() for DB schema evolution |
| 53 | +- `PluginSource`: Connection(), Scope(), ScopeConfig() |
| 54 | + |
| 55 | +### Subtask Pattern (Collector → Extractor → Converter) |
| 56 | +```go |
| 57 | +// 1. Register subtask in tasks/register.go via init() |
| 58 | +func init() { |
| 59 | + RegisterSubtaskMeta(&CollectIssuesMeta) |
| 60 | +} |
| 61 | + |
| 62 | +// 2. Define dependencies for execution order |
| 63 | +var CollectIssuesMeta = plugin.SubTaskMeta{ |
| 64 | + Name: "Collect Issues", |
| 65 | + Dependencies: []*plugin.SubTaskMeta{}, // or reference other metas |
| 66 | +} |
| 67 | +``` |
| 68 | + |
| 69 | +### API Collectors |
| 70 | +- Use `helper.NewStatefulApiCollector` for incremental collection with time-based bookmarking |
| 71 | +- See [backend/plugins/gitlab/tasks/issue_collector.go](backend/plugins/gitlab/tasks/issue_collector.go) |
| 72 | + |
| 73 | +### Migration Scripts |
| 74 | +- Located in `models/migrationscripts/` |
| 75 | +- Register all scripts in `register.go`'s `All()` function |
| 76 | +- Version format: `YYYYMMDD_description.go` |
| 77 | + |
| 78 | +## Build & Development Commands |
| 79 | + |
| 80 | +```bash |
| 81 | +# From repo root |
| 82 | +make dep # Install Go + Python dependencies |
| 83 | +make build # Build plugins + server |
| 84 | +make dev # Build + run server |
| 85 | +make godev # Go-only dev (no Python plugins) |
| 86 | +make unit-test # Run all unit tests |
| 87 | +make e2e-test # Run E2E tests |
| 88 | + |
| 89 | +# From backend/ |
| 90 | +make swag # Regenerate Swagger docs (required after API changes) |
| 91 | +make lint # Run golangci-lint |
| 92 | +``` |
| 93 | + |
| 94 | +### Running Locally |
| 95 | +```bash |
| 96 | +docker-compose -f docker-compose-dev.yml up mysql grafana # Start deps |
| 97 | +make dev # Run server on :8080 |
| 98 | +cd config-ui && yarn && yarn start # UI on :4000 |
| 99 | +``` |
| 100 | + |
| 101 | +## Testing |
| 102 | + |
| 103 | +### Unit Tests |
| 104 | +Place `*_test.go` files alongside source. Use mocks from `backend/mocks/`. |
| 105 | + |
| 106 | +### E2E Tests for Plugins |
| 107 | +Use CSV fixtures in `e2e/` directory. See [backend/test/helper/](backend/test/helper/) for the Go test client that can spin up an in-memory DevLake instance. |
| 108 | + |
| 109 | +### Integration Testing |
| 110 | +```go |
| 111 | +helper.ConnectLocalServer(t, &helper.LocalClientConfig{ |
| 112 | + ServerPort: 8080, |
| 113 | + DbURL: "mysql://merico:merico@127.0.0.1:3306/lake", |
| 114 | + CreateServer: true, |
| 115 | + Plugins: []plugin.PluginMeta{gitlab.Gitlab{}}, |
| 116 | +}) |
| 117 | +``` |
| 118 | + |
| 119 | +## Python Plugins |
| 120 | +Located in `backend/python/plugins/`. Use Poetry for dependencies. See [backend/python/README.md](backend/python/README.md). |
| 121 | + |
| 122 | +## Code Conventions |
| 123 | +- Tool model table names: `_tool_<plugin>_<entity>` (e.g., `_tool_gitlab_issues`) |
| 124 | +- Domain model IDs: Use `didgen.NewDomainIdGenerator` for consistent cross-plugin IDs |
| 125 | +- All plugins must be independent - no cross-plugin imports |
| 126 | +- Apache 2.0 license header required on all source files |
| 127 | + |
| 128 | +## Common Pitfalls |
| 129 | +- Forgetting to add models to `GetTablesInfo()` fails `plugins/table_info_test.go` |
| 130 | +- Migration scripts must be added to `All()` in `register.go` |
| 131 | +- API changes require running `make swag` to update Swagger docs |
| 132 | +- Python plugins require `libgit2` for gitextractor functionality |
0 commit comments