| --- |
| title: "Project" |
| sidebar_position: 5 |
| description: > |
| `Project` is **a set of [Scope](../Overview/KeyConcepts.md#data-scope) from different domains**, a way to group different resources, and it is crucial for some metric calculations like `Dora`. |
| --- |
| |
| # 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](../Overview/KeyConcepts.md#data-scope), i.e., a couple of `GitLab Projects`, `Jira Boards` or `Jenkins Jobs`, etc. |
| |
| `Project` is **a set of [Scope](../Overview/KeyConcepts.md#data-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: |
| - `Project` related models |
| - Related APIs that can be used to manipulate `Project` models |
| - 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` |
| |
| # Models |
| |
| To support project we contains the following three models: |
| - `projects` describes a project object, including its name, creation and update time and other basic information |
| - `project_metric_settings` describes what metric plugins a project had enabled. |
| - `project_mapping` describes the mapping relationship of project and scope, including the name of the project、the table name of [Scope](../Overview/KeyConcepts.md#data-scope) and the row_id in the [Scope](../Overview/KeyConcepts.md#data-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](../Overview/KeyConcepts.md#data-scope) | PK | |
| | `row_id` | varchar | 255 | the row_id in the [Scope](../Overview/KeyConcepts.md#data-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: |
| |
| 1. /projects |
| 2. /projects/:projectName/metrics |
| 3. /plugins |
| |
| # The interface that needs to be implemented |
| |
| We divide plugins into two categories |
| - The first category is `Data Source Plugin`, such as `GitLab` `GitHub` `Jira` `Jenkins`, etc. These plugins collect data from various data sources |
| - The second category is `Metric Plugin`, such as `Dora`, etc. These plugins do not directly contact the data source but do secondary calculations based on the collected data after the `Data Source Plugin` works |
| |
| ## 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 |
| |
| ```go |
| // 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: |
| |
| ```go |
| []*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: |
| |
| ```go |
| 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) |
| |
| ```go |
| 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](../Overview/KeyConcepts.md#data-scope) 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.go` |
| - `models/domainlayer/ticket/board.go` |
| - `models/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.go` |
| - `plugins/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: |
| |
| ```go |
| 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() bool` |
| - `func (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](https://pkg.go.dev/github.com/apache/incubator-devlake) reference. |