Summary
For some metric calculations such as the DORA metric, we often encounter situations requiring comprehensive calculations based on data from multiple data sources.
For example, we may use GitLab for code hosting, Jenkins for CI/CD, to calculate PR deployment cycle time, we need to know which GitLab Projects and Jenkins Jobs are related for correctness and performance reasons.
However, in most cases, we have multiple GitLab Projects / Jenkins Jobs that belong to different teams in our Apache DevLake database.
To distinguish them into different groups. The Project is introduced in v0.15. Essentially, a project consists of a set of Scopes, i.e., a couple of GitLab Projects, Jira Boards or Jenkins Jobs, etc.
Project is a set of Scope from different domains, a way to group different resources, and it is crucial for some metric calculation like Dora.
Next, let us introduce Project in the following order:
Projectrelated models- Related APIs that can be used to manipulate
Projectmodels - The interface that needs to be implemented when developing various plugins to support the
Project.- The interface that needs to be implemented to develop the
Data Source Plugin - The interface that needs to be implemented to develop the
Metric Plugins
- The interface that needs to be implemented to develop the
Models
To support project we contains the following three models:
projectsdescribes a project object, including its name, creation and update time and other basic informationproject_metric_settingsdescribes what metric plugins a project had enabled.project_mappingdescribes the mapping relationship of project and scope, including the name of the project、the table name of Scope and the row_id in the Scope table.
projects
| field | type | length | description | key |
|---|---|---|---|---|
name | varchar | 255 | name for project | PK |
description | longtext | description of the project | ||
created_at | datetime | 3 | created time of project | |
updated_at | datetime | 3 | last updated time of project |
example
| name | describe | created_at | updated_at |
|---|---|---|---|
| project_1 | this is one of the test projects | 2022-11-01 01:22:13.000 | 2022-11-01 02:24:15.000 |
| project_2 | this is another project test project | 2022-11-01 01:23:29.000 | 2022-11-01 02:27:24.000 |
project_metric_settings
| field | type | length | description | key |
|---|---|---|---|---|
project_name | varchar | 255 | name for project | PK |
plugin_name | varchar | 255 | name for plugin | PK |
plugin_option | longtext | check if metric plugins have been enabled by the project | ||
enable | tinyint | 1 | if the metric plugins is enabled |
example
| project_name | plugin_name | plugin_option | enable |
|---|---|---|---|
| project_1 | dora | {} | true |
| project_2 | dora | {} | false |
project_mapping
| field | type | length | description | key |
|---|---|---|---|---|
project_name | varchar | 255 | name for project | PK |
table | varchar | 255 | the table name of Scope | PK |
row_id | varchar | 255 | the row_id in the Scope table | PK |
example
| project_name | table | row_id |
|---|---|---|
| project_1 | Repo | gitlab:GithubRepo:1:lake |
| project_1 | Board | jira:JiraBoard:1:lake |
| project_2 | Repo | github:GithubRepo:1:lake |
How to manage project via API
For API specification, please check the swagger doc(by visiting [Your Config-UI Host]/api/swagger/index.html).
Related endpoints:
- /projects
- /projects/:projectName/metrics
- /plugins
The interface that needs to be implemented
We divide plugins into two categories
- The first category is
Data Source Plugin, such asGitLabGitHubJiraJenkins, etc. These plugins collect data from various data sources - The second category is
Metric Plugin, such asDora, etc. These plugins do not directly contact the data source but do secondary calculations based on the collected data after theData Source Pluginworks
Data Source Plugin
For example GitLab GitHub Jira Jenkins etc.
These plugins, from various data sources, extract data into the database and store them, they deal directly with the data source, so we classify them as Data Source Plugin.
the DataSourcePluginBlueprintV200 interface
Data Source Plugin needs to implement DataSourcePluginBlueprintV200 interface to support project
The interface definition for this interface is as follows
// DataSourcePluginBlueprintV200 extends the V100 to provide support for
// Project, so that complex metrics like DORA can be implemented based on a set
// of Data Scopes
type DataSourcePluginBlueprintV200 interface {
MakeDataSourcePipelinePlanV200(
connectionId uint64,
scopes []*BlueprintScopeV200,
syncPolicy BlueprintSyncPolicy,
) (PipelinePlan, []Scope, errors.Error)
}
scopes in input parameters is a set of arrays containing IDs, Names, and Entities.
The input data format is as follows:
[]*core.BlueprintScopeV200{
{
Entities: []string{"CODE", "TICKET", "CICD"},
Id: "37",
Name: "test",
},
}
syncPolicy in input parameters contains some option settings, whose structure is defined as follows:
type BlueprintSyncPolicy struct {
Version string `json:"version" validate:"required,semver,oneof=1.0.0"`
SkipOnFail bool `json:"skipOnFail"`
CreatedDateAfter *time.Time `json:"createdDateAfter"`
}
PipelinePlan in output is a part of blueprint JSON:
The input data format is as follows:(Take GitLab plugin as an example)
core.PipelinePlan{
{
{
Plugin: "gitlab",
Subtasks: []string{
tasks.ConvertProjectMeta.Name,
tasks.CollectApiIssuesMeta.Name,
tasks.ExtractApiIssuesMeta.Name,
tasks.ConvertIssuesMeta.Name,
tasks.ConvertIssueLabelsMeta.Name,
tasks.CollectApiJobsMeta.Name,
tasks.ExtractApiJobsMeta.Name,
tasks.CollectApiPipelinesMeta.Name,
tasks.ExtractApiPipelinesMeta.Name,
},
Options: map[string]interface{}{
"connectionId": uint64(1),
"projectId": testID,
},
},
{
Plugin: "gitextractor",
Options: map[string]interface{}{
"proxy": "",
"repoId": repoId,
"url": "https://git:nddtf@this_is_cloneUrl",
},
},
},
{
{
Plugin: "refdiff",
Options: map[string]interface{}{
"tagsLimit": 10,
"tagsOrder": "reverse semver",
"tagsPattern": "pattern",
},
},
},
}
project needs to provide a specific set of Scopes for a specific connection to the plugin through this interface, and then obtain the plugin involved in the PipelineTask All plugins and corresponding parameter information. At the same time, the plugin needs to convert entities like repo and board in the data source into a scope interface that project can understand
The corresponding scope interface has been implemented at following files of in the framework layer:
models/domainlayer/devops/cicd_scope.gomodels/domainlayer/ticket/board.gomodels/domainlayer/code/repo.go
In the plugins/gitlab/impl/impl.go file, there is a GitLab plugin implementation of the above interface, which can be used as a reference.
And the plugins/gitlab/api/blueprint_v200.go contains implementation details.
The following files contain the models that the relevant implementations depend on for reference:
plugins/gitlab/models/project.goplugins/gitlab/models/scope_config.go
Metric Plugins
For example Dora, and Refdff plugins belong to the Metric Plugins
These plugins are mainly for calculating various metrics, they do not directly contact the data source, so we classify them as Metric Plugins.
The PluginMetric Interface
Metric Plugins needs to implement the PluginMetric interface to support project
The interface definition for this interface looks like this:
type PluginMetric interface {
// returns a list of required data entities and expected features.
// [{ "model": "cicd_tasks", "requiredFields": {"column": "type", "execptedValue": "Deployment"}}, ...]
RequiredDataEntities() (data []map[string]interface{}, err errors.Error)
// returns if the metric depends on Project for calculation.
// Currently, only dora would return true.
IsProjectMetric() bool
// indicates which plugins must be executed before executing this one.
// declare a set of dependencies with this
RunAfter() ([]string, errors.Error)
// returns an empty pointer of the plugin setting struct.
// (no concrete usage at this point)
Settings() (p interface{})
}
Project needs PluginMetric to know whether a Metric Plugin is dependent on project, and the tables and fields required in its calculation process.
In the plugins/dora/impl/impl.go file, there is a Dora plugin implementation of the above interface, which can be used as a sample reference.You can find it by searching the following fields:
func (plugin Dora) RequiredDataEntities() (data []map[string]interface{}, err errors.Error)func (plugin Dora) IsProjectMetric() boolfunc (plugin Dora) RunAfter() ([]string, errors.Error)func (plugin Dora) Settings() interface{}
References
To dig deeper into developing and utilizing our built-in functions and have a better developer experience, feel free to dive into our godoc reference.