From 3355217b40810e48d199ca260fd7d769694ab6ee Mon Sep 17 00:00:00 2001 From: Itai Spiegel Date: Sun, 11 Oct 2026 16:27:58 +0300 Subject: [PATCH] docs: add monorepo plugin documentation Companion to apache/devlake#9037 (Plugin for per-sub-project DORA metrics in a monorepo). Adds a Plugins/monorepo page covering how deployments are attributed by CI job name and pull requests by label, the per-project configuration on the project settings page and its equivalent metric plugin option, the unattributed/All reserved names, what the plugin writes, and the built-in Monorepo Sub-Projects dashboard. It also states that only Deployment Frequency and Lead Time for Changes are computed per sub-project, since incidents are not attributed. Documents the new sub_project columns on pull_requests, pull_request_commits and project_pr_metrics plus the new cicd_deployment_subprojects table in the domain layer schema, and links to the plugin from the DORA page. Co-Authored-By: Claude Opus 5 (1M context) --- docs/DORA.md | 11 ++ docs/DataModels/DevLakeDomainLayerSchema.md | 17 +++ docs/Plugins/monorepo.md | 147 ++++++++++++++++++++ 3 files changed, 175 insertions(+) create mode 100644 docs/Plugins/monorepo.md diff --git a/docs/DORA.md b/docs/DORA.md index d828d3388c5..49308324bb8 100644 --- a/docs/DORA.md +++ b/docs/DORA.md @@ -206,6 +206,17 @@ If you are not familiar with Grafana, please refer to our [Grafana doc](Configur

+## DORA for a monorepo + +DevLake measures DORA at the project level, and a project's scope is a repository. If a +single repository hosts several logically separate projects — each with its own deploy job +and its own PR label — all of them collapse into one set of DORA numbers. + +The [monorepo plugin](Plugins/monorepo.md) splits such a repository into sub-projects and +computes per-sub-project Deployment Frequency and Lead Time for Changes. + +
+ ## Try it Out To create the DORA dashboard with your own toolchain, please look at the [configuration tutorial](Configuration/Tutorial.md) and [project organization documentation](Configuration/HowToOrganizeDevlakeProjects.md) for more details. diff --git a/docs/DataModels/DevLakeDomainLayerSchema.md b/docs/DataModels/DevLakeDomainLayerSchema.md index 4676005c75f..7f6cda28cb9 100644 --- a/docs/DataModels/DevLakeDomainLayerSchema.md +++ b/docs/DataModels/DevLakeDomainLayerSchema.md @@ -465,6 +465,7 @@ Pull requests are the abstraction of GitHub pull requests, GitLab merge requests | `head_ref` | varchar | 255 | The branch name in the head repo that contains the changes that will be added to the base | | | `base_commit_sha` | char | 40 | The base commit of this PR. | | | `head_commit_sha` | char | 40 | The head commit of this PR. | | +| `sub_project` | varchar | 100 | The monorepo sub-project this PR belongs to, matched by label. Written by the [monorepo plugin](../Plugins/monorepo.md); NULL when the project has no monorepo configuration. | | #### pull_request_labels @@ -489,6 +490,7 @@ The list is additive. This means if a rebase with commit squashing takes place a | `commit_author_name` | varchar | 255 | The name of the person who authored the commit | | | `commit_author_email` | varchar | 255 | The email address of the person who authored the commit. | | | `commit_authored_date` | varchar | 255 | The date and time when the commit was authored. | | +| `sub_project` | varchar | 100 | Mirrors the owning pull request's `sub_project`. | | #### pull_request_comments @@ -656,6 +658,20 @@ Normally, one deployment only deploy to one repo. But in some cases, one deploym | `repo_url` | varchar | 191 | The url of the repo | | | `prev_success_deployment_commit_id` | varchar | 255 | The last successful deployment_commit_id before this one in the same `cicd_scope`, `repo` and `environment`, which is used to calculate the new commits deployed by this deployment, thereby measuring [DORA - change lead time](../Metrics/LeadTimeForChanges.md). | | +#### cicd_deployment_subprojects + +Maps a deployment to the monorepo sub-project(s) it deployed. Rows are written by the [monorepo plugin](../Plugins/monorepo.md), which matches the name of the deploying CI job against each sub-project's configured pattern. + +The relationship is many-to-many: a pipeline that runs the deploy jobs of several sub-projects produces one row per sub-project, so dashboards can `GROUP BY sub_project` without double counting. + +Projects without monorepo configuration have no rows in this table at all; dashboards treat a missing mapping as the single, implicit `All` group. + +| **field** | **type** | **length** | **description** | **key** | +|:---------------------|:---------|:-----------|:------------------------------------------------------------------------------------------|:--------| +| `project_name` | varchar | 100 | The project this mapping belongs to | PK | +| `cicd_deployment_id` | varchar | 255 | The deployment, matching [table.cicd_deployment_commits](#cicd_deployment_commits).`cicd_deployment_id` | PK | +| `sub_project` | varchar | 100 | The sub-project this deployment deployed | PK | + ### Domain 5 - Code Quality The names of tables in the 'Code Quality' domain will start with a prefix cq\_ @@ -929,6 +945,7 @@ metrics, such as _'No. of Issue closed by contributor', 'No. of commits by contr | `deployment_id` | longtext | | The id of cicd_task which deploy the commits of this PR | | | `pr_deploy_time` | bigint | | The time it takes from when a PR is merged to when it is deployed | | | `pr_cycle_time` | bigint | | The total time from the first commit to when the PR is deployed | | +| `sub_project` | varchar | 100 | The monorepo sub-project of this PR, copied from [table.pull_requests](#pull_requests) | | #### project_issue_metrics diff --git a/docs/Plugins/monorepo.md b/docs/Plugins/monorepo.md new file mode 100644 index 00000000000..82b02748999 --- /dev/null +++ b/docs/Plugins/monorepo.md @@ -0,0 +1,147 @@ +--- +title: "Monorepo" +description: > + Monorepo Plugin +--- + +## Summary + +DevLake's scope model is one scope per repository, so a repository that hosts several +logically separate projects collapses into a single set of DORA numbers. The `monorepo` +plugin splits such a repository into **sub-projects** and computes per-sub-project +delivery metrics. + +Like [DORA](../DORA.md) and [Linker](./linker.md), it is a metric plugin: it works on the +domain layer after data collection, and runs after `dora`. + +It attributes: + +- **Deployments** to a sub-project by matching the name of the CI job that performed the + deployment against a regular expression. +- **Pull requests** to a sub-project by matching the PR's labels. + +From those two attributions it produces per-sub-project +[Deployment Frequency](../Metrics/DeploymentFrequency.md) and +[Lead Time for Changes](../Metrics/LeadTimeForChanges.md). + +[Change Failure Rate](../Metrics/CFR.md) and +[Median Time to Restore Service](../Metrics/MTTR.md) are **not** computed per sub-project, +because they require incident data and incidents are not attributed to sub-projects. + +## Supported Versions + +The monorepo plugin was added after the `v1.0.3-beta18` release and is available in all +later releases. + +## Configuration + +The plugin is configured per project, on the project's settings page. + +1. Open **Projects** → your project → **Settings**. +2. Tick **Enable Monorepo Sub-Projects**. +3. Add one row per sub-project and fill in the three fields below. +4. Click **Save**, then re-run the project's blueprint. + +| Field | Description | Example | +|:--------------------------|:----------------------------------------------------------------------------------------------------------------------------------------|:---------------------| +| **Sub-project name** | Identifies the sub-project in the output tables and dashboards. Must be unique within the project. | `serviceA` | +| **Labels** | Comma-separated pull request labels that mark a PR as belonging to this sub-project. Matching is **exact and case-sensitive**. | `serviceA,svc-a` | +| **Deploy job pattern** | A [Go regular expression](https://pkg.go.dev/regexp/syntax) matched against `cicd_tasks.name` to recognise this sub-project's deploy jobs. | `^deploy-serviceA$` | + +`unattributed` and `All` are reserved and cannot be used as sub-project names. + +The same options can be set through the API or the Config UI's +[advanced mode](../Configuration/AdvancedMode.md) as the project's `monorepo` metric +plugin option: + +```json +{ + "pluginName": "monorepo", + "enable": true, + "pluginOption": { + "subProjects": [ + { + "name": "serviceA", + "prLabels": ["serviceA", "svc-a"], + "deployJobPattern": "^deploy-serviceA$" + }, + { + "name": "serviceB", + "prLabels": ["serviceB"], + "deployJobPattern": "^deploy-serviceB$" + } + ], + "includeUnattributed": true + } +} +``` + +`includeUnattributed` (default `true`) controls what happens to pull requests and +deployments that belong to the project but match none of the configured sub-projects: +with `true` they are recorded under the sentinel sub-project `unattributed`, so you can +see how much of the repository is not yet classified; with `false` they are left +unclassified. + +## How attribution works + +### Deployments + +Every deployment of the project is joined to the CI/CD tasks of the pipeline that produced +it, and each task of type `Deployment` has its name matched against each sub-project's +`deployJobPattern`. + +- A pipeline that runs the deploy jobs of several sub-projects produces **one row per + sub-project**, so dashboards can `GROUP BY sub_project` without double counting. +- Deployments imported directly from a provider's deployment API (rather than generated + from a pipeline) carry no job name and cannot be attributed. + +### Pull requests + +All pull requests of the project are attributed — open, closed and merged — by label. +A pull request belongs to exactly one sub-project: when it carries the labels of more than +one, the **first matching sub-project in the configured order wins**, so order the list +from most to least specific. + +PR coding, pickup, review, deploy and cycle time are not recomputed by this plugin; they +are taken from DORA's own `project_pr_metrics` rows and tagged with the sub-project. + +### Mismatch warnings + +After tagging, the plugin cross-checks each PR's label-derived sub-project against the +sub-project of the deployment that DORA says actually shipped it. Disagreements are logged +as warnings and never fail the pipeline — labels always win. They usually point at a +`prLabels` or `deployJobPattern` entry that needs fixing, though a pipeline deploying +several sub-projects at once will produce such warnings legitimately. + +## Output + +| Table | Description | +|:------------------------------------------------------------------------------------------|:-------------------------------------------------------------------------------------------| +| [`cicd_deployment_subprojects`](../DataModels/DevLakeDomainLayerSchema.md#cicd_deployment_subprojects) | Maps each deployment to the sub-project(s) it deployed. | +| [`pull_requests.sub_project`](../DataModels/DevLakeDomainLayerSchema.md#pull_requests) | The sub-project a pull request belongs to. | +| [`pull_request_commits.sub_project`](../DataModels/DevLakeDomainLayerSchema.md#pull_request_commits) | Mirrors the owning pull request's sub-project. | +| [`project_pr_metrics.sub_project`](../DataModels/DevLakeDomainLayerSchema.md#project_pr_metrics) | Tags DORA's per-PR metrics with the sub-project. | + +A `NULL` `sub_project` means the row was never classified — single-repo projects, or rows +the plugin has not processed. Dashboards render these as the single implicit group `All` +via `COALESCE(sub_project, 'All')`. + +Attribution is rebuilt from scratch on every run, so changing the configuration and +re-running the blueprint reclassifies existing data. + +:::note +The plugin also populates `monorepo_subproject_deployments` and +`monorepo_subproject_pr_metrics`. Both are deprecated and will be removed in a future +release — query the tables above instead. +::: + +## Dashboard + +A built-in Grafana dashboard, **Monorepo Sub-Projects**, visualises the output: + +- Deployment Count by Sub-Project +- Deployment Frequency over Time +- Change Lead Time Breakdown by Sub-Project +- Unattributed PRs +- Awaiting Deployment +- Attributed Deployments