From 80d07657b49e85cbd29f7dba3ad61dcc42a2787f Mon Sep 17 00:00:00 2001 From: Tiexin Guo Date: Mon, 3 Jul 2023 11:14:54 +0800 Subject: [PATCH] grafana official helm chart as dependency (#140) * update * chore: update ci * chore: update ci * chore: update ci * chore: update ci * chore: update ci * chore: update ci * chore: update ciush * chore: update ciush * update docs * update docs --- .github/workflows/deploy-test.yml | 24 +- .github/workflows/release.yaml | 6 +- .github/workflows/yaml-lint.yml | 4 + HelmSetup.md | 188 +- charts/devlake/Chart.lock | 6 + charts/devlake/Chart.yaml | 7 +- charts/devlake/dashboards/BitBucket.json | 970 +++++ .../ComponentAndFileLevelMetrics.json | 1065 ++++++ .../dashboards/ContributorExperience.json | 832 +++++ charts/devlake/dashboards/DORA.json | 1056 ++++++ charts/devlake/dashboards/DORAByTeam.json | 1094 ++++++ charts/devlake/dashboards/DORADebug.json | 3174 +++++++++++++++++ ...oAverageRequirementLeadTimeByAssignee.json | 250 ++ .../dashboards/DemoCommitCountByAuthor.json | 257 ++ .../dashboards/DemoDetailedBugInfo.json | 315 ++ charts/devlake/dashboards/DemoHomepage.json | 191 + ...FastDoWeRespondToCustomerRequirements.json | 223 ++ ...DemoIsThisMonthMoreProductiveThanLast.json | 253 ++ .../DemoWasOurQualityImprovedOrNot.json | 220 ++ .../dashboards/EngineeringOverview.json | 1849 ++++++++++ .../EngineeringThroughputAndCycleTime.json | 1649 +++++++++ ...neeringThroughputAndCycleTimeTeamView.json | 2782 +++++++++++++++ charts/devlake/dashboards/GitHub.json | 2003 +++++++++++ ...ReleaseQualityAndContributionAnalysis.json | 2650 ++++++++++++++ charts/devlake/dashboards/Gitlab.json | 1147 ++++++ charts/devlake/dashboards/Homepage.json | 1039 ++++++ charts/devlake/dashboards/Jenkins.json | 975 +++++ charts/devlake/dashboards/Jira.json | 1031 ++++++ charts/devlake/dashboards/Sonarqube.json | 1058 ++++++ charts/devlake/dashboards/TAPD.json | 1031 ++++++ charts/devlake/dashboards/Teambition.json | 1031 ++++++ charts/devlake/dashboards/WeeklyBugRetro.json | 1681 +++++++++ .../dashboards/WeeklyCommunityRetro.json | 1794 ++++++++++ charts/devlake/dashboards/Zentao.json | 1031 ++++++ charts/devlake/templates/configmaps.yaml | 44 - charts/devlake/templates/deployments.yaml | 111 +- .../grafana-dashboard-configmap.yaml | 64 + charts/devlake/templates/ingresses.yaml | 9 +- charts/devlake/templates/services.yaml | 44 - charts/devlake/templates/statefulsets.yaml | 4 - charts/devlake/values.yaml | 96 +- 41 files changed, 32871 insertions(+), 387 deletions(-) create mode 100644 charts/devlake/Chart.lock create mode 100644 charts/devlake/dashboards/BitBucket.json create mode 100644 charts/devlake/dashboards/ComponentAndFileLevelMetrics.json create mode 100644 charts/devlake/dashboards/ContributorExperience.json create mode 100644 charts/devlake/dashboards/DORA.json create mode 100644 charts/devlake/dashboards/DORAByTeam.json create mode 100644 charts/devlake/dashboards/DORADebug.json create mode 100644 charts/devlake/dashboards/DemoAverageRequirementLeadTimeByAssignee.json create mode 100644 charts/devlake/dashboards/DemoCommitCountByAuthor.json create mode 100644 charts/devlake/dashboards/DemoDetailedBugInfo.json create mode 100644 charts/devlake/dashboards/DemoHomepage.json create mode 100644 charts/devlake/dashboards/DemoHowFastDoWeRespondToCustomerRequirements.json create mode 100644 charts/devlake/dashboards/DemoIsThisMonthMoreProductiveThanLast.json create mode 100644 charts/devlake/dashboards/DemoWasOurQualityImprovedOrNot.json create mode 100644 charts/devlake/dashboards/EngineeringOverview.json create mode 100644 charts/devlake/dashboards/EngineeringThroughputAndCycleTime.json create mode 100644 charts/devlake/dashboards/EngineeringThroughputAndCycleTimeTeamView.json create mode 100644 charts/devlake/dashboards/GitHub.json create mode 100644 charts/devlake/dashboards/GithubReleaseQualityAndContributionAnalysis.json create mode 100644 charts/devlake/dashboards/Gitlab.json create mode 100644 charts/devlake/dashboards/Homepage.json create mode 100644 charts/devlake/dashboards/Jenkins.json create mode 100644 charts/devlake/dashboards/Jira.json create mode 100644 charts/devlake/dashboards/Sonarqube.json create mode 100644 charts/devlake/dashboards/TAPD.json create mode 100644 charts/devlake/dashboards/Teambition.json create mode 100644 charts/devlake/dashboards/WeeklyBugRetro.json create mode 100644 charts/devlake/dashboards/WeeklyCommunityRetro.json create mode 100644 charts/devlake/dashboards/Zentao.json create mode 100644 charts/devlake/templates/grafana-dashboard-configmap.yaml diff --git a/.github/workflows/deploy-test.yml b/.github/workflows/deploy-test.yml index be3ff5c..186684b 100644 --- a/.github/workflows/deploy-test.yml +++ b/.github/workflows/deploy-test.yml @@ -29,7 +29,7 @@ on: paths: - charts/devlake/** - .github/workflows/deploy-test.yml - - '!**.md' + - "!**.md" jobs: deploy-with-helm: @@ -37,10 +37,7 @@ jobs: strategy: fail-fast: false matrix: - database_type: ["mysql-builtin", -# "pgsql-builtin", - "mysql-external" - ] + database_type: ["mysql-builtin", "mysql-external"] steps: - name: Creating kind cluster uses: container-tools/kind-action@v1 @@ -61,8 +58,10 @@ jobs: if: matrix.database_type == 'mysql-external' run: | helm repo add bitnami https://charts.bitnami.com/bitnami + helm repo add grafana https://grafana.github.io/helm-charts helm install mysql bitnami/mysql --set auth.rootPassword=admin --set auth.database=lake --set auth.username=merico --set auth.password=merico # external mysql at service: mysql + helm dep build charts/devlake helm install --wait --timeout 300s deploy-test charts/devlake \ --set service.uiPort=30000 \ --set mysql.useExternal=true \ @@ -74,6 +73,8 @@ jobs: - name: Helm install devlake if: matrix.database_type == 'mysql-builtin' run: | + helm repo add grafana https://grafana.github.io/helm-charts + helm dep build charts/devlake export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}") echo Node IP: ${NODE_IP} helm install --wait --timeout 300s deploy-test charts/devlake \ @@ -82,18 +83,6 @@ jobs: --set option.localtime="" kubectl get pods -o wide kubectl get services -o wide - -# - name: Helm install devlake -# if: matrix.database_type == 'pgsql-builtin' -# run: | -# export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}") -# echo Node IP: ${NODE_IP} -# helm install --wait --timeout 300s deploy-test charts/devlake \ -# --set service.uiPort=30000 \ -# --set option.database=pgsql \ -# --set option.localtime="" -# kubectl get pods -o wide -# kubectl get services -o wide # TODO: using some e2e test code to replace it - name: Curl with endpoints @@ -128,4 +117,3 @@ jobs: echo logs for $pod kubectl logs $pod || echo "" done - diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index de9d994..8e7c49e 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -6,7 +6,7 @@ on: - main paths: - charts/** - - '!**.md' + - "!**.md" jobs: release: runs-on: ubuntu-latest @@ -27,6 +27,10 @@ jobs: echo "installing helm 3..." curl -sSL https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash + - name: Add repositories + run: | + helm repo add grafana https://grafana.github.io/helm-charts + - name: Run chart-releaser uses: ./.github/actions/chart-releaser-action with: diff --git a/.github/workflows/yaml-lint.yml b/.github/workflows/yaml-lint.yml index 033af52..b3f301c 100644 --- a/.github/workflows/yaml-lint.yml +++ b/.github/workflows/yaml-lint.yml @@ -29,5 +29,9 @@ jobs: - uses: actions/checkout@v3 - name: install latest helm run: curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash + - name: Add repositories + run: | + helm repo add grafana https://grafana.github.io/helm-charts + helm dep build charts/devlake - name: lint helm chart run: helm lint charts/devlake --strict diff --git a/HelmSetup.md b/HelmSetup.md index e67cd77..e23c818 100644 --- a/HelmSetup.md +++ b/HelmSetup.md @@ -5,16 +5,18 @@ description: > sidebar_position: 2 --- -## Prerequisites +## 1 Prerequisites - Helm >= 3.6.0 - Kubernetes >= 1.19.0 -## Quick Start +--- + +## 2 Quick Start -#### You can also check https://github.com/apache/incubator-devlake-helm-chart to make contribution +**Check https://github.com/apache/incubator-devlake-helm-chart to contribute!** -### Install +### 2.1 Install To install the chart with release name `devlake`: @@ -24,36 +26,22 @@ helm repo update helm install devlake devlake/devlake --version=0.17.0-beta12 ``` -And visit your devlake from the node port (32001 by default). - -http://YOUR-NODE-IP:32001 - -#### Tips: - -If you are using minikube inside your mac, please use the following command to forward the port: - -```shell -kubectl port-forward service/devlake-ui 30090:4000 -``` - -and open another terminal: +Visit your devlake from the node port (32001 by default): http://YOUR-NODE-IP:32001. -```shell -kubectl port-forward service/devlake-grafana 30091:3000 -``` +_Notes for mac users with minikube:_ -Then you can visit: -config-ui by url `http://YOUR-NODE-IP:30090` -grafana by url `http://YOUR-NODE-IP:30091` +- forward the port: `kubectl port-forward svc/devlake-ui 4000:4000` +- access config-ui: `http://YOUR-NODE-IP:4000/` +- access Grafana dashboard: click the dashboard button in config-ui, or visit `http://YOUR-NODE-IP:4000/grafana/` -### Update +### 2.2 Update ```shell helm repo update helm upgrade --install devlake devlake/devlake --version=0.17.0-beta12 ``` -### Uninstall +### 2.3 Uninstall To uninstall/delete the `devlake` release: @@ -61,9 +49,11 @@ To uninstall/delete the `devlake` release: helm uninstall devlake ``` -## Some example deployments +--- + +## 3 Example Deployments -### Deploy with NodePort +### 3.1 Deploy with NodePort Conditions: @@ -76,7 +66,7 @@ helm install devlake devlake/devlake --set service.uiPort=30000 After deployed, visit devlake: http://192.168.0.6:30000 -### Deploy with Ingress +### 3.2 Deploy with Ingress Conditions: @@ -89,7 +79,7 @@ helm install devlake devlake/devlake --set "ingress.enabled=true,ingress.hostnam After deployed, visit devlake: http://devlake.example.com, and grafana at http://devlake.example.com/grafana -### Deploy with Ingress (Https) +### 3.3 Deploy with Ingress (Https) Conditions: @@ -114,80 +104,74 @@ helm install devlake devlake/devlake \ After deployed, visit devlake: https://devlake-0.example.com:8443, and grafana at https://devlake-0.example.com:8443/grafana -## Parameters +--- + +## 4 Parameters Some useful parameters for the chart, you could also check them in values.yaml -| Parameter | Description | Default | -| ----------------------------------------- | ---------------------------------------------------- | ------------------------ | -| replicaCount | Replica Count for devlake, currently not used | 1 | -| imageTag | The version tag for all images | see Values.yaml | -| mysql.useExternal | If use external mysql server, set true | false | -| mysql.externalServer | External mysql server address | 127.0.0.1 | -| mysql.externalPort | External mysql server port | 3306 | -| mysql.username | username for mysql | merico | -| mysql.password | password for mysql | merico | -| mysql.database | database for mysql | lake | -| mysql.rootPassword | root password for mysql | admin | -| mysql.storage.class | storage class for mysql's volume | "" | -| mysql.storage.size | volume size for mysql's data | 5Gi | -| mysql.image.repository | repository for mysql's image | mysql | -| mysql.image.tag | image tag for mysql's image | 8 | -| mysql.image.pullPolicy | pullPolicy for mysql's image | IfNotPresent | -| mysql.extraLabels | extra labels for mysql's statefulset | {} | -| mysql.securityContext | pod security context values | {} | -| mysql.containerSecurityContext | container security context values | {} | -| grafana.image.repository | repository for grafana's image | apache/devlake-dashboard | -| grafana.image.pullPolicy | pullPolicy for grafana's image | Always | -| grafana.useExternal | If use external grafana server | false | -| grafana.externalUrl | external grafana server if use external | "" | -| grafana.extraLabels | extra labels for grafana's statefulset | {} | -| grafana.securityContext | pod security context values | {} | -| grafana.containerSecurityContext | container security context values | {} | -| grafana.oauthEnabled | enable oauth for grafana | false | -| grafana.oauthConfig | a list of env vars used for oauth | {} | -| lake.storage.class | storage class for lake's volume | "" | -| lake.storage.size | volume size for lake's data | 100Mi | -| lake.image.repository | repository for lake's image | apache/devlake | -| lake.image.pullPolicy | pullPolicy for lake's image | Always | -| lake.loggingDir | log dir for the lake server | /app/logs | -| lake.loggingLevel | log level for the lake server | info | -| lake.dotenv | initial configurations for injecting to lake's .env | see Values.yaml | -| lake.extraLabels | extra labels for lake's statefulset | {} | -| lake.securityContext | pod security context values | {} | -| lake.containerSecurityContext | container security context values | {} | -| ui.image.repository | repository for ui's image | apache/devlake-config-ui | -| ui.image.pullPolicy | pullPolicy for ui's image | Always | -| ui.basicAuth.enabled | If the basic auth in ui is enabled | false | -| ui.basicAuth.user | The user name for the basic auth | "admin" | -| ui.basicAuth.password | The password for the basic auth | "admin" | -| ui.basicAuth.useSecret | If use secret instead of configmap for basic auth | false | -| ui.basicAuth.autoCreateSecret | If let the helm chart create the secret | true | -| ui.basicAuth.secretName | The basic auth secret name | devlake-auth | -| ui.extraLabels | extra labels for ui's statefulset | {} | -| ui.securityContext | pod security context values | {} | -| ui.containerSecurityContext | container security context values | {} | -| service.type | Service type for exposed service | NodePort | -| service.uiPort | Node port for config ui | 32001 | -| service.ingress.enabled | If enable ingress | false | -| service.ingress.enableHttps | If enable https | false | -| service.ingress.className | Name for ingressClass. leave empty for using default | "" | -| service.ingress.hostname | The hostname/domainname for ingress | localhost | -| service.ingress.prefix | The prefix for endpoints, currently not used | / | -| service.ingress.tlsSecretName | The secret name for tls's certificate for https | "" | -| service.ingress.httpPort | The http port for ingress | 80 | -| service.ingress.httpsPort | The https port for ingress | 443 | -| option.localtime | The hostpath for mount as /etc/localtime | /etc/localtime | -| option.database | The database type, valids: mysql | mysql | -| option.useConnectionDetailsSecret | If use secret instead of configmap for db connection | false | -| option.connectionSecretName | The database connection details secret name | devlake-db-connection | -| option.autoCreateSecret | If let the helm chart create the secret | true | -| awsCognitoAuth.enabled | use AWS cognito for authentication | false | -| awsCognitoAuth.awsAuthRegion | aws Cognito auth region | "" | -| awsCognitoAuth.awsAuthUserPoolID | aws Cognito user pool ID | "" | -| awsCognitoAuth.awsAuthUserPoolWebClientID | aws Cognito web client ID for the user pool | "" | - -## FAQ +| Parameter | Description | Default | +| --------------------------------- | ------------------------------------------------------------------------------------- | ------------------------ | +| replicaCount | Replica Count for devlake, currently not used | 1 | +| imageTag | The version tag for all images | see Values.yaml | +| mysql.useExternal | If use external mysql server, set true | false | +| mysql.externalServer | External mysql server address | 127.0.0.1 | +| mysql.externalPort | External mysql server port | 3306 | +| mysql.username | username for mysql | merico | +| mysql.password | password for mysql | merico | +| mysql.database | database for mysql | lake | +| mysql.rootPassword | root password for mysql | admin | +| mysql.storage.class | storage class for mysql's volume | "" | +| mysql.storage.size | volume size for mysql's data | 5Gi | +| mysql.image.repository | repository for mysql's image | mysql | +| mysql.image.tag | image tag for mysql's image | 8 | +| mysql.image.pullPolicy | pullPolicy for mysql's image | IfNotPresent | +| mysql.extraLabels | extra labels for mysql's statefulset | {} | +| mysql.securityContext | pod security context values | {} | +| mysql.containerSecurityContext | container security context values | {} | +| externalGrafana.useExternal | If use external grafana server | false | +| externalGrafana.grafanaUrl | external grafana server if use external | "" | +| grafana | dashboard, datasource, etc. settings for grafana, installed by grafana official chart | | +| lake.storage.class | storage class for lake's volume | "" | +| lake.storage.size | volume size for lake's data | 100Mi | +| lake.image.repository | repository for lake's image | apache/devlake | +| lake.image.pullPolicy | pullPolicy for lake's image | Always | +| lake.loggingDir | log dir for the lake server | /app/logs | +| lake.loggingLevel | log level for the lake server | info | +| lake.dotenv | initial configurations for injecting to lake's .env | see Values.yaml | +| lake.extraLabels | extra labels for lake's statefulset | {} | +| lake.securityContext | pod security context values | {} | +| lake.containerSecurityContext | container security context values | {} | +| ui.image.repository | repository for ui's image | apache/devlake-config-ui | +| ui.image.pullPolicy | pullPolicy for ui's image | Always | +| ui.basicAuth.enabled | If the basic auth in ui is enabled | false | +| ui.basicAuth.user | The user name for the basic auth | "admin" | +| ui.basicAuth.password | The password for the basic auth | "admin" | +| ui.basicAuth.useSecret | If use secret instead of configmap for basic auth | false | +| ui.basicAuth.autoCreateSecret | If let the helm chart create the secret | true | +| ui.basicAuth.secretName | The basic auth secret name | devlake-auth | +| ui.extraLabels | extra labels for ui's statefulset | {} | +| ui.securityContext | pod security context values | {} | +| ui.containerSecurityContext | container security context values | {} | +| service.type | Service type for exposed service | NodePort | +| service.uiPort | Node port for config ui | 32001 | +| service.ingress.enabled | If enable ingress | false | +| service.ingress.enableHttps | If enable https | false | +| service.ingress.className | Name for ingressClass. leave empty for using default | "" | +| service.ingress.hostname | The hostname/domainname for ingress | localhost | +| service.ingress.prefix | The prefix for endpoints, currently not used | / | +| service.ingress.tlsSecretName | The secret name for tls's certificate for https | "" | +| service.ingress.httpPort | The http port for ingress | 80 | +| service.ingress.httpsPort | The https port for ingress | 443 | +| option.localtime | The hostpath for mount as /etc/localtime | /etc/localtime | +| option.database | The database type, valids: mysql | mysql | +| option.useConnectionDetailsSecret | If use secret instead of configmap for db connection | false | +| option.connectionSecretName | The database connection details secret name | devlake-db-connection | +| option.autoCreateSecret | If let the helm chart create the secret | true | + +--- + +## 5 FAQ 1. Can I use a managed Cloud database service instead of running database in docker? @@ -246,6 +230,8 @@ helm install devlake devlake/devlake \ --set grafana.externalUrl=https://grafana.example.com ``` -## Troubleshooting +--- + +## 6 Troubleshooting If you run into any problem, please check the [Troubleshooting](/Troubleshooting/Installation.md) or [create an issue](https://github.com/apache/incubator-devlake/issues) diff --git a/charts/devlake/Chart.lock b/charts/devlake/Chart.lock new file mode 100644 index 0000000..9bc65a8 --- /dev/null +++ b/charts/devlake/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: grafana + repository: https://grafana.github.io/helm-charts + version: 6.56.6 +digest: sha256:cbe6f07dc05e6699e46ce6da0db5eb937bd3c6203f6a19fc8adcf72f9f7005fb +generated: "2023-05-28T13:53:10.903912+08:00" diff --git a/charts/devlake/Chart.yaml b/charts/devlake/Chart.yaml index 22f8678..f5c36cf 100644 --- a/charts/devlake/Chart.yaml +++ b/charts/devlake/Chart.yaml @@ -28,7 +28,12 @@ keywords: type: application # Chart version -version: 0.17.0-beta12 +version: 0.17.0-gf-dep # devlake version appVersion: v0.17.0-beta12 + +dependencies: +- name: grafana + version: "6.56.6" + repository: "https://grafana.github.io/helm-charts" diff --git a/charts/devlake/dashboards/BitBucket.json b/charts/devlake/dashboards/BitBucket.json new file mode 100644 index 0000000..f6eb480 --- /dev/null +++ b/charts/devlake/dashboards/BitBucket.json @@ -0,0 +1,970 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 13, + "iteration": 1683688425813, + "links": [], + "panels": [ + { + "datasource": null, + "gridPos": { + "h": 3, + "w": 13, + "x": 0, + "y": 0 + }, + "id": 101, + "options": { + "content": "- Use Cases: This dashboard shows the basic Git and Code Review metrics from BitBucket.\n- Data Source Required: BitBucket", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "title": "Dashboard Introduction", + "type": "text" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 3 + }, + "id": 83, + "panels": [], + "title": "1. Contribution (PRs)", + "type": "row" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 4 + }, + "id": 68, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select\n\tcount(*) as pull_request_count\nfrom \n\tpull_requests pr\nwhere\n $__timeFilter(created_date)\n\tand base_repo_id in ($repo_id)\n\t\n\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "1.1 Number of New Pull Requests [Selected Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 18, + "x": 6, + "y": 4 + }, + "id": 77, + "options": { + "barWidth": 0.5, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _prs as(\n SELECT\n DATE_ADD(date(created_date), INTERVAL -DAY(date(created_date))+1 DAY) as time,\n count(*) as pr_count\n FROM pull_requests\n WHERE\n base_repo_id in ($repo_id)\n and $__timeFilter(created_date)\n and created_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\n group by 1\n)\n\nSELECT \n date_format(time,'%M %Y') as month,\n pr_count as \"Pull Request Count\"\nFROM _prs\nORDER BY time\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "1.2 Total Number of New Pull Requests [Each Month]", + "type": "barchart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Merged PR Count", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 54, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 59, + "options": { + "barWidth": 0.5, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "-- The PR/MR statuses are standardized to DevLake's statuses 'OPEN', 'MERGED' and 'CLOSED'. You can check out the original status from the field `original_status`\nselect\n author_name,\n\tcount(*) as merged_pull_request_count\nfrom \n\tpull_requests pr\nwhere\n $__timeFilter(created_date)\n\tand base_repo_id in ($repo_id)\n\tand pr.status = 'MERGED'\ngroup by 1\norder by 2 desc\nlimit 20\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "1.3 Top Contributors By Merged PRs", + "type": "barchart" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 85, + "panels": [], + "title": "2. How PRs are handled?", + "type": "row" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 17 + }, + "id": 66, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "-- The PR/MR statuses are standardized to DevLake's statuses 'OPEN', 'MERGED' and 'CLOSED'. You can check out the original status from the field `original_status`\nselect\n count(distinct case when status='CLOSED' then id else null end)/count(distinct case when status in ('MERGED','CLOSED') then id else null end) as ratio\nfrom \n\tpull_requests pr\nwhere\n $__timeFilter(created_date)\n\tand base_repo_id in ($repo_id)", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "2.1 Ratio of Non-merging Pull Requests of All Closed or Merged PRs", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Pull Request Count", + "axisPlacement": "auto", + "barAlignment": 1, + "drawStyle": "bars", + "fillOpacity": 50, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 18, + "x": 6, + "y": 17 + }, + "id": 79, + "options": { + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "-- The PR/MR statuses are standardized to DevLake's statuses 'OPEN', 'MERGED' and 'CLOSED'. You can check out the original status from the field `original_status`\nSELECT\n DATE_ADD(date(created_date), INTERVAL -DAYOFMONTH(date(created_date))+1 DAY) as time,\n count(distinct case when status = 'OPEN' then id else null end) as \"PR: Open\",\n count(distinct case when status = 'CLOSED' then id else null end) as \"PR: Closed without merging\",\n count(distinct case when status = 'MERGED' then id else null end) as \"PR: Merged\"\nFROM pull_requests\nWHERE\n $__timeFilter(created_date)\n and base_repo_id in ($repo_id)\ngroup by 1\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "2.2 Pull Request Status Distribution [Each Month]", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 23 + }, + "id": 80, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "-- The PR/MR statuses are standardized to DevLake's statuses 'OPEN', 'MERGED' and 'CLOSED'. You can check out the original status from the field `original_status`\nselect\n\tcount(*) as merged_pull_request_count\nfrom \n\tpull_requests pr\nwhere\n $__timeFilter(created_date)\n\tand base_repo_id in ($repo_id)\n\tand pr.status = 'CLOSED'", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "2.3 Number of Pull Requests Closed without Merging [Selected Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Ratio", + "axisPlacement": "auto", + "barAlignment": 1, + "drawStyle": "line", + "fillOpacity": 50, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 18, + "x": 6, + "y": 23 + }, + "id": 81, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "-- The PR/MR statuses are standardized to DevLake's statuses 'OPEN', 'MERGED' and 'CLOSED'. You can check out the original status from the field `original_status`\nSELECT\n DATE_ADD(date(created_date), INTERVAL -DAYOFMONTH(date(created_date))+1 DAY) as time,\n count(distinct case when status = 'CLOSED' then id else null end)/count(distinct case when status in ('MERGED', 'CLOSED') then id else null end) as ratio\nFROM pull_requests\nWHERE\n $__timeFilter(created_date)\n and base_repo_id in ($repo_id)\ngroup by 1\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "2.4 Ratio of Non-merging PRs of All Closed or Merged PRs [Each Month]", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 29 + }, + "id": 72, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select\n\tavg(TIMESTAMPDIFF(Minute,created_date,merged_date)/1440)\nfrom \n\tpull_requests\nwhere \n $__timeFilter(created_date)\n\tand base_repo_id in ($repo_id)\n\tand merged_date is not null\n\n\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "2.5 Mean Time to Merge of Pull Requests in Days [Selected Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 18, + "x": 6, + "y": 29 + }, + "id": 95, + "options": { + "barWidth": 0.5, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _prs as(\n SELECT\n DATE_ADD(date(created_date), INTERVAL -DAY(date(created_date))+1 DAY) as time,\n avg(TIMESTAMPDIFF(Minute,created_date,merged_date)/1440) as time_to_merge\n FROM pull_requests\n WHERE\n $__timeFilter(created_date)\n and base_repo_id in ($repo_id)\n and created_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\n group by 1\n)\n\nSELECT \n date_format(time,'%M %Y') as month,\n time_to_merge as \"Time to Merge\"\nFROM _prs\nORDER BY time\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "2.6 Mean Time to Merge of Pull Requests in Days [Each Month]", + "type": "barchart" + }, + { + "datasource": null, + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 35 + }, + "id": 99, + "options": { + "content": "
\n\nThis dashboard is created based on this [data schema](https://devlake.apache.org/docs/DataModels/DevLakeDomainLayerSchema). Want to add more metrics? Please follow the [guide](https://devlake.apache.org/docs/Configuration/Dashboards/GrafanaUserGuide).", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + } + ], + "refresh": "", + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": "", + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": "mysql", + "definition": "select concat(name, '--', id) as text from repos where id like 'bitbucket%'", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Repo", + "multi": true, + "name": "repo_id", + "options": [], + "query": "select concat(name, '--', id) as text from repos where id like 'bitbucket%'", + "refresh": 1, + "regex": "/^(?.*)--(?.*)$/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-6M", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "BitBucket", + "uid": "4LzQHZa4k", + "version": 8 +} \ No newline at end of file diff --git a/charts/devlake/dashboards/ComponentAndFileLevelMetrics.json b/charts/devlake/dashboards/ComponentAndFileLevelMetrics.json new file mode 100644 index 0000000..d8f08e4 --- /dev/null +++ b/charts/devlake/dashboards/ComponentAndFileLevelMetrics.json @@ -0,0 +1,1065 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "This dashboard shows the metrics collected by gitextractor plugin", + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 20, + "iteration": 1682062815355, + "links": [], + "panels": [ + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 14, + "panels": [], + "title": "file dimension", + "type": "row" + }, + { + "datasource": "-- Mixed --", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 1 + }, + "id": 12, + "options": { + "barWidth": 0.78, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "horizontal", + "showValue": "auto", + "text": {}, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "datasource": "mysql", + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT file_path,\n count(distinct author_name) AS cnt\nFROM commits\nJOIN commit_files\nJOIN repo_commits rc\n ON commit_files.commit_sha = rc.commit_sha\n AND commit_files.commit_sha = commits.sha\nWHERE repo_id IN ($repo_id)\n AND $__timeFilter(commits.authored_date)\n AND file_path REGEXP '($selected_path)'\nGROUP BY file_path\nORDER BY cnt DESC limit 10;", + "refId": "A", + "select": [ + [ + { + "params": [ + "_raw_data_id" + ], + "type": "column" + } + ] + ], + "table": "issue_commits", + "timeColumn": "id", + "timeColumnType": "bigint", + "where": [] + } + ], + "title": "files with maximum number of authors", + "type": "barchart" + }, + { + "datasource": "-- Mixed --", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 1 + }, + "id": 2, + "options": { + "showHeader": true + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "datasource": "mysql", + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "SELECT file_path,\n COUNT(DISTINCT author_name) AS author_count,\n MAX(rst) AS file_total_size,\n MAX(rst) / COUNT(DISTINCT author_name) AS rate\nFROM commits\nJOIN (\n SELECT file_path,\n commit_files.commit_sha,\n SUM(additions - deletions) AS rst\n FROM commit_files\n JOIN repo_commits rc ON commit_files.commit_sha = rc.commit_sha\n WHERE repo_id IN ($repo_id)\n GROUP BY file_path, commit_files.commit_sha\n) a ON a.commit_sha = commits.sha\nGROUP BY file_path\nHAVING author_count > 0\nORDER BY rate DESC\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "largest files with lowest number of authors", + "type": "table" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 9 + }, + "id": 10, + "options": { + "barWidth": 0.8, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "horizontal", + "showValue": "auto", + "text": {}, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "SELECT file_path,\n count(*) AS modified_num\nFROM commits\nJOIN commit_files\nJOIN repo_commits rc\n ON commit_files.commit_sha = rc.commit_sha\n AND sha=commit_files.commit_sha\n AND $__timeFilter(commits.authored_date)\nWHERE repo_id IN ($repo_id) and file_path REGEXP '($selected_path)'\nAND $__timeFilter(commits.authored_date)\nGROUP BY file_path\nORDER BY modified_num desc\nLIMIT 15;", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "files with most modifications", + "type": "barchart" + }, + { + "datasource": "-- Mixed --", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 9 + }, + "id": 8, + "options": { + "barWidth": 0.79, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "horizontal", + "showValue": "auto", + "text": {}, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "datasource": "mysql", + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "SELECT file_path,\n count(*) AS cnt\nFROM commits\nJOIN commit_files\nJOIN repo_commits rc\n ON commit_files.commit_sha = rc.commit_sha\n AND sha=commit_files.commit_sha\nWHERE repo_id IN ($repo_id)\n AND $__timeFilter(commits.authored_date)\nGROUP BY file_path\nORDER BY cnt desc\nLIMIT 10;", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "[total]files with most modifications", + "type": "barchart" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 17 + }, + "id": 6, + "panels": [], + "title": "author dimension", + "type": "row" + }, + { + "datasource": "-- Mixed --", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 18 + }, + "id": 16, + "options": { + "barWidth": 0.79, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "horizontal", + "showValue": "auto", + "text": {}, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "datasource": "mysql", + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "SELECT author_name,\n count(distinct commit_sha) AS commit_nums\nFROM commits\nJOIN repo_commits\nWHERE commits.sha =repo_commits.commit_sha\n AND repo_commits.repo_id IN ($repo_id)\n AND $__timeFilter(commits.authored_date)\nGROUP BY author_name,author_id\nORDER BY commit_nums desc\nLIMIT 10; ", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "commits distribution by author", + "type": "barchart" + }, + { + "datasource": "-- Mixed --", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 79, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 18 + }, + "id": 4, + "options": { + "barWidth": 0.55, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "horizontal", + "showValue": "auto", + "text": {}, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "datasource": "mysql", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "SELECT author_name,\n sum(additions-deletions) AS cnt\nFROM commits\nJOIN repo_commits\nWHERE commits.sha =repo_commits.commit_sha\n AND repo_commits.repo_id IN ($repo_id)\n AND $__timeFilter(commits.authored_date)\nGROUP BY author_name,author_id\nORDER BY cnt DESC \nLIMIT 10;", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "lines of code distribution by author", + "type": "barchart" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 26 + }, + "id": 20, + "panels": [], + "title": "time perspective", + "type": "row" + }, + { + "datasource": "-- Mixed --", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 27 + }, + "id": 22, + "options": { + "barWidth": 0.97, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": {}, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "datasource": "mysql", + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "SELECT\n CASE cast(dayofweek(authored_date) AS char) \n WHEN '1' THEN\n '1.Monday'\n WHEN '2' THEN\n '2.Tuesday'\n WHEN '3' THEN\n '3.Wednesday'\n WHEN '4' THEN\n '4.Thursday'\n WHEN '5' THEN\n '5.Friday'\n WHEN '6' THEN\n '6.Saturday'\n WHEN '7' THEN\n '7.Sunday'\n END AS weekday , count(distinct commit_sha) AS commit_nums\nFROM commits\nJOIN repo_commits\nWHERE $__timeFilter(commits.authored_date)\n AND commits.sha =repo_commits.commit_sha\n AND repo_commits.repo_id IN ($repo_id)\nGROUP BY weekday\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "commits distribution", + "type": "barchart" + }, + { + "cacheTimeout": null, + "datasource": "-- Mixed --", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 27 + }, + "id": 24, + "interval": null, + "links": [], + "options": { + "barWidth": 0.97, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": {}, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "datasource": "mysql", + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "SELECT\n CASE cast(dayofweek(authored_date) AS char)\n WHEN '1' THEN\n '1.Monday'\n WHEN '2' THEN\n '2.Tuesday'\n WHEN '3' THEN\n '3.Wednesday'\n WHEN '4' THEN\n '4.Thursday'\n WHEN '5' THEN\n '5.Friday'\n WHEN '6' THEN\n '6.Saturday'\n WHEN '7' THEN\n '7.Sunday'\n END AS weekday , sum(additions-deletions) AS changed_nums, sum(additions) AS total_additions, sum(deletions) AS total_deletions\nFROM commits\nJOIN repo_commits\nWHERE commits.sha =repo_commits.commit_sha\n AND repo_commits.repo_id IN ($repo_id)\n AND $__timeFilter(commits.authored_date)\nGROUP BY weekday\nORDER BY weekday", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "lines of code distribution", + "type": "barchart" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 35 + }, + "id": 26, + "panels": [], + "title": "lineage dimension", + "type": "row" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 36 + }, + "id": 28, + "options": { + "barWidth": 0.97, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": {}, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "SELECT CASE cast(dayofweek(commits.committed_date) AS char)\n WHEN '1' THEN\n '1.Monday'\n WHEN '2' THEN\n '2.Tuesday'\n WHEN '3' THEN\n '3.Wednesday'\n WHEN '4' THEN\n '4.Thursday'\n WHEN '5' THEN\n '5.Friday'\n WHEN '6' THEN\n '6.Saturday'\n WHEN '7' THEN\n '7.Sunday'\n END AS wd,\n count(*) as lived_lines\nFROM repo_snapshot\n JOIN commits\n ON commits.sha=repo_snapshot.commit_sha\nWHERE repo_snapshot.repo_id IN ($repo_id)\n AND $__timeFilter(commits.committed_date)\nGROUP BY wd\nORDER BY wd ;", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "In which day the code has highest chance to stay in repository.", + "type": "barchart" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 36 + }, + "id": 30, + "options": { + "showHeader": true + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "SELECT file_path,\n avg(timestampdiff(day,\n commits.committed_date,\n now())) AS line_age\nFROM repo_snapshot\nJOIN commits\n ON repo_snapshot.commit_sha = commits.sha\nWHERE repo_snapshot.repo_id IN ($repo_id)\n AND $__timeFilter(commits.committed_date)\nGROUP BY file_path\nORDER BY line_age desc \nLIMIT 20;", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Which file has the longest average line age?", + "type": "table" + } + ], + "refresh": "", + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": "mysql", + "definition": "select concat(name, '--', id) as text from repos", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Repo", + "multi": true, + "name": "repo_id", + "options": [], + "query": "select concat(name, '--', id) as text from repos", + "refresh": 1, + "regex": "/^(?.*)--(?.*)$/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": { + "selected": false, + "text": "", + "value": "" + }, + "description": "input file path", + "error": null, + "hide": 0, + "label": "", + "name": "selected_path", + "options": [ + { + "selected": true, + "text": "", + "value": "" + } + ], + "query": "", + "skipUrlSync": false, + "type": "textbox" + } + ] + }, + "time": { + "from": "now-6M", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Component and File-level Metrics", + "uid": "KxUh7IG4z", + "version": 3 +} \ No newline at end of file diff --git a/charts/devlake/dashboards/ContributorExperience.json b/charts/devlake/dashboards/ContributorExperience.json new file mode 100644 index 0000000..20af955 --- /dev/null +++ b/charts/devlake/dashboards/ContributorExperience.json @@ -0,0 +1,832 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 10, + "iteration": 1683690480749, + "links": [], + "panels": [ + { + "datasource": null, + "gridPos": { + "h": 4, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 24, + "options": { + "content": "- Use Cases: This dashboard answers the question \"What makes a great developer experience? And how can we define and track that?\". This dashboard heavily focuses on actionability. All metrics can be deterministically improved as long as OSS maintainers invested time into them.\n- Data Source Required: GitHub", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "title": "Dashboard Introduction", + "type": "text" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "d" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 4 + }, + "id": 8, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": { + "titleSize": 2 + }, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with issue_comment_list as(\n select\n i.id as issue_id,\n i.url,\n i.title,\n i.created_date as issue_created_date,\n ic.id as comment_id,\n ic.created_date as comment_date,\n ic.body,\n case when ic.id is not null then rank() over (partition by i.id order by ic.created_date asc) else null end as comment_rank\n from\n lake.issues i\n join lake.board_issues bi on i.id = bi.issue_id\n join lake.boards b on bi.board_id = b.id\n left join lake.issue_comments ic on i.id = ic.issue_id\n where\n date(i.created_date) BETWEEN\n curdate() - INTERVAL DAYOFMONTH(curdate())-1 DAY - INTERVAL 1 month and\n curdate() - INTERVAL DAYOFMONTH(curdate()) DAY\n and b.id in ($repo_id)\n)\n\nselect\n avg((TIMESTAMPDIFF(MINUTE, issue_created_date,comment_date))/1440)\nfrom issue_comment_list\nwhere comment_rank = 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Time To Initial Issue Response [Last Month]", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "d" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 4 + }, + "id": 4, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select \n\tAVG(i.lead_time_minutes/1440) issue_lead_time\nfrom \n\tissues i\n\tjoin board_issues bi on i.id = bi.issue_id\n\tjoin boards b on bi.board_id = b.id\nwhere\n date(i.created_date) BETWEEN\n curdate() - INTERVAL DAYOFMONTH(curdate())-1 DAY - INTERVAL 1 month and\n curdate() - INTERVAL DAYOFMONTH(curdate()) DAY\n and i.status = \"DONE\"\n and b.id in ($repo_id)", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Issue Resolution Time [Last Month]", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 95 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 4 + }, + "id": 12, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with issue_comment_list as(\n select\n i.id as issue_id,\n i.url,\n i.title,\n i.created_date as issue_created_date,\n ic.id as comment_id,\n ic.created_date as comment_date,\n ic.body,\n case when ic.id is not null then rank() over (partition by i.id order by ic.created_date asc) else null end as comment_rank\n from\n lake.issues i\n join lake.board_issues bi on i.id = bi.issue_id\n join lake.boards b on bi.board_id = b.id\n left join lake.issue_comments ic on i.id = ic.issue_id\n where\n date(i.created_date) BETWEEN\n curdate() - INTERVAL DAYOFMONTH(curdate())-1 DAY - INTERVAL 1 month and\n curdate() - INTERVAL DAYOFMONTH(curdate()) DAY\n and b.id in ($repo_id)\n)\n\nselect\n 100 * sum(case when (TIMESTAMPDIFF(MINUTE, issue_created_date,comment_date))/60 < $iir_sla then 1 else null end) / count(*)\nfrom issue_comment_list\nwhere comment_rank = 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Issue Response Rate within SLA [Last Month]", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 18, + "y": 4 + }, + "id": 10, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select\n count(*)\nfrom\n lake.issues i\n join lake.board_issues bi on i.id = bi.issue_id\n join lake.boards b on bi.board_id = b.id\n join lake.issue_labels il on il.issue_id = i.id\nwhere\n il.label_name = \"$label_gfi\" and\n i.status != 'DONE' and\n b.id in ($repo_id)", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Number of Good First Issues [Outstanding]", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "d" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 12 + }, + "id": 16, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with pr_comment_list as(\n select\n pr.id as issue_id,\n pr.url,\n pr.title,\n pr.created_date as pr_created_date,\n prc.id as comment_id,\n prc.created_date as comment_date,\n prc.account_id,\n case when prc.id is not null then rank() over (partition by pr.id order by prc.created_date asc) else null end as comment_rank\n from\n lake.pull_requests pr\n left join lake.pull_request_comments prc on pr.id = prc.pull_request_id\n where\n date(pr.created_date) BETWEEN\n curdate() - INTERVAL DAYOFMONTH(curdate())-1 DAY - INTERVAL 1 month and\n curdate() - INTERVAL DAYOFMONTH(curdate()) DAY\n and pr.base_repo_id in ($repo_id)\n)\n\nselect\n avg((TIMESTAMPDIFF(MINUTE, pr_created_date, comment_date))/1440)\nfrom pr_comment_list\nwhere comment_rank = 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Time to Initial PR Review [Last Month]", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "d" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 12 + }, + "id": 14, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- The PR/MR statuses are standardized to DevLake's statuses 'OPEN', 'MERGED' and 'CLOSED'. You can check out the original status from the field `original_status`\nselect\n\tavg(TIMESTAMPDIFF(Minute,created_date,closed_date)/1440) as time_to_close\nfrom \n\tpull_requests pr\nwhere \n date(created_date) BETWEEN\n curdate() - INTERVAL DAYOFMONTH(curdate())-1 DAY - INTERVAL 1 month and\n curdate() - INTERVAL DAYOFMONTH(curdate()) DAY\n\tand status in ('CLOSED', 'MERGED')\n\tand pr.base_repo_id in ($repo_id)\n\n\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "PR Resolution Time [Last Month]", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 95 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 12, + "y": 12 + }, + "id": 18, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- The PR/MR statuses are standardized to DevLake's statuses 'OPEN', 'MERGED' and 'CLOSED'. You can check out the original status from the field `original_status`\nselect\n 100 * sum(case when TIMESTAMPDIFF(Minute, created_date, closed_date) / 1440 < $prrt_sla then 1 else null end) / count(*)\nfrom \n\tpull_requests pr\nwhere \n date(created_date) BETWEEN\n curdate() - INTERVAL DAYOFMONTH(curdate())-1 DAY - INTERVAL 1 month and\n curdate() - INTERVAL DAYOFMONTH(curdate()) DAY\n\tand status in ('CLOSED', 'MERGED')\n\tand pr.base_repo_id in ($repo_id)\n\n\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "PR Resolution Rate within SLA [Last Month]", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 60 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 18, + "y": 12 + }, + "id": 20, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- The PR/MR statuses are standardized to DevLake's statuses 'OPEN', 'MERGED' and 'CLOSED'. You can check out the original status from the field `original_status`\nselect\n 100 * count(distinct case when status = 'CLOSED' then id else null end)/count(distinct case when status in ('CLOSED', 'MERGED') then id else null end) as ratio\nfrom \n\tpull_requests pr\nwhere\n date(created_date) BETWEEN\n curdate() - INTERVAL DAYOFMONTH(curdate())-1 DAY - INTERVAL 1 month and\n curdate() - INTERVAL DAYOFMONTH(curdate()) DAY\n and pr.base_repo_id in ($repo_id)", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "PR Closed W/O Merging Ratio [Last Month]", + "type": "stat" + }, + { + "datasource": null, + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 22, + "options": { + "content": "
\n\nThis dashboard is created based on this [data schema](https://devlake.apache.org/docs/DataModels/DevLakeDomainLayerSchema). Want to add more metrics? Please follow the [guide](https://devlake.apache.org/docs/Configuration/Dashboards/GrafanaUserGuide).", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + } + ], + "refresh": "", + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "mysql", + "definition": "select concat(name, '-', id) from lake.repos", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Repo", + "multi": true, + "name": "repo_id", + "options": [], + "query": "select concat(name, '-', id) from lake.repos", + "refresh": 1, + "regex": "/^(?.*)-(?.*)$/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "current": { + "selected": true, + "text": "24", + "value": "24" + }, + "description": null, + "error": null, + "hide": 0, + "label": "Time to Initial Issue Response SLA (in hours)", + "name": "iir_sla", + "options": [ + { + "selected": true, + "text": "24", + "value": "24" + } + ], + "query": "24", + "skipUrlSync": false, + "type": "textbox" + }, + { + "current": { + "selected": true, + "text": "7", + "value": "7" + }, + "description": null, + "error": null, + "hide": 0, + "label": "PR Resolution Time SLA (in days)", + "name": "prrt_sla", + "options": [ + { + "selected": true, + "text": "7", + "value": "7" + } + ], + "query": "7", + "skipUrlSync": false, + "type": "textbox" + }, + { + "current": { + "selected": false, + "text": "good first issue", + "value": "good first issue" + }, + "description": null, + "error": null, + "hide": 0, + "label": "Label for good first issues", + "name": "label_gfi", + "options": [ + { + "selected": true, + "text": "good first issue", + "value": "good first issue" + } + ], + "query": "good first issue", + "skipUrlSync": false, + "type": "textbox" + } + ] + }, + "time": { + "from": "now-6M", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Contributor Experience", + "uid": "bwsP5Nz4z", + "version": 6 +} \ No newline at end of file diff --git a/charts/devlake/dashboards/DORA.json b/charts/devlake/dashboards/DORA.json new file mode 100644 index 0000000..7cc119d --- /dev/null +++ b/charts/devlake/dashboards/DORA.json @@ -0,0 +1,1056 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 21, + "iteration": 1684326672244, + "links": [], + "panels": [ + { + "datasource": null, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 16, + "options": { + "content": "- See [how to config](https://devlake.apache.org/docs/DORA) this dashboard\n- Data Sources Required: \n - `Deployments` from Jenkins, GitLab CI, GitHub Action, webhook, etc. \n - `Pull Requests` from GitHub PRs, GitLab MRs, BitBucket PRs, Azure DevOps PRs, etc.\n - `Incidents` from Jira issues, GitHub issues, TAPD issues, PagerDuty Incidents, etc. \n- Transformation Required: Define `deployments` and `incidents` in [data transformations](https://devlake.apache.org/docs/Configuration/Tutorial#step-3---add-transformations-optional) while configuring the blueprint of a project.\n- You can validate/debug this dashboard with the [DORA validation dashboard](/grafana/d/KGkUnV-Vz/dora-dashboard-validation)", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "title": "Dashboard Introduction", + "type": "text" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto", + "filterable": false + }, + "mappings": [], + "noValue": "-", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "low" + }, + "properties": [ + { + "id": "custom.displayMode", + "value": "color-text" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "medium" + }, + "properties": [ + { + "id": "custom.displayMode", + "value": "color-text" + }, + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "high" + }, + "properties": [ + { + "id": "custom.displayMode", + "value": "color-text" + }, + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "elite" + }, + "properties": [ + { + "id": "custom.displayMode", + "value": "color-text" + }, + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 8, + "options": { + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Metric 1: Deployment Frequency\nwith last_few_calendar_months as(\n-- construct the last few calendar months within the selected time period in the top-right corner\n\tSELECT CAST((SYSDATE()-INTERVAL (H+T+U) DAY) AS date) day\n\tFROM ( SELECT 0 H\n\t\t\tUNION ALL SELECT 100 UNION ALL SELECT 200 UNION ALL SELECT 300\n\t\t) H CROSS JOIN ( SELECT 0 T\n\t\t\tUNION ALL SELECT 10 UNION ALL SELECT 20 UNION ALL SELECT 30\n\t\t\tUNION ALL SELECT 40 UNION ALL SELECT 50 UNION ALL SELECT 60\n\t\t\tUNION ALL SELECT 70 UNION ALL SELECT 80 UNION ALL SELECT 90\n\t\t) T CROSS JOIN ( SELECT 0 U\n\t\t\tUNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3\n\t\t\tUNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6\n\t\t\tUNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9\n\t\t) U\n\tWHERE\n\t\t(SYSDATE()-INTERVAL (H+T+U) DAY) > $__timeFrom()\n),\n\n_production_deployment_days as(\n-- When deploying multiple commits in one pipeline, GitLab and BitBucket may generate more than one deployment. However, DevLake consider these deployments as ONE production deployment and use the last one's finished_date as the finished date.\n\tSELECT\n\t\tcdc.cicd_deployment_id as deployment_id,\n\t\tmax(DATE(cdc.finished_date)) as day\n\tFROM cicd_deployment_commits cdc\n\tJOIN project_mapping pm on cdc.cicd_scope_id = pm.row_id and pm.`table` = 'cicd_scopes'\n\tWHERE\n\t\tpm.project_name in ($project)\n\t\tand cdc.result = 'SUCCESS'\n\t\tand cdc.environment = 'PRODUCTION'\n\tGROUP BY 1\n),\n\n_days_weeks_deploy as(\n-- calculate the number of deployment days every week\n\tSELECT\n\t\t\tdate(DATE_ADD(last_few_calendar_months.day, INTERVAL -WEEKDAY(last_few_calendar_months.day) DAY)) as week,\n\t\t\tMAX(if(_production_deployment_days.day is not null, 1, 0)) as weeks_deployed,\n\t\t\tCOUNT(distinct _production_deployment_days.day) as days_deployed\n\tFROM \n\t\tlast_few_calendar_months\n\t\tLEFT JOIN _production_deployment_days ON _production_deployment_days.day = last_few_calendar_months.day\n\tGROUP BY week\n\t),\n\n_monthly_deploy as(\n-- calculate the number of deployment days every month\n\tSELECT\n\t\t\tdate(DATE_ADD(last_few_calendar_months.day, INTERVAL -DAY(last_few_calendar_months.day)+1 DAY)) as month,\n\t\t\tMAX(if(_production_deployment_days.day is not null, 1, 0)) as months_deployed\n\tFROM \n\t\tlast_few_calendar_months\n\t\tLEFT JOIN _production_deployment_days ON _production_deployment_days.day = last_few_calendar_months.day\n\tGROUP BY month\n\t),\n\n_median_number_of_deployment_days_per_week_ranks as(\n\tSELECT *, percent_rank() over(order by days_deployed) as ranks\n\tFROM _days_weeks_deploy\n),\n\n_median_number_of_deployment_days_per_week as(\n\tSELECT max(days_deployed) as median_number_of_deployment_days_per_week\n\tFROM _median_number_of_deployment_days_per_week_ranks\n\tWHERE ranks <= 0.5\n),\n\n_median_number_of_deployment_days_per_month_ranks as(\n\tSELECT *, percent_rank() over(order by months_deployed) as ranks\n\tFROM _monthly_deploy\n),\n\n_median_number_of_deployment_days_per_month as(\n\tSELECT max(months_deployed) as median_number_of_deployment_days_per_month\n\tFROM _median_number_of_deployment_days_per_month_ranks\n\tWHERE ranks <= 0.5\n),\n\n_metric_deployment_frequency as (\n\tSELECT \n\t\t'Deployment frequency' as metric,\n\t\tCASE \n\t\t\tWHEN median_number_of_deployment_days_per_week >= 3 THEN 'On-demand'\n\t\t\tWHEN median_number_of_deployment_days_per_week >= 1 THEN 'Between once per week and once per month'\n\t\t\tWHEN median_number_of_deployment_days_per_month >= 1 THEN 'Between once per month and once every 6 months'\n\t\t\tELSE 'Fewer than once per six months' END AS value\n\tFROM _median_number_of_deployment_days_per_week, _median_number_of_deployment_days_per_month\n),\n\n-- Metric 2: median lead time for changes\n_pr_stats as (\n-- get the cycle time of PRs deployed by the deployments finished in the selected period\n\tSELECT\n\t\tdistinct pr.id,\n\t\tppm.pr_cycle_time\n\tFROM\n\t\tpull_requests pr \n\t\tjoin project_pr_metrics ppm on ppm.id = pr.id\n\t\tjoin project_mapping pm on pr.base_repo_id = pm.row_id and pm.`table` = 'repos'\n\t\tjoin cicd_deployment_commits cdc on ppm.deployment_commit_id = cdc.id\n\tWHERE\n\t pm.project_name in ($project) \n\t\tand pr.merged_date is not null\n\t\tand ppm.pr_cycle_time is not null\n\t\tand $__timeFilter(cdc.finished_date)\n),\n\n_median_change_lead_time_ranks as(\n\tSELECT *, percent_rank() over(order by pr_cycle_time) as ranks\n\tFROM _pr_stats\n),\n\n_median_change_lead_time as(\n-- use median PR cycle time as the median change lead time\n\tSELECT max(pr_cycle_time) as median_change_lead_time\n\tFROM _median_change_lead_time_ranks\n\tWHERE ranks <= 0.5\n),\n\n_metric_change_lead_time as (\n\tSELECT \n\t\t'Lead time for changes' as metric,\n\t\tCASE\n\t\t\tWHEN median_change_lead_time < 60 then \"Less than one hour\"\n\t\t\tWHEN median_change_lead_time < 7 * 24 * 60 then \"Less than one week\"\n\t\t\tWHEN median_change_lead_time < 180 * 24 * 60 then \"Between one week and six months\"\n\t\t\tELSE \"More than six months\"\n\t\t\tEND as value\nFROM _median_change_lead_time\n),\n\n\n-- Metric 3: Median time to restore service \n_incidents as (\n-- get the incidents created within the selected time period in the top-right corner\n\tSELECT\n\t distinct i.id,\n\t\tcast(lead_time_minutes as signed) as lead_time_minutes\n\tFROM\n\t\tissues i\n\t join board_issues bi on i.id = bi.issue_id\n\t join boards b on bi.board_id = b.id\n\t join project_mapping pm on b.id = pm.row_id and pm.`table` = 'boards'\n\tWHERE\n\t pm.project_name in ($project)\n\t\tand i.type = 'INCIDENT'\n\t\tand $__timeFilter(i.created_date)\n),\n\n_median_mttr_ranks as(\n\tSELECT *, percent_rank() over(order by lead_time_minutes) as ranks\n\tFROM _incidents\n),\n\n_median_mttr as(\n\tSELECT max(lead_time_minutes) as median_time_to_resolve\n\tFROM _median_mttr_ranks\n\tWHERE ranks <= 0.5\n),\n\n\n_metric_mttr as (\n\tSELECT \n\t\t'Time to restore service' as metric,\n\t\tcase\n\t\t\tWHEN median_time_to_resolve < 60 then \"Less than one hour\"\n\t\t\tWHEN median_time_to_resolve < 24 * 60 then \"Less than one Day\"\n\t\t\tWHEN median_time_to_resolve < 7 * 24 * 60 then \"Between one day and one week\"\n\t\t\tELSE \"More than one week\"\n\t\t\tEND as value\n\tFROM \n\t\t_median_mttr\n),\n\n-- Metric 4: change failure rate\n_deployments as (\n-- When deploying multiple commits in one pipeline, GitLab and BitBucket may generate more than one deployment. However, DevLake consider these deployments as ONE production deployment and use the last one's finished_date as the finished date.\n\tSELECT\n\t\tcdc.cicd_deployment_id as deployment_id,\n\t\tmax(cdc.finished_date) as deployment_finished_date\n\tFROM \n\t\tcicd_deployment_commits cdc\n\t\tJOIN project_mapping pm on cdc.cicd_scope_id = pm.row_id and pm.`table` = 'cicd_scopes'\n\tWHERE\n\t\tpm.project_name in ($project)\n\t\tand cdc.result = 'SUCCESS'\n\t\tand cdc.environment = 'PRODUCTION'\n\tGROUP BY 1\n\tHAVING $__timeFilter(max(cdc.finished_date))\n),\n\n_failure_caused_by_deployments as (\n-- calculate the number of incidents caused by each deployment\n\tSELECT\n\t\td.deployment_id,\n\t\td.deployment_finished_date,\n\t\tcount(distinct case when i.type = 'INCIDENT' then d.deployment_id else null end) as has_incident\n\tFROM\n\t\t_deployments d\n\t\tleft join project_issue_metrics pim on d.deployment_id = pim.deployment_id\n\t\tleft join issues i on pim.id = i.id\n\tGROUP BY 1,2\n),\n\n_change_failure_rate as (\n\tSELECT \n\t\tcase \n\t\t\twhen count(deployment_id) is null then null\n\t\t\telse sum(has_incident)/count(deployment_id) end as change_failure_rate\n\tFROM\n\t\t_failure_caused_by_deployments\n),\n\n_metric_cfr as (\n\tSELECT\n\t\t'Change failure rate' as metric,\n\t\tcase \n\t\t\twhen change_failure_rate <= .15 then \"0-15%\"\n\t\t\twhen change_failure_rate <= .20 then \"16%-20%\"\n\t\t\twhen change_failure_rate <= .30 then \"21%-30%\"\n\t\t\telse \"> 30%\" \n\t\tend as value\n\tFROM \n\t\t_change_failure_rate\n),\n\n_final_results as (\t\n\tSELECT distinct db.id,db.metric,db.low,db.medium,db.high,db.elite,m1.metric as _metric, m1.value FROM dora_benchmarks db\n\tleft join _metric_deployment_frequency m1 on db.metric = m1.metric\n\tWHERE m1.metric is not null\n\t\n\tunion \n\t\n\tSELECT distinct db.id,db.metric,db.low,db.medium,db.high,db.elite,m2.metric as _metric, m2.value FROM dora_benchmarks db\n\tleft join _metric_change_lead_time m2 on db.metric = m2.metric\n\tWHERE m2.metric is not null\n\t\n\tunion \n\t\n\tSELECT distinct db.id,db.metric,db.low,db.medium,db.high,db.elite,m3.metric as _metric, m3.value FROM dora_benchmarks db\n\tleft join _metric_mttr m3 on db.metric = m3.metric\n\tWHERE m3.metric is not null\n\t\n\tunion \n\t\n\tSELECT distinct db.id,db.metric,db.low,db.medium,db.high,db.elite,m4.metric as _metric, m4.value FROM dora_benchmarks db\n\tleft join _metric_cfr m4 on db.metric = m4.metric\n\tWHERE m4.metric is not null\n)\n\n\nSELECT \n\tmetric,\n\tcase when low = value then low else null end as low,\n\tcase when medium = value then medium else null end as medium,\n\tcase when high = value then high else null end as high,\n\tcase when elite = value then elite else null end as elite\nFROM _final_results\nORDER BY id", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Overall DORA Metrics", + "type": "table" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "Between once per month and once every 6 months": { + "color": "yellow", + "index": 1 + }, + "Between once per week and once per month": { + "color": "green", + "index": 2 + }, + "Fewer than once per six months": { + "color": "red", + "index": 0 + }, + "On-demand": { + "color": "purple", + "index": 3 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 0, + "y": 12 + }, + "id": 11, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/^Deployment Frequency$/", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Metric 1: Deployment Frequency\nwith last_few_calendar_months as(\n-- construct the last few calendar months within the selected time period in the top-right corner\n\tSELECT CAST((SYSDATE()-INTERVAL (H+T+U) DAY) AS date) day\n\tFROM ( SELECT 0 H\n\t\t\tUNION ALL SELECT 100 UNION ALL SELECT 200 UNION ALL SELECT 300\n\t\t) H CROSS JOIN ( SELECT 0 T\n\t\t\tUNION ALL SELECT 10 UNION ALL SELECT 20 UNION ALL SELECT 30\n\t\t\tUNION ALL SELECT 40 UNION ALL SELECT 50 UNION ALL SELECT 60\n\t\t\tUNION ALL SELECT 70 UNION ALL SELECT 80 UNION ALL SELECT 90\n\t\t) T CROSS JOIN ( SELECT 0 U\n\t\t\tUNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3\n\t\t\tUNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6\n\t\t\tUNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9\n\t\t) U\n\tWHERE\n\t\t(SYSDATE()-INTERVAL (H+T+U) DAY) > $__timeFrom()\n),\n\n_production_deployment_days as(\n-- When deploying multiple commits in one pipeline, GitLab and BitBucket may generate more than one deployment. However, DevLake consider these deployments as ONE production deployment and use the last one's finished_date as the finished date.\n\tSELECT\n\t\tcdc.cicd_deployment_id as deployment_id,\n\t\tmax(DATE(cdc.finished_date)) as day\n\tFROM cicd_deployment_commits cdc\n\tJOIN project_mapping pm on cdc.cicd_scope_id = pm.row_id and pm.`table` = 'cicd_scopes'\n\tWHERE\n\t\tpm.project_name in ($project)\n\t\tand cdc.result = 'SUCCESS'\n\t\tand cdc.environment = 'PRODUCTION'\n\tGROUP BY 1\n),\n\n_days_weeks_deploy as(\n-- calculate the number of deployment days every week\n\tSELECT\n\t\t\tdate(DATE_ADD(last_few_calendar_months.day, INTERVAL -WEEKDAY(last_few_calendar_months.day) DAY)) as week,\n\t\t\tMAX(if(_production_deployment_days.day is not null, 1, 0)) as weeks_deployed,\n\t\t\tCOUNT(distinct _production_deployment_days.day) as days_deployed\n\tFROM \n\t\tlast_few_calendar_months\n\t\tLEFT JOIN _production_deployment_days ON _production_deployment_days.day = last_few_calendar_months.day\n\tGROUP BY week\n\t),\n\n_monthly_deploy as(\n-- calculate the number of deployment days every month\n\tSELECT\n\t\t\tdate(DATE_ADD(last_few_calendar_months.day, INTERVAL -DAY(last_few_calendar_months.day)+1 DAY)) as month,\n\t\t\tMAX(if(_production_deployment_days.day is not null, 1, 0)) as months_deployed\n\tFROM \n\t\tlast_few_calendar_months\n\t\tLEFT JOIN _production_deployment_days ON _production_deployment_days.day = last_few_calendar_months.day\n\tGROUP BY month\n\t),\n\n_median_number_of_deployment_days_per_week_ranks as(\n\tSELECT *, percent_rank() over(order by days_deployed) as ranks\n\tFROM _days_weeks_deploy\n),\n\n_median_number_of_deployment_days_per_week as(\n\tSELECT max(days_deployed) as median_number_of_deployment_days_per_week\n\tFROM _median_number_of_deployment_days_per_week_ranks\n\tWHERE ranks <= 0.5\n),\n\n_median_number_of_deployment_days_per_month_ranks as(\n\tSELECT *, percent_rank() over(order by months_deployed) as ranks\n\tFROM _monthly_deploy\n),\n\n_median_number_of_deployment_days_per_month as(\n\tSELECT max(months_deployed) as median_number_of_deployment_days_per_month\n\tFROM _median_number_of_deployment_days_per_month_ranks\n\tWHERE ranks <= 0.5\n)\n\nSELECT \n\tCASE \n\t\tWHEN median_number_of_deployment_days_per_week >= 3 THEN 'On-demand'\n\t\tWHEN median_number_of_deployment_days_per_week >= 1 THEN 'Between once per week and once per month'\n\t\tWHEN median_number_of_deployment_days_per_month >= 1 THEN 'Between once per month and once every 6 months'\n\t\tELSE 'Fewer than once per six months' END AS 'Deployment Frequency'\nFROM _median_number_of_deployment_days_per_week, _median_number_of_deployment_days_per_month\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Deployment Frequency", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "Between one week and six months": { + "color": "yellow", + "index": 1 + }, + "Less than one hour": { + "color": "purple", + "index": 3 + }, + "Less than one week": { + "color": "green", + "index": 2 + }, + "More than six months": { + "color": "red", + "index": 0 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 6, + "y": 12 + }, + "id": 12, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/^median_change_lead_time$/", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Metric 2: median lead time for changes\nwith _pr_stats as (\n-- get the cycle time of PRs deployed by the deployments finished in the selected period\n\tSELECT\n\t\tdistinct pr.id,\n\t\tppm.pr_cycle_time\n\tFROM\n\t\tpull_requests pr \n\t\tjoin project_pr_metrics ppm on ppm.id = pr.id\n\t\tjoin project_mapping pm on pr.base_repo_id = pm.row_id and pm.`table` = 'repos'\n\t\tjoin cicd_deployment_commits cdc on ppm.deployment_commit_id = cdc.id\n\tWHERE\n\t pm.project_name in ($project) \n\t\tand pr.merged_date is not null\n\t\tand ppm.pr_cycle_time is not null\n\t\tand $__timeFilter(cdc.finished_date)\n),\n\n_median_change_lead_time_ranks as(\n\tSELECT *, percent_rank() over(order by pr_cycle_time) as ranks\n\tFROM _pr_stats\n),\n\n_median_change_lead_time as(\n-- use median PR cycle time as the median change lead time\n\tSELECT max(pr_cycle_time) as median_change_lead_time\n\tFROM _median_change_lead_time_ranks\n\tWHERE ranks <= 0.5\n)\n\nSELECT \n CASE\n WHEN median_change_lead_time < 60 then \"Less than one hour\"\n WHEN median_change_lead_time < 7 * 24 * 60 then \"Less than one week\"\n WHEN median_change_lead_time < 180 * 24 * 60 then \"Between one week and six months\"\n WHEN median_change_lead_time >= 180 * 24 * 60 then \"More than six months\"\n ELSE \"N/A.Please check if you have collected deployments/incidents.\"\n END as median_change_lead_time\nFROM _median_change_lead_time", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Median Lead Time for Changes", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "Between one day and one week": { + "color": "yellow", + "index": 1 + }, + "Less than one day": { + "color": "green", + "index": 2 + }, + "Less than one hour": { + "color": "purple", + "index": 3 + }, + "More than one week": { + "color": "red", + "index": 0 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 12, + "y": 12 + }, + "id": 13, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/^median_time_to_resolve$/", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Metric 3: Median time to restore service \nwith _incidents as (\n-- get the incidents created within the selected time period in the top-right corner\n\tSELECT\n\t distinct i.id,\n\t\tcast(lead_time_minutes as signed) as lead_time_minutes\n\tFROM\n\t\tissues i\n\t join board_issues bi on i.id = bi.issue_id\n\t join boards b on bi.board_id = b.id\n\t join project_mapping pm on b.id = pm.row_id and pm.`table` = 'boards'\n\tWHERE\n\t pm.project_name in ($project)\n\t\tand i.type = 'INCIDENT'\n\t\tand $__timeFilter(i.created_date)\n),\n\n_median_mttr_ranks as(\n\tSELECT *, percent_rank() over(order by lead_time_minutes) as ranks\n\tFROM _incidents\n),\n\n_median_mttr as(\n\tSELECT max(lead_time_minutes) as median_time_to_resolve\n\tFROM _median_mttr_ranks\n\tWHERE ranks <= 0.5\n)\n\nSELECT \n\tcase\n\t\tWHEN median_time_to_resolve < 60 then \"Less than one hour\"\n WHEN median_time_to_resolve < 24 * 60 then \"Less than one Day\"\n WHEN median_time_to_resolve < 7 * 24 * 60 then \"Between one day and one week\"\n WHEN median_time_to_resolve >= 7 * 24 * 60 then \"More than one week\"\n ELSE \"N/A.Please check if you have collected deployments/incidents.\"\n END as median_time_to_resolve\nFROM \n\t_median_mttr", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Median Time to Restore Service", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "0-15%": { + "color": "purple", + "index": 3 + }, + "16%-20%": { + "color": "green", + "index": 2 + }, + "21%-30%": { + "color": "yellow", + "index": 1 + }, + "> 30%": { + "color": "red", + "index": 0 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 18, + "y": 12 + }, + "id": 14, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/^change_failure_rate$/", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Metric 4: change failure rate\nwith _deployments as (\n-- When deploying multiple commits in one pipeline, GitLab and BitBucket may generate more than one deployment. However, DevLake consider these deployments as ONE production deployment and use the last one's finished_date as the finished date.\n\tSELECT\n\t\tcdc.cicd_deployment_id as deployment_id,\n\t\tmax(cdc.finished_date) as deployment_finished_date\n\tFROM \n\t\tcicd_deployment_commits cdc\n\t\tJOIN project_mapping pm on cdc.cicd_scope_id = pm.row_id and pm.`table` = 'cicd_scopes'\n\tWHERE\n\t\tpm.project_name in ($project)\n\t\tand cdc.result = 'SUCCESS'\n\t\tand cdc.environment = 'PRODUCTION'\n\tGROUP BY 1\n\tHAVING $__timeFilter(max(cdc.finished_date))\n),\n\n_failure_caused_by_deployments as (\n-- calculate the number of incidents caused by each deployment\n\tSELECT\n\t\td.deployment_id,\n\t\td.deployment_finished_date,\n\t\tcount(distinct case when i.type = 'INCIDENT' then d.deployment_id else null end) as has_incident\n\tFROM\n\t\t_deployments d\n\t\tleft join project_issue_metrics pim on d.deployment_id = pim.deployment_id\n\t\tleft join issues i on pim.id = i.id\n\tGROUP BY 1,2\n),\n\n_change_failure_rate as (\n\tSELECT \n\t\tcase \n\t\t\twhen count(deployment_id) is null then null\n\t\t\telse sum(has_incident)/count(deployment_id) end as change_failure_rate\n\tFROM\n\t\t_failure_caused_by_deployments\n)\n\nSELECT\n\tcase \n\t\twhen change_failure_rate <= .15 then \"0-15%\"\n\t\twhen change_failure_rate <= .20 then \"16%-20%\"\n\t\twhen change_failure_rate <= .30 then \"21%-30%\"\n\t\telse \"> 30%\" \n\tend as change_failure_rate\nFROM \n\t_change_failure_rate", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Change Failure Rate", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 17 + }, + "id": 2, + "options": { + "barWidth": 0.6, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": {}, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Metric 1: Number of deployments per month\nwith _deployments as(\n-- When deploying multiple commits in one pipeline, GitLab and BitBucket may generate more than one deployment. However, DevLake consider these deployments as ONE production deployment and use the last one's finished_date as the finished date.\n\tSELECT \n\t\tdate_format(deployment_finished_date,'%y/%m') as month,\n\t\tcount(cicd_deployment_id) as deployment_count\n\tFROM (\n\t\tSELECT\n\t\t\tcdc.cicd_deployment_id,\n\t\t\tmax(cdc.finished_date) as deployment_finished_date\n\t\tFROM cicd_deployment_commits cdc\n\t\tJOIN project_mapping pm on cdc.cicd_scope_id = pm.row_id and pm.`table` = 'cicd_scopes'\n\t\tWHERE\n\t\t\tpm.project_name in ($project)\n\t\t\tand cdc.result = 'SUCCESS'\n\t\t\tand cdc.environment = 'PRODUCTION'\n\t\tGROUP BY 1\n\t\tHAVING $__timeFilter(max(cdc.finished_date))\n\t) _production_deployments\n\tGROUP BY 1\n)\n\nSELECT \n\tcm.month, \n\tcase when d.deployment_count is null then 0 else d.deployment_count end as deployment_count\nFROM \n\tcalendar_months cm\n\tLEFT JOIN _deployments d on cm.month = d.month\n\tWHERE $__timeFilter(cm.month_timestamp)", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Monthly deployments", + "type": "barchart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Hours", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 17 + }, + "id": 6, + "options": { + "barWidth": 0.7, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": {}, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "-- Metric 2: median change lead time per month\nwith _pr_stats as (\n-- get the cycle time of PRs deployed by the deployments finished each month\n\tSELECT\n\t\tdistinct pr.id,\n\t\tdate_format(cdc.finished_date,'%y/%m') as month,\n\t\tppm.pr_cycle_time\n\tFROM\n\t\tpull_requests pr\n\t\tjoin project_pr_metrics ppm on ppm.id = pr.id\n\t\tjoin project_mapping pm on pr.base_repo_id = pm.row_id and pm.`table` = 'repos'\n\t\tjoin cicd_deployment_commits cdc on ppm.deployment_commit_id = cdc.id\n\tWHERE\n\t\tpm.project_name in ($project) \n\t\tand pr.merged_date is not null\n\t\tand ppm.pr_cycle_time is not null\n\t\tand $__timeFilter(cdc.finished_date)\n),\n\n_find_median_clt_each_month_ranks as(\n\tSELECT *, percent_rank() over(PARTITION BY month order by pr_cycle_time) as ranks\n\tFROM _pr_stats\n),\n\n_clt as(\n\tSELECT month, max(pr_cycle_time) as median_change_lead_time\n\tFROM _find_median_clt_each_month_ranks\n\tWHERE ranks <= 0.5\n\tgroup by month\n)\n\nSELECT \n\tcm.month,\n\tcase \n\t\twhen _clt.median_change_lead_time is null then 0 \n\t\telse _clt.median_change_lead_time/60 end as median_change_lead_time_in_hour\nFROM \n\tcalendar_months cm\n\tLEFT JOIN _clt on cm.month = _clt.month\n WHERE $__timeFilter(cm.month_timestamp)", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Median Lead Time for Changes", + "type": "barchart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Hours", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "median_time_to_resolve_in_hour" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 25 + }, + "id": 9, + "options": { + "barWidth": 0.6, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": {}, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "-- Metric 3: median time to restore service - MTTR\nwith _incidents as (\n-- get the number of incidents created each month\n\tSELECT\n\t distinct i.id,\n\t\tdate_format(i.created_date,'%y/%m') as month,\n\t\tcast(lead_time_minutes as signed) as lead_time_minutes\n\tFROM\n\t\tissues i\n\t join board_issues bi on i.id = bi.issue_id\n\t join boards b on bi.board_id = b.id\n\t join project_mapping pm on b.id = pm.row_id and pm.`table` = 'boards'\n\tWHERE\n\t pm.project_name in ($project)\n\t\tand i.type = 'INCIDENT'\n\t\tand i.lead_time_minutes is not null\n),\n\n_find_median_mttr_each_month_ranks as(\n\tSELECT *, percent_rank() over(PARTITION BY month order by lead_time_minutes) as ranks\n\tFROM _incidents\n),\n\n_mttr as(\n\tSELECT month, max(lead_time_minutes) as median_time_to_resolve\n\tFROM _find_median_mttr_each_month_ranks\n\tWHERE ranks <= 0.5\n\tGROUP BY month\n)\n\nSELECT \n\tcm.month,\n\tcase \n\t\twhen m.median_time_to_resolve is null then 0 \n\t\telse m.median_time_to_resolve/60 end as median_time_to_resolve_in_hour\nFROM \n\tcalendar_months cm\n\tLEFT JOIN _mttr m on cm.month = m.month\n WHERE $__timeFilter(cm.month_timestamp)", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Median Time to Restore Service", + "type": "barchart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "max": 1, + "min": 0, + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "percentunit" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "change_failure_rate" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 25 + }, + "id": 5, + "options": { + "barWidth": 0.6, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "-- Metric 4: change failure rate per month\nwith _deployments as (\n-- When deploying multiple commits in one pipeline, GitLab and BitBucket may generate more than one deployment. However, DevLake consider these deployments as ONE production deployment and use the last one's finished_date as the finished date.\n\tSELECT\n\t\tcdc.cicd_deployment_id as deployment_id,\n\t\tmax(cdc.finished_date) as deployment_finished_date\n\tFROM \n\t\tcicd_deployment_commits cdc\n\t\tJOIN project_mapping pm on cdc.cicd_scope_id = pm.row_id and pm.`table` = 'cicd_scopes'\n\tWHERE\n\t\tpm.project_name in ($project)\n\t\tand cdc.result = 'SUCCESS'\n\t\tand cdc.environment = 'PRODUCTION'\n\tGROUP BY 1\n\tHAVING $__timeFilter(max(cdc.finished_date))\n),\n\n_failure_caused_by_deployments as (\n-- calculate the number of incidents caused by each deployment\n\tSELECT\n\t\td.deployment_id,\n\t\td.deployment_finished_date,\n\t\tcount(distinct case when i.type = 'INCIDENT' then d.deployment_id else null end) as has_incident\n\tFROM\n\t\t_deployments d\n\t\tleft join project_issue_metrics pim on d.deployment_id = pim.deployment_id\n\t\tleft join issues i on pim.id = i.id\n\tGROUP BY 1,2\n),\n\n_change_failure_rate_for_each_month as (\n\tSELECT \n\t\tdate_format(deployment_finished_date,'%y/%m') as month,\n\t\tcase \n\t\t\twhen count(deployment_id) is null then null\n\t\t\telse sum(has_incident)/count(deployment_id) end as change_failure_rate\n\tFROM\n\t\t_failure_caused_by_deployments\n\tGROUP BY 1\n)\n\nSELECT \n\tcm.month,\n\tcfr.change_failure_rate\nFROM \n\tcalendar_months cm\n\tLEFT JOIN _change_failure_rate_for_each_month cfr on cm.month = cfr.month\n\tWHERE $__timeFilter(cm.month_timestamp)", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Change Failure Rate", + "type": "barchart" + } + ], + "refresh": "", + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": "mysql", + "definition": "select distinct name from projects", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Project", + "multi": true, + "name": "project", + "options": [], + "query": "select distinct name from projects", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-6M", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "DORA", + "uid": "qNo8_0M4z", + "version": 11 +} \ No newline at end of file diff --git a/charts/devlake/dashboards/DORAByTeam.json b/charts/devlake/dashboards/DORAByTeam.json new file mode 100644 index 0000000..611cdeb --- /dev/null +++ b/charts/devlake/dashboards/DORAByTeam.json @@ -0,0 +1,1094 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" + }, + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 44, + "iteration": 1683291538967, + "links": [], + "liveNow": false, + "panels": [ + { + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 16, + "options": { + "content": "- See [how to config](https://devlake.apache.org/docs/DORA) this dashboard\n- Data Sources Required: \n - `Deployments` from Jenkins, GitLab CI, GitHub Action, webhook, etc. \n - `Pull Requests` from GitHub PRs, GitLab MRs, BitBucket PRs, Azure DevOps PRs, etc.\n - `Incidents` from Jira issues, GitHub issues, TAPD issues, PagerDuty Incidents, etc. \n- Transformation Required: Define `deployments` and `incidents` in [data transformations](https://devlake.apache.org/docs/Configuration/Tutorial#step-3---add-transformations-optional) while configuring the blueprint of a project.\n- You can validate/debug this dashboard with the [DORA validation dashboard](/grafana/d/KGkUnV-Vz/dora-dashboard-validation) \n- You also need to do [team configuration](https://devlake.apache.org/docs/Configuration/TeamConfiguration) to use this dashboard. \n \nHow does this work? \n- Gets the author of the specific commit and then navigates to the team the user belongs to. \n- Gets the team from the PR's author. \n- Gets the team from the commit author.", + "mode": "markdown" + }, + "pluginVersion": "8.4.7", + "title": "Dashboard Introduction", + "type": "text" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto", + "filterable": false + }, + "mappings": [], + "noValue": "-", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "low" + }, + "properties": [ + { + "id": "custom.displayMode", + "value": "color-text" + }, + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "medium" + }, + "properties": [ + { + "id": "custom.displayMode", + "value": "color-text" + }, + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "high" + }, + "properties": [ + { + "id": "custom.displayMode", + "value": "color-text" + }, + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "elite" + }, + "properties": [ + { + "id": "custom.displayMode", + "value": "color-text" + }, + { + "id": "color", + "value": { + "fixedColor": "purple", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 2 + }, + "id": 8, + "options": { + "footer": { + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "8.4.7", + "targets": [ + { + "datasource": "mysql", + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Metric 1: Deployment Frequency\nwith last_few_calendar_months as(\n-- construct the last few calendar months within the selected time period in the top-right corner\n\tSELECT CAST((SYSDATE()-INTERVAL (H+T+U) DAY) AS date) day\n\tFROM ( SELECT 0 H\n\t\t\tUNION ALL SELECT 100 UNION ALL SELECT 200 UNION ALL SELECT 300\n\t\t) H CROSS JOIN ( SELECT 0 T\n\t\t\tUNION ALL SELECT 10 UNION ALL SELECT 20 UNION ALL SELECT 30\n\t\t\tUNION ALL SELECT 40 UNION ALL SELECT 50 UNION ALL SELECT 60\n\t\t\tUNION ALL SELECT 70 UNION ALL SELECT 80 UNION ALL SELECT 90\n\t\t) T CROSS JOIN ( SELECT 0 U\n\t\t\tUNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3\n\t\t\tUNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6\n\t\t\tUNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9\n\t\t) U\n\tWHERE\n\t\t(SYSDATE()-INTERVAL (H+T+U) DAY) > $__timeFrom()\n),\n\n_production_deployment_days as(\n-- When deploying multiple commits in one pipeline, GitLab and BitBucket may generate more than one deployment. However, DevLake consider these deployments as ONE production deployment and use the last one's finished_date as the finished date.\n\tSELECT\n\t\tcdc.cicd_deployment_id as deployment_id,\n\t\tmax(DATE(cdc.finished_date)) as day\n\tFROM cicd_deployment_commits cdc\n\tJOIN commits c on cdc.commit_sha = c.sha\n\tjoin user_accounts ua on c.author_id = ua.account_id\n join users u on ua.user_id = u.id\n join team_users tu on u.id = tu.user_id\n join teams t on tu.team_id = t.id\n\tJOIN project_mapping pm on cdc.cicd_scope_id = pm.row_id\n\tWHERE\n\t\tt.name in ($team)\n\t\tand cdc.result = 'SUCCESS'\n\t\tand cdc.environment = 'PRODUCTION'\n\tGROUP BY 1\n),\n\n_days_weeks_deploy as(\n-- calculate the number of deployment days every week\n\tSELECT\n\t\t\tdate(DATE_ADD(last_few_calendar_months.day, INTERVAL -WEEKDAY(last_few_calendar_months.day) DAY)) as week,\n\t\t\tMAX(if(_production_deployment_days.day is not null, 1, 0)) as weeks_deployed,\n\t\t\tCOUNT(distinct _production_deployment_days.day) as days_deployed\n\tFROM \n\t\tlast_few_calendar_months\n\t\tLEFT JOIN _production_deployment_days ON _production_deployment_days.day = last_few_calendar_months.day\n\tGROUP BY week\n\t),\n\n_monthly_deploy as(\n-- calculate the number of deployment days every month\n\tSELECT\n\t\t\tdate(DATE_ADD(last_few_calendar_months.day, INTERVAL -DAY(last_few_calendar_months.day)+1 DAY)) as month,\n\t\t\tMAX(if(_production_deployment_days.day is not null, 1, 0)) as months_deployed\n\tFROM \n\t\tlast_few_calendar_months\n\t\tLEFT JOIN _production_deployment_days ON _production_deployment_days.day = last_few_calendar_months.day\n\tGROUP BY month\n\t),\n\n_median_number_of_deployment_days_per_week_ranks as(\n\tSELECT *, percent_rank() over(order by days_deployed) as ranks\n\tFROM _days_weeks_deploy\n),\n\n_median_number_of_deployment_days_per_week as(\n\tSELECT max(days_deployed) as median_number_of_deployment_days_per_week\n\tFROM _median_number_of_deployment_days_per_week_ranks\n\tWHERE ranks <= 0.5\n),\n\n_median_number_of_deployment_days_per_month_ranks as(\n\tSELECT *, percent_rank() over(order by months_deployed) as ranks\n\tFROM _monthly_deploy\n),\n\n_median_number_of_deployment_days_per_month as(\n\tSELECT max(months_deployed) as median_number_of_deployment_days_per_month\n\tFROM _median_number_of_deployment_days_per_month_ranks\n\tWHERE ranks <= 0.5\n),\n\n_metric_deployment_frequency as (\n\tSELECT \n\t\t'Deployment frequency' as metric,\n\t\tCASE \n\t\t\tWHEN median_number_of_deployment_days_per_week >= 3 THEN 'On-demand'\n\t\t\tWHEN median_number_of_deployment_days_per_week >= 1 THEN 'Between once per week and once per month'\n\t\t\tWHEN median_number_of_deployment_days_per_month >= 1 THEN 'Between once per month and once every 6 months'\n\t\t\tELSE 'Fewer than once per six months' END AS value\n\tFROM _median_number_of_deployment_days_per_week, _median_number_of_deployment_days_per_month\n),\n\n-- Metric 2: median lead time for changes\n_pr_stats as (\n-- get the cycle time of PRs deployed by the deployments finished in the selected period\n\tSELECT\n\t\tdistinct pr.id,\n\t\tppm.pr_cycle_time\n\tFROM\n\t\tpull_requests pr\n\t\tjoin user_accounts ua on pr.author_id = ua.account_id\n \tjoin users u on ua.user_id = u.id\n \tjoin team_users tu on u.id = tu.user_id\n \tjoin teams t on tu.team_id = t.id\n\t\tjoin project_pr_metrics ppm on ppm.id = pr.id\n\t\tjoin project_mapping pm on pr.base_repo_id = pm.row_id\n\t\tjoin cicd_deployment_commits cdc on ppm.deployment_commit_id = cdc.id\n\tWHERE\n\t t.name in ($team) \n\t\tand pr.merged_date is not null\n\t\tand ppm.pr_cycle_time is not null\n\t\tand $__timeFilter(cdc.finished_date)\n),\n\n_median_change_lead_time_ranks as(\n\tSELECT *, percent_rank() over(order by pr_cycle_time) as ranks\n\tFROM _pr_stats\n),\n\n_median_change_lead_time as(\n-- use median PR cycle time as the median change lead time\n\tSELECT max(pr_cycle_time) as median_change_lead_time\n\tFROM _median_change_lead_time_ranks\n\tWHERE ranks <= 0.5\n),\n\n_metric_change_lead_time as (\n\tSELECT \n\t\t'Lead time for changes' as metric,\n\t\tCASE\n\t\t\tWHEN median_change_lead_time < 60 then \"Less than one hour\"\n\t\t\tWHEN median_change_lead_time < 7 * 24 * 60 then \"Less than one week\"\n\t\t\tWHEN median_change_lead_time < 180 * 24 * 60 then \"Between one week and six months\"\n\t\t\tELSE \"More than six months\"\n\t\t\tEND as value\nFROM _median_change_lead_time\n),\n\n\n-- Metric 3: Median time to restore service \n_incidents as (\n-- get the incidents created within the selected time period in the top-right corner\n\tSELECT\n\t distinct i.id,\n\t\tcast(lead_time_minutes as signed) as lead_time_minutes\n\tFROM\n\t\tissues i\n\t join board_issues bi on i.id = bi.issue_id\n\t join boards b on bi.board_id = b.id\n\t join project_mapping pm on b.id = pm.row_id\n\t join user_accounts ua on i.assignee_id = ua.account_id\n join users u on ua.user_id = u.id\n join team_users tu on u.id = tu.user_id\n join teams t on tu.team_id = t.id\n\tWHERE\n\t t.name in ($team)\n\t\tand i.type = 'INCIDENT'\n\t\tand $__timeFilter(i.created_date)\n),\n\n_median_mttr_ranks as(\n\tSELECT *, percent_rank() over(order by lead_time_minutes) as ranks\n\tFROM _incidents\n),\n\n_median_mttr as(\n\tSELECT max(lead_time_minutes) as median_time_to_resolve\n\tFROM _median_mttr_ranks\n\tWHERE ranks <= 0.5\n),\n\n\n_metric_mttr as (\n\tSELECT \n\t\t'Time to restore service' as metric,\n\t\tcase\n\t\t\tWHEN median_time_to_resolve < 60 then \"Less than one hour\"\n\t\t\tWHEN median_time_to_resolve < 24 * 60 then \"Less than one Day\"\n\t\t\tWHEN median_time_to_resolve < 7 * 24 * 60 then \"Between one day and one week\"\n\t\t\tELSE \"More than one week\"\n\t\t\tEND as value\n\tFROM \n\t\t_median_mttr\n),\n\n-- Metric 4: change failure rate\n_deployments as (\n-- When deploying multiple commits in one pipeline, GitLab and BitBucket may generate more than one deployment. However, DevLake consider these deployments as ONE production deployment and use the last one's finished_date as the finished date.\n\tSELECT\n\t\tcdc.cicd_deployment_id as deployment_id,\n\t\tmax(cdc.finished_date) as deployment_finished_date\n\tFROM \n\t\tcicd_deployment_commits cdc\n\t JOIN commits c on cdc.commit_sha = c.sha\n\t join user_accounts ua on c.author_id = ua.account_id\n join users u on ua.user_id = u.id\n join team_users tu on u.id = tu.user_id\n join teams t on tu.team_id = t.id\n\t\tJOIN project_mapping pm on cdc.cicd_scope_id = pm.row_id\n\tWHERE\n\t\tt.name in ($team)\n\t\tand cdc.result = 'SUCCESS'\n\t\tand cdc.environment = 'PRODUCTION'\n\tGROUP BY 1\n\tHAVING $__timeFilter(max(cdc.finished_date))\n),\n\n_failure_caused_by_deployments as (\n-- calculate the number of incidents caused by each deployment\n\tSELECT\n\t\td.deployment_id,\n\t\td.deployment_finished_date,\n\t\tcount(distinct case when i.type = 'INCIDENT' then d.deployment_id else null end) as has_incident\n\tFROM\n\t\t_deployments d\n\t\tleft join project_issue_metrics pim on d.deployment_id = pim.deployment_id\n\t\tleft join issues i on pim.id = i.id\n\tGROUP BY 1,2\n),\n\n_change_failure_rate as (\n\tSELECT \n\t\tcase \n\t\t\twhen count(deployment_id) is null then null\n\t\t\telse sum(has_incident)/count(deployment_id) end as change_failure_rate\n\tFROM\n\t\t_failure_caused_by_deployments\n),\n\n_metric_cfr as (\n\tSELECT\n\t\t'Change failure rate' as metric,\n\t\tcase \n\t\t\twhen change_failure_rate <= .15 then \"0-15%\"\n\t\t\twhen change_failure_rate <= .20 then \"16%-20%\"\n\t\t\twhen change_failure_rate <= .30 then \"21%-30%\"\n\t\t\telse \"> 30%\" \n\t\tend as value\n\tFROM \n\t\t_change_failure_rate\n),\n\n_final_results as (\t\n\tSELECT distinct db.id,db.metric,db.low,db.medium,db.high,db.elite,m1.metric as _metric, m1.value FROM dora_benchmarks db\n\tleft join _metric_deployment_frequency m1 on db.metric = m1.metric\n\tWHERE m1.metric is not null\n\t\n\tunion \n\t\n\tSELECT distinct db.id,db.metric,db.low,db.medium,db.high,db.elite,m2.metric as _metric, m2.value FROM dora_benchmarks db\n\tleft join _metric_change_lead_time m2 on db.metric = m2.metric\n\tWHERE m2.metric is not null\n\t\n\tunion \n\t\n\tSELECT distinct db.id,db.metric,db.low,db.medium,db.high,db.elite,m3.metric as _metric, m3.value FROM dora_benchmarks db\n\tleft join _metric_mttr m3 on db.metric = m3.metric\n\tWHERE m3.metric is not null\n\t\n\tunion \n\t\n\tSELECT distinct db.id,db.metric,db.low,db.medium,db.high,db.elite,m4.metric as _metric, m4.value FROM dora_benchmarks db\n\tleft join _metric_cfr m4 on db.metric = m4.metric\n\tWHERE m4.metric is not null\n)\n\n\nSELECT \n\tmetric,\n\tcase when low = value then low else null end as low,\n\tcase when medium = value then medium else null end as medium,\n\tcase when high = value then high else null end as high,\n\tcase when elite = value then elite else null end as elite\nFROM _final_results\nORDER BY id", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Overall DORA Metrics", + "type": "table" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "Between once per month and once every 6 months": { + "color": "yellow", + "index": 1 + }, + "Between once per week and once per month": { + "color": "green", + "index": 2 + }, + "Fewer than once per six months": { + "color": "red", + "index": 0 + }, + "On-demand": { + "color": "purple", + "index": 3 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 0, + "y": 8 + }, + "id": 11, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/^Deployment Frequency$/", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.4.7", + "targets": [ + { + "datasource": "mysql", + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Metric 1: Deployment Frequency\nwith last_few_calendar_months as(\n-- construct the last few calendar months within the selected time period in the top-right corner\n\tSELECT CAST((SYSDATE()-INTERVAL (H+T+U) DAY) AS date) day\n\tFROM ( SELECT 0 H\n\t\t\tUNION ALL SELECT 100 UNION ALL SELECT 200 UNION ALL SELECT 300\n\t\t) H CROSS JOIN ( SELECT 0 T\n\t\t\tUNION ALL SELECT 10 UNION ALL SELECT 20 UNION ALL SELECT 30\n\t\t\tUNION ALL SELECT 40 UNION ALL SELECT 50 UNION ALL SELECT 60\n\t\t\tUNION ALL SELECT 70 UNION ALL SELECT 80 UNION ALL SELECT 90\n\t\t) T CROSS JOIN ( SELECT 0 U\n\t\t\tUNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3\n\t\t\tUNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6\n\t\t\tUNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9\n\t\t) U\n\tWHERE\n\t\t(SYSDATE()-INTERVAL (H+T+U) DAY) > $__timeFrom()\n),\n\n_production_deployment_days as(\n-- When deploying multiple commits in one pipeline, GitLab and BitBucket may generate more than one deployment. However, DevLake consider these deployments as ONE production deployment and use the last one's finished_date as the finished date.\n\tSELECT\n\t\tcdc.cicd_deployment_id as deployment_id,\n\t\tmax(DATE(cdc.finished_date)) as day\n\tFROM cicd_deployment_commits cdc\n\tJOIN commits c on cdc.commit_sha = c.sha\n\tjoin user_accounts ua on c.author_id = ua.account_id\n join users u on ua.user_id = u.id\n join team_users tu on u.id = tu.user_id\n join teams t on tu.team_id = t.id\n\tJOIN project_mapping pm on cdc.cicd_scope_id = pm.row_id\n\tWHERE\n\t\tt.name in ($team)\n\t\tand cdc.result = 'SUCCESS'\n\t\tand cdc.environment = 'PRODUCTION'\n\tGROUP BY 1\n),\n\n_days_weeks_deploy as(\n-- calculate the number of deployment days every week\n\tSELECT\n\t\t\tdate(DATE_ADD(last_few_calendar_months.day, INTERVAL -WEEKDAY(last_few_calendar_months.day) DAY)) as week,\n\t\t\tMAX(if(_production_deployment_days.day is not null, 1, 0)) as weeks_deployed,\n\t\t\tCOUNT(distinct _production_deployment_days.day) as days_deployed\n\tFROM \n\t\tlast_few_calendar_months\n\t\tLEFT JOIN _production_deployment_days ON _production_deployment_days.day = last_few_calendar_months.day\n\tGROUP BY week\n\t),\n\n_monthly_deploy as(\n-- calculate the number of deployment days every month\n\tSELECT\n\t\t\tdate(DATE_ADD(last_few_calendar_months.day, INTERVAL -DAY(last_few_calendar_months.day)+1 DAY)) as month,\n\t\t\tMAX(if(_production_deployment_days.day is not null, 1, 0)) as months_deployed\n\tFROM \n\t\tlast_few_calendar_months\n\t\tLEFT JOIN _production_deployment_days ON _production_deployment_days.day = last_few_calendar_months.day\n\tGROUP BY month\n\t),\n\n_median_number_of_deployment_days_per_week_ranks as(\n\tSELECT *, percent_rank() over(order by days_deployed) as ranks\n\tFROM _days_weeks_deploy\n),\n\n_median_number_of_deployment_days_per_week as(\n\tSELECT max(days_deployed) as median_number_of_deployment_days_per_week\n\tFROM _median_number_of_deployment_days_per_week_ranks\n\tWHERE ranks <= 0.5\n),\n\n_median_number_of_deployment_days_per_month_ranks as(\n\tSELECT *, percent_rank() over(order by months_deployed) as ranks\n\tFROM _monthly_deploy\n),\n\n_median_number_of_deployment_days_per_month as(\n\tSELECT max(months_deployed) as median_number_of_deployment_days_per_month\n\tFROM _median_number_of_deployment_days_per_month_ranks\n\tWHERE ranks <= 0.5\n)\n\nSELECT \n\tCASE \n\t\tWHEN median_number_of_deployment_days_per_week >= 3 THEN 'On-demand'\n\t\tWHEN median_number_of_deployment_days_per_week >= 1 THEN 'Between once per week and once per month'\n\t\tWHEN median_number_of_deployment_days_per_month >= 1 THEN 'Between once per month and once every 6 months'\n\t\tELSE 'Fewer than once per six months' END AS 'Deployment Frequency'\nFROM _median_number_of_deployment_days_per_week, _median_number_of_deployment_days_per_month\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Deployment Frequency", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "Between one week and six months": { + "color": "yellow", + "index": 1 + }, + "Less than one hour": { + "color": "purple", + "index": 3 + }, + "Less than one week": { + "color": "green", + "index": 2 + }, + "More than six months": { + "color": "red", + "index": 0 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 6, + "y": 8 + }, + "id": 12, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/^median_change_lead_time$/", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.4.7", + "targets": [ + { + "datasource": "mysql", + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Metric 2: median lead time for changes\nwith _pr_stats as (\n-- get the cycle time of PRs deployed by the deployments finished in the selected period\n\tSELECT\n\t\tdistinct pr.id,\n\t\tppm.pr_cycle_time\n\tFROM\n\t\tpull_requests pr\n\t\tjoin user_accounts ua on pr.author_id = ua.account_id\n \tjoin users u on ua.user_id = u.id\n \tjoin team_users tu on u.id = tu.user_id\n \tjoin teams t on tu.team_id = t.id\n\t\tjoin project_pr_metrics ppm on ppm.id = pr.id\n\t\tjoin project_mapping pm on pr.base_repo_id = pm.row_id\n\t\tjoin cicd_deployment_commits cdc on ppm.deployment_commit_id = cdc.id\n\tWHERE\n\t t.name in ($team) \n\t\tand pr.merged_date is not null\n\t\tand ppm.pr_cycle_time is not null\n\t\tand $__timeFilter(cdc.finished_date)\n),\n\n_median_change_lead_time_ranks as(\n\tSELECT *, percent_rank() over(order by pr_cycle_time) as ranks\n\tFROM _pr_stats\n),\n\n_median_change_lead_time as(\n-- use median PR cycle time as the median change lead time\n\tSELECT max(pr_cycle_time) as median_change_lead_time\n\tFROM _median_change_lead_time_ranks\n\tWHERE ranks <= 0.5\n)\n\nSELECT \n CASE\n WHEN median_change_lead_time < 60 then \"Less than one hour\"\n WHEN median_change_lead_time < 7 * 24 * 60 then \"Less than one week\"\n WHEN median_change_lead_time < 180 * 24 * 60 then \"Between one week and six months\"\n WHEN median_change_lead_time >= 180 * 24 * 60 then \"More than six months\"\n ELSE \"N/A.Please check if you have collected deployments/incidents.\"\n END as median_change_lead_time\nFROM _median_change_lead_time", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Median Lead Time for Changes", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "Between one day and one week": { + "color": "yellow", + "index": 1 + }, + "Less than one day": { + "color": "green", + "index": 2 + }, + "Less than one hour": { + "color": "purple", + "index": 3 + }, + "More than one week": { + "color": "red", + "index": 0 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 12, + "y": 8 + }, + "id": 13, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/^median_time_to_resolve$/", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.4.7", + "targets": [ + { + "datasource": "mysql", + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Metric 3: Median time to restore service \nwith _incidents as (\n-- get the incidents created within the selected time period in the top-right corner\n\tSELECT\n\t distinct i.id,\n\t\tcast(lead_time_minutes as signed) as lead_time_minutes\n\tFROM\n\t\tissues i\n\t join board_issues bi on i.id = bi.issue_id\n\t join boards b on bi.board_id = b.id\n\t join project_mapping pm on b.id = pm.row_id\n\t join user_accounts ua on i.assignee_id = ua.account_id\n join users u on ua.user_id = u.id\n join team_users tu on u.id = tu.user_id\n join teams t on tu.team_id = t.id\n\tWHERE\n\t t.name in ($team)\n\t\tand i.type = 'INCIDENT'\n\t\tand $__timeFilter(i.created_date)\n),\n\n_median_mttr_ranks as(\n\tSELECT *, percent_rank() over(order by lead_time_minutes) as ranks\n\tFROM _incidents\n),\n\n_median_mttr as(\n\tSELECT max(lead_time_minutes) as median_time_to_resolve\n\tFROM _median_mttr_ranks\n\tWHERE ranks <= 0.5\n)\n\nSELECT \n\tcase\n\t\tWHEN median_time_to_resolve < 60 then \"Less than one hour\"\n WHEN median_time_to_resolve < 24 * 60 then \"Less than one Day\"\n WHEN median_time_to_resolve < 7 * 24 * 60 then \"Between one day and one week\"\n WHEN median_time_to_resolve >= 7 * 24 * 60 then \"More than one week\"\n ELSE \"N/A.Please check if you have collected deployments/incidents.\"\n END as median_time_to_resolve\nFROM \n\t_median_mttr", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Median Time to Restore Service", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "0-15%": { + "color": "purple", + "index": 3 + }, + "16%-20%": { + "color": "green", + "index": 2 + }, + "21%-30%": { + "color": "yellow", + "index": 1 + }, + "> 30%": { + "color": "red", + "index": 0 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 18, + "y": 8 + }, + "id": 14, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/^change_failure_rate$/", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.4.7", + "targets": [ + { + "datasource": "mysql", + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Metric 4: change failure rate\nwith _deployments as (\n-- When deploying multiple commits in one pipeline, GitLab and BitBucket may generate more than one deployment. However, DevLake consider these deployments as ONE production deployment and use the last one's finished_date as the finished date.\n\tSELECT\n\t\tcdc.cicd_deployment_id as deployment_id,\n\t\tmax(cdc.finished_date) as deployment_finished_date\n\tFROM \n\t\tcicd_deployment_commits cdc\n\t JOIN commits c on cdc.commit_sha = c.sha\n\t join user_accounts ua on c.author_id = ua.account_id\n join users u on ua.user_id = u.id\n join team_users tu on u.id = tu.user_id\n join teams t on tu.team_id = t.id\n\t\tJOIN project_mapping pm on cdc.cicd_scope_id = pm.row_id\n\tWHERE\n\t\tt.name in ($team)\n\t\tand cdc.result = 'SUCCESS'\n\t\tand cdc.environment = 'PRODUCTION'\n\tGROUP BY 1\n\tHAVING $__timeFilter(max(cdc.finished_date))\n),\n\n_failure_caused_by_deployments as (\n-- calculate the number of incidents caused by each deployment\n\tSELECT\n\t\td.deployment_id,\n\t\td.deployment_finished_date,\n\t\tcount(distinct case when i.type = 'INCIDENT' then d.deployment_id else null end) as has_incident\n\tFROM\n\t\t_deployments d\n\t\tleft join project_issue_metrics pim on d.deployment_id = pim.deployment_id\n\t\tleft join issues i on pim.id = i.id\n\tGROUP BY 1,2\n),\n\n_change_failure_rate as (\n\tSELECT \n\t\tcase \n\t\t\twhen count(deployment_id) is null then null\n\t\t\telse sum(has_incident)/count(deployment_id) end as change_failure_rate\n\tFROM\n\t\t_failure_caused_by_deployments\n)\n\nSELECT\n\tcase \n\t\twhen change_failure_rate <= .15 then \"0-15%\"\n\t\twhen change_failure_rate <= .20 then \"16%-20%\"\n\t\twhen change_failure_rate <= .30 then \"21%-30%\"\n\t\telse \"> 30%\" \n\tend as change_failure_rate\nFROM \n\t_change_failure_rate", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Change Failure Rate", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 13 + }, + "id": 2, + "options": { + "barRadius": 0, + "barWidth": 0.6, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "stacking": "none", + "text": {}, + "tooltip": { + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "targets": [ + { + "datasource": "mysql", + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Metric 1: Number of deployments per month\nwith _deployments as(\n-- When deploying multiple commits in one pipeline, GitLab and BitBucket may generate more than one deployment. However, DevLake consider these deployments as ONE production deployment and use the last one's finished_date as the finished date.\n\tSELECT \n\t\tdate_format(deployment_finished_date,'%y/%m') as month,\n\t\tcount(cicd_deployment_id) as deployment_count\n\tFROM (\n\t\tSELECT\n\t\t\tcdc.cicd_deployment_id,\n\t\t\tmax(cdc.finished_date) as deployment_finished_date\n\t\tFROM cicd_deployment_commits cdc\n\t\tJOIN commits c on cdc.commit_sha = c.sha\n\t join user_accounts ua on c.author_id = ua.account_id\n join users u on ua.user_id = u.id\n join team_users tu on u.id = tu.user_id\n join teams t on tu.team_id = t.id\n\t\tJOIN project_mapping pm on cdc.cicd_scope_id = pm.row_id\n\t\tWHERE\n\t\t\tt.name in ($team)\n\t\t\tand cdc.result = 'SUCCESS'\n\t\t\tand cdc.environment = 'PRODUCTION'\n\t\tGROUP BY 1\n\t\tHAVING $__timeFilter(max(cdc.finished_date))\n\t) _production_deployments\n\tGROUP BY 1\n),\n\n_calendar_months as(\n-- construct the calendar months of last 6 months\n\tSELECT date_format(CAST((SYSDATE()-INTERVAL (month_index) MONTH) AS date), '%y/%m') as month\n\tFROM ( SELECT 0 month_index\n\t\t\tUNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3\n\t\t\tUNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6\n\t\t\tUNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9\n\t\t\tUNION ALL SELECT 10 UNION ALL SELECT 11\n\t\t) month_index\n\tWHERE (SYSDATE()-INTERVAL (month_index) MONTH) > SYSDATE()-INTERVAL 6 MONTH\t\n)\n\nSELECT \n\tcm.month, \n\tcase when d.deployment_count is null then 0 else d.deployment_count end as deployment_count\nFROM \n\t_calendar_months cm\n\tleft join _deployments d on cm.month = d.month\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Monthly deployments", + "type": "barchart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Hours", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 13 + }, + "id": 6, + "options": { + "barRadius": 0, + "barWidth": 0.7, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "stacking": "none", + "text": {}, + "tooltip": { + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "datasource": "mysql", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "-- Metric 2: median change lead time per month\nwith _pr_stats as (\n-- get the cycle time of PRs deployed by the deployments finished each month\n\tSELECT\n\t\tdistinct pr.id,\n\t\tdate_format(cdc.finished_date,'%y/%m') as month,\n\t\tppm.pr_cycle_time\n\tFROM\n\t\tpull_requests pr\n\t\tjoin user_accounts ua on pr.author_id = ua.account_id\n \tjoin users u on ua.user_id = u.id\n \tjoin team_users tu on u.id = tu.user_id\n \tjoin teams t on tu.team_id = t.id\n\t\tjoin project_pr_metrics ppm on ppm.id = pr.id\n\t\tjoin project_mapping pm on pr.base_repo_id = pm.row_id\n\t\tjoin cicd_deployment_commits cdc on ppm.deployment_commit_id = cdc.id\n\tWHERE\n\t\tt.name in ($team) \n\t\tand pr.merged_date is not null\n\t\tand ppm.pr_cycle_time is not null\n\t\tand $__timeFilter(cdc.finished_date)\n),\n\n_find_median_clt_each_month_ranks as(\n\tSELECT *, percent_rank() over(PARTITION BY month order by pr_cycle_time) as ranks\n\tFROM _pr_stats\n),\n\n_clt as(\n\tSELECT month, max(pr_cycle_time) as median_change_lead_time\n\tFROM _find_median_clt_each_month_ranks\n\tWHERE ranks <= 0.5\n\tgroup by month\n),\n\n_calendar_months as(\n-- to\tdeal with the month with no incidents\n\tSELECT date_format(CAST((SYSDATE()-INTERVAL (month_index) MONTH) AS date), '%y/%m') as month\n\tFROM ( SELECT 0 month_index\n\t\t\tUNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3\n\t\t\tUNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6\n\t\t\tUNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9\n\t\t\tUNION ALL SELECT 10 UNION ALL SELECT 11\n\t\t) month_index\n\tWHERE (SYSDATE()-INTERVAL (month_index) MONTH) > SYSDATE()-INTERVAL 6 MONTH\t\n)\n\nSELECT \n\tcm.month,\n\tcase \n\t\twhen _clt.median_change_lead_time is null then 0 \n\t\telse _clt.median_change_lead_time/60 end as median_change_lead_time_in_hour\nFROM \n\t_calendar_months cm\n\tleft join _clt on cm.month = _clt.month\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Median Lead Time for Changes", + "type": "barchart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Hours", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "median_time_to_resolve_in_hour" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 21 + }, + "id": 9, + "options": { + "barRadius": 0, + "barWidth": 0.6, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "stacking": "none", + "text": {}, + "tooltip": { + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "datasource": "mysql", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "-- Metric 3: median time to restore service - MTTR\nwith _incidents as (\n-- get the number of incidents created each month\n\tSELECT\n\t distinct i.id,\n\t\tdate_format(i.created_date,'%y/%m') as month,\n\t\tcast(lead_time_minutes as signed) as lead_time_minutes\n\tFROM\n\t\tissues i\n\t join board_issues bi on i.id = bi.issue_id\n\t join boards b on bi.board_id = b.id\n\t join project_mapping pm on b.id = pm.row_id\n\t join user_accounts ua on i.assignee_id = ua.account_id\n join users u on ua.user_id = u.id\n join team_users tu on u.id = tu.user_id\n join teams t on tu.team_id = t.id\n\tWHERE\n\t t.name in ($team)\n\t\tand i.type = 'INCIDENT'\n\t\tand i.lead_time_minutes is not null\n),\n\n_find_median_mttr_each_month_ranks as(\n\tSELECT *, percent_rank() over(PARTITION BY month order by lead_time_minutes) as ranks\n\tFROM _incidents\n),\n\n_mttr as(\n\tSELECT month, max(lead_time_minutes) as median_time_to_resolve\n\tFROM _find_median_mttr_each_month_ranks\n\tWHERE ranks <= 0.5\n\tGROUP BY month\n),\n\n_calendar_months as(\n-- deal with the month with no incidents\n\tSELECT date_format(CAST((SYSDATE()-INTERVAL (month_index) MONTH) AS date), '%y/%m') as month\n\tFROM ( SELECT 0 month_index\n\t\t\tUNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3\n\t\t\tUNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6\n\t\t\tUNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9\n\t\t\tUNION ALL SELECT 10 UNION ALL SELECT 11\n\t\t) month_index\n\tWHERE (SYSDATE()-INTERVAL (month_index) MONTH) > SYSDATE()-INTERVAL 6 MONTH\t\n)\n\nSELECT \n\tcm.month,\n\tcase \n\t\twhen m.median_time_to_resolve is null then 0 \n\t\telse m.median_time_to_resolve/60 end as median_time_to_resolve_in_hour\nFROM \n\t_calendar_months cm\n\tleft join _mttr m on cm.month = m.month\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Median Time to Restore Service", + "type": "barchart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + } + }, + "mappings": [], + "max": 1, + "min": 0, + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "percentunit" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "change_failure_rate" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 21 + }, + "id": 5, + "options": { + "barRadius": 0, + "barWidth": 0.6, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "stacking": "none", + "text": {}, + "tooltip": { + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "datasource": "mysql", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "-- Metric 4: change failure rate per month\nwith _deployments as (\n-- When deploying multiple commits in one pipeline, GitLab and BitBucket may generate more than one deployment. However, DevLake consider these deployments as ONE production deployment and use the last one's finished_date as the finished date.\n\tSELECT\n\t\tcdc.cicd_deployment_id as deployment_id,\n\t\tmax(cdc.finished_date) as deployment_finished_date\n\tFROM \n\t\tcicd_deployment_commits cdc\n\t\tJOIN commits c on cdc.commit_sha = c.sha\n\tjoin user_accounts ua on c.author_id = ua.account_id\n join users u on ua.user_id = u.id\n join team_users tu on u.id = tu.user_id\n join teams t on tu.team_id = t.id\n\tJOIN project_mapping pm on cdc.cicd_scope_id = pm.row_id\n\tWHERE\n\t\tt.name in ($team)\n\t\tand cdc.result = 'SUCCESS'\n\t\tand cdc.environment = 'PRODUCTION'\n\tGROUP BY 1\n\tHAVING $__timeFilter(max(cdc.finished_date))\n),\n\n_failure_caused_by_deployments as (\n-- calculate the number of incidents caused by each deployment\n\tSELECT\n\t\td.deployment_id,\n\t\td.deployment_finished_date,\n\t\tcount(distinct case when i.type = 'INCIDENT' then d.deployment_id else null end) as has_incident\n\tFROM\n\t\t_deployments d\n\t\tleft join project_issue_metrics pim on d.deployment_id = pim.deployment_id\n\t\tleft join issues i on pim.id = i.id\n\tGROUP BY 1,2\n),\n\n_change_failure_rate_for_each_month as (\n\tSELECT \n\t\tdate_format(deployment_finished_date,'%y/%m') as month,\n\t\tcase \n\t\t\twhen count(deployment_id) is null then null\n\t\t\telse sum(has_incident)/count(deployment_id) end as change_failure_rate\n\tFROM\n\t\t_failure_caused_by_deployments\n\tGROUP BY 1\n),\n\n_calendar_months as(\n-- deal with the month with no incidents\n\tSELECT date_format(CAST((SYSDATE()-INTERVAL (month_index) MONTH) AS date), '%y/%m') as month\n\tFROM ( SELECT 0 month_index\n\t\t\tUNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3\n\t\t\tUNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6\n\t\t\tUNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9\n\t\t\tUNION ALL SELECT 10 UNION ALL SELECT 11\n\t\t) month_index\n\tWHERE (SYSDATE()-INTERVAL (month_index) MONTH) > SYSDATE()-INTERVAL 6 MONTH\t\n)\n\nSELECT \n\tcm.month,\n\tcfr.change_failure_rate\nFROM \n\t_calendar_months cm\n\tleft join _change_failure_rate_for_each_month cfr on cm.month = cfr.month\nGROUP BY 1,2\nORDER BY 1 ", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Change Failure Rate", + "type": "barchart" + } + ], + "refresh": "", + "schemaVersion": 35, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "current": { + "selected": true, + "text": [ + "Experience" + ], + "value": [ + "Experience" + ] + }, + "datasource": "mysql", + "definition": "select distinct name from teams", + "hide": 0, + "includeAll": true, + "label": "Team", + "multi": true, + "name": "team", + "options": [], + "query": "select distinct name from teams", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-6M", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "DORA (by Team)", + "uid": "66YkL8y4z", + "version": 14, + "weekStart": "" +} diff --git a/charts/devlake/dashboards/DORADebug.json b/charts/devlake/dashboards/DORADebug.json new file mode 100644 index 0000000..ac09f3b --- /dev/null +++ b/charts/devlake/dashboards/DORADebug.json @@ -0,0 +1,3174 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 11, + "iteration": 1684326676771, + "links": [], + "panels": [ + { + "datasource": null, + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 63, + "options": { + "content": "This dashboard is designed to validate the [DORA dashboard](/grafana/d/qNo8_0M4z/dora?orgId=1).", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "title": "Dashboard Introduction", + "type": "text" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 2 + }, + "id": 20, + "panels": [], + "title": "Check \"Deployment Frequency\"", + "type": "row" + }, + { + "datasource": null, + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 3 + }, + "id": 64, + "options": { + "content": "- See the definition and calculation logic of [Deployment Frequency](https://devlake.apache.org/docs/Metrics/DeploymentFrequency)\n- Data Sources Required: \n - `Deployments` from Jenkins, GitLab CI, GitHub Action, BitBucket Pipelines, or Webhook, etc. \n- Transformation Required: Define `deployments` in [data transformations](https://devlake.apache.org/docs/Configuration/Tutorial#step-3---add-transformations-optional) while configuring the blueprint of a project.", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "rgba(255, 255, 255, 1)", + "mode": "fixed" + }, + "custom": { + "align": "left", + "displayMode": "color-background-solid" + }, + "mappings": [ + { + "options": { + "DEPLOYMENT": { + "color": "green", + "index": 1 + }, + "PRODUCTION": { + "color": "green", + "index": 0 + }, + "SUCCESS": { + "color": "green", + "index": 2 + }, + "This project is selected": { + "color": "green", + "index": 3 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 16, + "x": 0, + "y": 6 + }, + "id": 16, + "options": { + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "SELECT\n\tpm.project_name,\n\tIF(pm.project_name in ($project),'This project is selected','Not Selected') as select_status,\n\tIF(cdc._raw_data_table != '', cdc._raw_data_table, cdc.cicd_scope_id) as _raw_data_table,\n\tresult,\n\tenvironment,\n\tcount(distinct cdc.id) as deployment_commit_count, \n\tcount(distinct cdc.cicd_deployment_id) as deployment_count\nFROM cicd_deployment_commits cdc\nLEFT join project_mapping pm on cdc.cicd_scope_id = pm.row_id and pm.`table` = 'cicd_scopes'\nWHERE $__timeFilter(cdc.finished_date)\nGROUP BY pm.project_name, select_status, _raw_data_table,result,environment", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Step 1. All cicd_deployment_commits (the rows with 3 green columns will be used in the following steps)", + "type": "table" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "Between once per month and once every 6 months": { + "color": "yellow", + "index": 1 + }, + "Between once per week and once per month": { + "color": "green", + "index": 2 + }, + "Fewer than once per six months": { + "color": "red", + "index": 0 + }, + "On-demand": { + "color": "purple", + "index": 3 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 8, + "x": 16, + "y": 6 + }, + "id": 15, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/^Deployment Frequency$/", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Metric 1: Deployment Frequency\nwith last_few_calendar_months as(\n-- construct the last few calendar months within the selected time period in the top-right corner\n\tSELECT CAST((SYSDATE()-INTERVAL (H+T+U) DAY) AS date) day\n\tFROM ( SELECT 0 H\n\t\t\tUNION ALL SELECT 100 UNION ALL SELECT 200 UNION ALL SELECT 300\n\t\t) H CROSS JOIN ( SELECT 0 T\n\t\t\tUNION ALL SELECT 10 UNION ALL SELECT 20 UNION ALL SELECT 30\n\t\t\tUNION ALL SELECT 40 UNION ALL SELECT 50 UNION ALL SELECT 60\n\t\t\tUNION ALL SELECT 70 UNION ALL SELECT 80 UNION ALL SELECT 90\n\t\t) T CROSS JOIN ( SELECT 0 U\n\t\t\tUNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3\n\t\t\tUNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6\n\t\t\tUNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9\n\t\t) U\n\tWHERE\n\t\t(SYSDATE()-INTERVAL (H+T+U) DAY) > $__timeFrom()\n),\n\n_production_deployment_days as(\n-- When deploying multiple commits in one pipeline, GitLab and BitBucket may generate more than one deployment. However, DevLake consider these deployments as ONE production deployment and use the last one's finished_date as the finished date.\n\tSELECT\n\t\tcdc.cicd_deployment_id as deployment_id,\n\t\tmax(DATE(cdc.finished_date)) as day\n\tFROM cicd_deployment_commits cdc\n\tJOIN project_mapping pm on cdc.cicd_scope_id = pm.row_id and pm.`table` = 'cicd_scopes'\n\tWHERE\n\t\tpm.project_name in ($project)\n\t\tand cdc.result = 'SUCCESS'\n\t\tand cdc.environment = 'PRODUCTION'\n\tGROUP BY 1\n),\n\n_days_weeks_deploy as(\n-- calculate the number of deployment days every week\n\tSELECT\n\t\t\tdate(DATE_ADD(last_few_calendar_months.day, INTERVAL -WEEKDAY(last_few_calendar_months.day) DAY)) as week,\n\t\t\tMAX(if(_production_deployment_days.day is not null, 1, 0)) as weeks_deployed,\n\t\t\tCOUNT(distinct _production_deployment_days.day) as days_deployed\n\tFROM \n\t\tlast_few_calendar_months\n\t\tLEFT JOIN _production_deployment_days ON _production_deployment_days.day = last_few_calendar_months.day\n\tGROUP BY week\n\t),\n\n_monthly_deploy as(\n-- calculate the number of deployment days every month\n\tSELECT\n\t\t\tdate(DATE_ADD(last_few_calendar_months.day, INTERVAL -DAY(last_few_calendar_months.day)+1 DAY)) as month,\n\t\t\tMAX(if(_production_deployment_days.day is not null, 1, 0)) as months_deployed\n\tFROM \n\t\tlast_few_calendar_months\n\t\tLEFT JOIN _production_deployment_days ON _production_deployment_days.day = last_few_calendar_months.day\n\tGROUP BY month\n\t),\n\n_median_number_of_deployment_days_per_week_ranks as(\n\tSELECT *, percent_rank() over(order by days_deployed) as ranks\n\tFROM _days_weeks_deploy\n),\n\n_median_number_of_deployment_days_per_week as(\n\tSELECT max(days_deployed) as median_number_of_deployment_days_per_week\n\tFROM _median_number_of_deployment_days_per_week_ranks\n\tWHERE ranks <= 0.5\n),\n\n_median_number_of_deployment_days_per_month_ranks as(\n\tSELECT *, percent_rank() over(order by months_deployed) as ranks\n\tFROM _monthly_deploy\n),\n\n_median_number_of_deployment_days_per_month as(\n\tSELECT max(months_deployed) as median_number_of_deployment_days_per_month\n\tFROM _median_number_of_deployment_days_per_month_ranks\n\tWHERE ranks <= 0.5\n)\n\nSELECT \n\tCASE \n\t\tWHEN median_number_of_deployment_days_per_week >= 3 THEN 'On-demand'\n\t\tWHEN median_number_of_deployment_days_per_week >= 1 THEN 'Between once per week and once per month'\n\t\tWHEN median_number_of_deployment_days_per_month >= 1 THEN 'Between once per month and once every 6 months'\n\t\tELSE 'Fewer than once per six months' END AS 'Deployment Frequency'\nFROM _median_number_of_deployment_days_per_week, _median_number_of_deployment_days_per_month\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Figure 1 - Deployment Frequency", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "rgba(255, 255, 255, 1)", + "mode": "fixed" + }, + "custom": { + "align": "left", + "displayMode": "color-background-solid" + }, + "mappings": [ + { + "options": { + "DEPLOYMENT": { + "color": "green", + "index": 1 + }, + "PRODUCTION": { + "color": "green", + "index": 0 + }, + "SUCCESS": { + "color": "green", + "index": 2 + }, + "This project is selected": { + "color": "green", + "index": 3 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 16, + "x": 0, + "y": 11 + }, + "id": 29, + "options": { + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "SELECT\n\tpm.project_name,\n\tIF(pm.project_name in ($project),'This project is selected','Not Selected') as select_status,\n\tIF(cdc._raw_data_table != '', cdc._raw_data_table, cdc.cicd_scope_id) as _raw_data_table,\n\tresult,\n\tenvironment,\n\tcount(distinct cdc.id) as deployment_commit_count, \n\tcount(distinct cdc.cicd_deployment_id) as deployment_count\nFROM cicd_deployment_commits cdc\njoin project_mapping pm on cdc.cicd_scope_id = pm.row_id and pm.`table` = 'cicd_scopes'\nWHERE\n pm.project_name in ($project)\n\tand result = 'SUCCESS'\n\tand environment = 'PRODUCTION'\n\tand $__timeFilter(cdc.finished_date)\nGROUP BY 1,2,3,4,5", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Step 2. Find the number of successful production deployments in this project (Last column)", + "type": "table" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 11, + "w": 8, + "x": 16, + "y": 15 + }, + "id": 34, + "options": { + "barWidth": 0.6, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": {}, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Metric 1: Number of deployments per month\nwith _deployments as(\n-- When deploying multiple commits in one pipeline, GitLab and BitBucket may generate more than one deployment. However, DevLake consider these deployments as ONE production deployment and use the last one's finished_date as the finished date.\n\tSELECT \n\t\tdate_format(deployment_finished_date,'%y/%m') as month,\n\t\tcount(cicd_deployment_id) as deployment_count\n\tFROM (\n\t\tSELECT\n\t\t\tcdc.cicd_deployment_id,\n\t\t\tmax(cdc.finished_date) as deployment_finished_date\n\t\tFROM cicd_deployment_commits cdc\n\t\tJOIN project_mapping pm on cdc.cicd_scope_id = pm.row_id and pm.`table` = 'cicd_scopes'\n\t\tWHERE\n\t\t\tpm.project_name in ($project)\n\t\t\tand cdc.result = 'SUCCESS'\n\t\t\tand cdc.environment = 'PRODUCTION'\n\t\tGROUP BY 1\n\t\tHAVING $__timeFilter(max(cdc.finished_date))\n\t) _production_deployments\n\tGROUP BY 1\n)\n\nSELECT \n\tcm.month, \n\tcase when d.deployment_count is null then 0 else d.deployment_count end as deployment_count\nFROM \n\tcalendar_months cm\n\tLEFT JOIN _deployments d on cm.month = d.month\n\tWHERE $__timeFilter(cm.month_timestamp)", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Figure 2 - Monthly deployments", + "type": "barchart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "rgba(255, 255, 255, 1)", + "mode": "fixed" + }, + "custom": { + "align": "left", + "displayMode": "color-background-solid" + }, + "mappings": [ + { + "options": { + "DEPLOYMENT": { + "color": "green", + "index": 1 + }, + "PRODUCTION": { + "color": "green", + "index": 0 + }, + "SUCCESS": { + "color": "green", + "index": 2 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "deployment_id" + }, + "properties": [ + { + "id": "custom.width", + "value": null + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 16, + "x": 0, + "y": 16 + }, + "id": 49, + "options": { + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with _deployment_commit_rank as(\n SELECT\n \tpm.project_name,\n \tIF(cdc._raw_data_table != '', cdc._raw_data_table, cdc.cicd_scope_id) as _raw_data_table,\n \tcdc.id,\n \tcdc.cicd_deployment_id,\n \tcdc.cicd_scope_id,\n \tresult,\n \tenvironment,\n finished_date,\n row_number() over(partition by cdc.cicd_deployment_id order by finished_date desc) as _deployment_commit_rank\n FROM cicd_deployment_commits cdc\n left join project_mapping pm on cdc.cicd_scope_id = pm.row_id and pm.`table` = 'cicd_scopes'\n WHERE\n pm.project_name in ($project)\n \tand result = 'SUCCESS'\n \tand environment = 'PRODUCTION'\n)\n\nSELECT \n project_name, \n cicd_deployment_id as deployment_id,\n -- a deployment may have multiple deployment_commits\n id as deployment_commit_id, \n result,\n environment,\n finished_date\nFROM _deployment_commit_rank\nWHERE \n _deployment_commit_rank = 1\n and $__timeFilter(finished_date)", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Step 3. Use the last finished_date of deployment commits as the finished date of deployments in this project", + "type": "table" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "fixed" + }, + "custom": { + "align": "auto", + "displayMode": "auto" + }, + "mappings": [ + { + "options": { + "Between once per month and once every 6 months": { + "color": "yellow", + "index": 1 + }, + "Between once per week and once per month": { + "color": "green", + "index": 2 + }, + "Fewer than once per six months": { + "color": "red", + "index": 0 + }, + "On-demand": { + "color": "purple", + "index": 3 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "day" + }, + "properties": [ + { + "id": "custom.width", + "value": null + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 8, + "x": 0, + "y": 21 + }, + "id": 11, + "options": { + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with _deployment_commit_rank as(\n SELECT\n \tpm.project_name,\n \tIF(cdc._raw_data_table != '', cdc._raw_data_table, cdc.cicd_scope_id) as _raw_data_table,\n \tcdc.id,\n \tcdc.cicd_deployment_id,\n \tcdc.cicd_scope_id,\n \tresult,\n \tenvironment,\n finished_date,\n row_number() over(partition by cdc.cicd_deployment_id order by finished_date desc) as _deployment_commit_rank\n FROM cicd_deployment_commits cdc\n left join project_mapping pm on cdc.cicd_scope_id = pm.row_id and pm.`table` = 'cicd_scopes'\n WHERE\n pm.project_name in ($project)\n \tand result = 'SUCCESS'\n \tand environment = 'PRODUCTION'\n),\n\n_deployments as (\n SELECT \n project_name, \n cicd_deployment_id as deployment_id,\n -- a deployment may have multiple deployment_commits\n id as deployment_commit_id, \n result,\n environment,\n finished_date\n FROM _deployment_commit_rank\n WHERE \n _deployment_commit_rank = 1\n and $__timeFilter(finished_date)\n)\n\nSELECT\n\tdistinct DATE(finished_date) AS day,\n\tcount(1) as deployment_count\nFROM _deployments\nGROUP BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Step 4. Daily deployments in this project [To check Figure 1]", + "type": "table" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto" + }, + "mappings": [ + { + "options": { + "Between once per month and once every 6 months": { + "color": "yellow", + "index": 1 + }, + "Between once per week and once per month": { + "color": "green", + "index": 2 + }, + "Fewer than once per six months": { + "color": "red", + "index": 0 + }, + "On-demand": { + "color": "purple", + "index": 3 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "day" + }, + "properties": [ + { + "id": "custom.width", + "value": null + } + ] + } + ] + }, + "gridPos": { + "h": 5, + "w": 8, + "x": 8, + "y": 21 + }, + "id": 50, + "options": { + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with _deployment_commit_rank as(\n SELECT\n \tpm.project_name,\n \tIF(cdc._raw_data_table != '', cdc._raw_data_table, cdc.cicd_scope_id) as _raw_data_table,\n \tcdc.id,\n \tcdc.cicd_deployment_id,\n \tcdc.cicd_scope_id,\n \tresult,\n \tenvironment,\n finished_date,\n row_number() over(partition by cdc.cicd_deployment_id order by finished_date desc) as _deployment_commit_rank\n FROM cicd_deployment_commits cdc\n left join project_mapping pm on cdc.cicd_scope_id = pm.row_id and pm.`table` = 'cicd_scopes'\n WHERE\n pm.project_name in ($project)\n \tand result = 'SUCCESS'\n \tand environment = 'PRODUCTION'\n),\n\n_deployments as (\n SELECT \n project_name, \n cicd_deployment_id as deployment_id,\n -- a deployment may have multiple deployment_commits\n id as deployment_commit_id, \n result,\n environment,\n finished_date\n FROM _deployment_commit_rank\n WHERE \n _deployment_commit_rank = 1\n and $__timeFilter(finished_date)\n),\n\n_deployment_days as (\n SELECT\n \tdistinct DATE(finished_date) AS day,\n \tcount(1) as deployment_count\n FROM _deployments\n GROUP BY 1\n)\n\nSELECT \n date_format(day,'%y/%m') as month,\n sum(deployment_count) as monthly_deployment_counts\nFROM \n _deployment_days\nGROUP BY 1\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Step 5. Monthly deployments in this project [To check Figure 2]", + "type": "table" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 26 + }, + "id": 28, + "panels": [], + "title": "Check \"Median Lead Time for Changes\"", + "type": "row" + }, + { + "datasource": null, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 72, + "options": { + "content": "- See the definition and calculation logic of [Median Lead Time for Changes](https://devlake.apache.org/docs/Metrics/LeadTimeForChanges)\n- Data Sources Required: \n - `Deployments` from Jenkins, GitLab CI, GitHub Action, BitBucket Pipelines, or Webhook, etc. \n - `Pull Requests` from GitHub PRs, GitLab MRs, BitBucket PRs, Azure DevOps PRs, etc.\n- Transformation Required: Define `deployments` in [data transformations](https://devlake.apache.org/docs/Configuration/Tutorial#step-3---add-transformations-optional) while configuring the blueprint of a project.\n- Validatation Steps below:\n - Step 1 - check the data integrity of PRs in table `pull_requests`\n - Step 2 - check the data integrity of deployment_commit in table `cicd_deployment_commits`\n - Step 3 - check if a deployment_commit is associated with the correct PR in table `project_pr_metrics`\n - Step 4 - check if metrics like PR Coding/Pickup/Review/Deploy/cycle time are correct in table `project_pr_metrics`\n - Step 5 - check if the median lead time for changes in each month is correct", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "rgba(255, 254, 254, 1)", + "mode": "fixed" + }, + "custom": { + "align": "auto", + "displayMode": "color-background" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 16, + "x": 0, + "y": 34 + }, + "id": 18, + "options": { + "showHeader": true + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "SELECT\n\tpm.project_name,pr._raw_data_table,count(*) as total_number_of_PRs\nFROM\n\tpull_requests pr \n-- \tjoin project_pr_metrics prm on prm.id = pr.id\n\tjoin project_mapping pm on pr.base_repo_id = pm.row_id AND pm.`table`='repos'\nWHERE\n pm.project_name in ($project)\n-- \tand pr.merged_date is not null\n-- \tand prm.pr_cycle_time is not null\n\tand $__timeFilter(pr.created_date)\nGROUP BY 1,2\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Step 1-1. Check if the total PR number in the selected project(s) is correct", + "type": "table" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "Between one week and six months": { + "color": "yellow", + "index": 1 + }, + "Less than one hour": { + "color": "purple", + "index": 3 + }, + "Less than one week": { + "color": "green", + "index": 2 + }, + "More than six months": { + "color": "red", + "index": 0 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 16, + "y": 34 + }, + "id": 40, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/^median_change_lead_time$/", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Metric 2: median lead time for changes\nwith _pr_stats as (\n-- get the cycle time of PRs deployed by the deployments finished in the selected period\n\tSELECT\n\t\tdistinct pr.id,\n\t\tppm.pr_cycle_time\n\tFROM\n\t\tpull_requests pr \n\t\tjoin project_pr_metrics ppm on ppm.id = pr.id\n\t\tjoin project_mapping pm on pr.base_repo_id = pm.row_id and pm.`table` = 'repos'\n\t\tjoin cicd_deployment_commits cdc on ppm.deployment_commit_id = cdc.id\n\tWHERE\n\t pm.project_name in ($project) \n\t\tand pr.merged_date is not null\n\t\tand ppm.pr_cycle_time is not null\n\t\tand $__timeFilter(cdc.finished_date)\n),\n\n_median_change_lead_time_ranks as(\n\tSELECT *, percent_rank() over(order by pr_cycle_time) as ranks\n\tFROM _pr_stats\n),\n\n_median_change_lead_time as(\n-- use median PR cycle time as the median change lead time\n\tSELECT max(pr_cycle_time) as median_change_lead_time\n\tFROM _median_change_lead_time_ranks\n\tWHERE ranks <= 0.5\n)\n\nSELECT \n CASE\n WHEN median_change_lead_time < 60 then \"Less than one hour\"\n WHEN median_change_lead_time < 7 * 24 * 60 then \"Less than one week\"\n WHEN median_change_lead_time < 180 * 24 * 60 then \"Between one week and six months\"\n WHEN median_change_lead_time >= 180 * 24 * 60 then \"More than six months\"\n ELSE \"N/A.Please check if you have collected deployments/incidents.\"\n END as median_change_lead_time\nFROM _median_change_lead_time", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Figure 3 - Median Lead Time for Changes", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "rgba(255, 255, 255, 1)", + "mode": "fixed" + }, + "custom": { + "align": "auto", + "displayMode": "color-background-solid", + "filterable": false + }, + "mappings": [ + { + "options": { + "This Project": { + "color": "green", + "index": 0 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "merged_date" + }, + "properties": [ + { + "id": "color" + }, + { + "id": "custom.displayMode", + "value": "color-background-solid" + } + ] + }, + { + "matcher": { + "id": "byType", + "options": "time" + }, + "properties": [ + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 0 + } + ] + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "project_name" + }, + "properties": [ + { + "id": "custom.displayMode", + "value": "color-background-solid" + } + ] + } + ] + }, + "gridPos": { + "h": 3, + "w": 16, + "x": 0, + "y": 39 + }, + "id": 53, + "options": { + "showHeader": true + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "SELECT\n pm.project_name,\n\t-- pr.status,\n\tpr.title,\n\tpr.author_name,\n\tpr.url,\n\tpr.merged_date,\n\tpr.created_date\nFROM\n\tpull_requests pr \n\tjoin project_mapping pm on pr.base_repo_id = pm.row_id AND pm.`table`='repos'\nWHERE\n -- pm.project_name in ($project)\n\tpr.id = '$pr_id'\n\tand $__timeFilter(pr.created_date)\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Step 1-2. Check if the attributes of the selected pull request is correct (Use the Pull Request URL filter above)", + "type": "table" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Hours", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 40 + }, + "id": 38, + "options": { + "barWidth": 0.7, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": {}, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "-- Metric 2: median change lead time per month\nwith _pr_stats as (\n-- get the cycle time of PRs deployed by the deployments finished each month\n\tSELECT\n\t\tdistinct pr.id,\n\t\tdate_format(cdc.finished_date,'%y/%m') as month,\n\t\tppm.pr_cycle_time\n\tFROM\n\t\tpull_requests pr\n\t\tjoin project_pr_metrics ppm on ppm.id = pr.id\n\t\tjoin project_mapping pm on pr.base_repo_id = pm.row_id and pm.`table` = 'repos'\n\t\tjoin cicd_deployment_commits cdc on ppm.deployment_commit_id = cdc.id\n\tWHERE\n\t\tpm.project_name in ($project) \n\t\tand pr.merged_date is not null\n\t\tand ppm.pr_cycle_time is not null\n\t\tand $__timeFilter(cdc.finished_date)\n),\n\n_find_median_clt_each_month_ranks as(\n\tSELECT *, percent_rank() over(PARTITION BY month order by pr_cycle_time) as ranks\n\tFROM _pr_stats\n),\n\n_clt as(\n\tSELECT month, max(pr_cycle_time) as median_change_lead_time\n\tFROM _find_median_clt_each_month_ranks\n\tWHERE ranks <= 0.5\n\tgroup by month\n)\n\nSELECT \n\tcm.month,\n\tcase \n\t\twhen _clt.median_change_lead_time is null then 0 \n\t\telse _clt.median_change_lead_time/60 end as median_change_lead_time_in_hour\nFROM \n\tcalendar_months cm\n\tLEFT JOIN _clt on cm.month = _clt.month\n WHERE $__timeFilter(cm.month_timestamp)", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Figure 4 - Median Lead Time for Changes", + "type": "barchart" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "rgba(255, 254, 254, 1)", + "mode": "fixed" + }, + "mappings": [ + { + "options": { + "from": 1, + "result": { + "color": "green", + "index": 0 + }, + "to": 10000000 + }, + "type": "range" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 16, + "x": 0, + "y": 42 + }, + "id": 12, + "options": { + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "text": {} + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select \n count(distinct pr.id) as 'No. of merged PRs in table.pull_requests'\nfrom \n pull_requests pr\n join project_mapping pm on pr.base_repo_id = pm.row_id and pm.`table` = 'repos'\nwhere \n pm.project_name in ($project)\n and pr.merged_date is not null\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select \n count(distinct id) as 'No. of PRs in table.project_pr_metrics'\nfrom \n project_pr_metrics \nwhere \n project_name in ($project)", + "refId": "B", + "select": [ + [ + { + "params": [ + "blueprint_id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprint_labels", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Step 1-3. Check if the No. of records in project_pr_metrics is the same as the No. of MERGED PRs in the selected project(s)", + "type": "gauge" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "rgba(255, 255, 255, 1)", + "mode": "fixed" + }, + "custom": { + "align": "left", + "displayMode": "color-background-solid" + }, + "mappings": [ + { + "options": { + "DEPLOYMENT": { + "color": "green", + "index": 1 + }, + "PRODUCTION": { + "color": "green", + "index": 0 + }, + "SUCCESS": { + "color": "green", + "index": 2 + }, + "This project is selected": { + "color": "green", + "index": 3 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 16, + "x": 0, + "y": 46 + }, + "id": 68, + "options": { + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "SELECT\n\tpm.project_name,\n\tIF(pm.project_name in ($project),'This project is selected','Not Selected') as select_status,\n\tIF(cdc._raw_data_table != '', cdc._raw_data_table, cdc.cicd_scope_id) as _raw_data_table,\n\tresult,\n\tenvironment,\n\tcount(distinct cdc.id) as deployment_commit_count, \n\tcount(distinct cdc.cicd_deployment_id) as deployment_count\nFROM cicd_deployment_commits cdc\njoin project_mapping pm on cdc.cicd_scope_id = pm.row_id and pm.`table` = 'cicd_scopes'\nWHERE\n pm.project_name in ($project)\n\tand result = 'SUCCESS'\n\tand environment = 'PRODUCTION'\n\tand $__timeFilter(cdc.finished_date)\nGROUP BY 1,2,3,4,5", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Step 2. Check if the number of successful production deployments in the selected project(s) is correct", + "type": "table" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "rgba(255, 255, 255, 1)", + "mode": "fixed" + }, + "custom": { + "align": "auto", + "displayMode": "color-background-solid", + "filterable": true + }, + "mappings": [ + { + "options": { + "This Project": { + "color": "green", + "index": 0 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "merged_date" + }, + "properties": [ + { + "id": "custom.displayMode", + "value": "color-background-solid" + }, + { + "id": "color" + }, + { + "id": "thresholds", + "value": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 0 + } + ] + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "select_status" + }, + "properties": [ + { + "id": "custom.displayMode", + "value": "color-background-solid" + }, + { + "id": "mappings", + "value": [ + { + "options": { + "This project is selected": { + "color": "green", + "index": 0 + } + }, + "type": "value" + } + ] + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 47 + }, + "id": 51, + "options": { + "showHeader": true + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "SELECT\n pm.project_name,\n\tIF(pm.project_name in ($project),'This project is selected','Not Selected') as select_status,\n\t-- pr.status,\n\tpr.title,\n -- \tpr.author_name,\n\tpr.url,\n\tpr.merged_date,\n\tpr.created_date\nFROM\n\tpull_requests pr \n\tjoin project_mapping pm on pr.base_repo_id = pm.row_id AND pm.`table`='repos'\nWHERE\n -- pm.project_name in ($project)\n\t$__timeFilter(pr.created_date)\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Appendix 1 - All PRs in this project (Only the rows with 2 green columns should appear in project_pr_metrics)", + "type": "table" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "rgba(255, 255, 255, 1)", + "mode": "fixed" + }, + "custom": { + "align": "left", + "displayMode": "color-background-solid" + }, + "mappings": [ + { + "options": { + "NO": { + "color": "red", + "index": 1 + }, + "YES": { + "color": "green", + "index": 0 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 16, + "x": 0, + "y": 50 + }, + "id": 69, + "options": { + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- This query can be used to test if the column `deployment_commit_id` is associated with the correct PR\nWITH pr_merge_commits AS (\n\tSELECT\n\t\tppm.id AS pr_id,\n\t\tppm.deployment_commit_id AS id_1,\n\t\tpr.merge_commit_sha,\n\t\tppm.project_name \n\tFROM\n\t\tproject_pr_metrics ppm\n\t\tLEFT JOIN pull_requests pr ON ppm.id = pr.id \n\tWHERE\n\t\tppm.project_name in ($project) \n\t\tAND ppm.id = '$pr_id'\n\t),\n\t_deployment_commits AS (\n\tSELECT DISTINCT\n\t\tcdc1.id AS id_2,\n\t\tcdc1.prev_success_deployment_commit_id,\n\t\tcdc1.commit_sha AS new_commit_sha,\n\t\tcdc2.commit_sha AS old_commit_sha,\n\t\tcdc1.finished_date,\n\t\tcd.commit_sha AS deployed_commits \n\tFROM\n\t\tcicd_deployment_commits cdc1\n\t\tLEFT JOIN cicd_deployment_commits cdc2 ON cdc1.prev_success_deployment_commit_id = cdc2.id\n\t\tJOIN commits_diffs cd ON cdc1.commit_sha = cd.new_commit_sha \n\t\tAND COALESCE ( cdc2.commit_sha, '' ) = cd.old_commit_sha\n\t\tJOIN project_mapping pm ON cdc1.cicd_scope_id = pm.row_id \n\tWHERE\n\t\tcdc1.result = 'SUCCESS' \n\t\tAND cdc1.environment = 'PRODUCTION' \n\t\tAND pm.project_name in ($project)\n\t),\n\t_find_deployment_commit_id_from_pr AS (\n\tSELECT\n\t\tpmc.pr_id,\n\t\tpmc.id_1,\n\t\tpmc.merge_commit_sha,\n\t\tpmc.project_name,\n\t\tdc.id_2,\n\t\tdc.prev_success_deployment_commit_id,\n\t\tdc.deployed_commits,\n\t\trank() over ( PARTITION BY pr_id ORDER BY dc.finished_date ) AS deployment_rank \n\tFROM\n\t\tpr_merge_commits pmc\n\t\tLEFT JOIN _deployment_commits dc ON pmc.merge_commit_sha = dc.deployed_commits \n\t) SELECT\n\tpr_id,\n\t-- If `id_1` equals `id_2`, then pass\n\tid_1 as deployment_commit_id,\n-- \tid_2,\n\tcase when id_1 = COALESCE(id_2,'') then 'YES' else 'NO' end as if_the_mapping_logic_is_correct\nFROM\n\t_find_deployment_commit_id_from_pr \nWHERE\n\tdeployment_rank = 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Step 3. Check if a `pull request` is associated with the correct `depoloyment commit` in table project_pr_metrics", + "type": "table" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 0, + "y": 54 + }, + "id": 52, + "options": { + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "text": {} + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with _pr_commit_ranks as(\n select \n pr.id,\n pr.created_date as pr_created_date,\n prc.commit_sha,\n prc.commit_authored_date,\n row_number() over(partition by pr.id order by prc.commit_authored_date asc) as commit_rank\n from \n pull_requests pr\n left join pull_request_commits prc on pr.id = prc.pull_request_id\n where pr.id = '$pr_id'\n)\n\nselect \n id,\n -- commit_sha as first_commit_sha,\n -- commit_authored_date as first_commit_authored_date,\n CEILING(TIMESTAMPDIFF(Second,commit_authored_date,pr_created_date)/60) as 'PR coding time from PRs and commits'\nfrom\n _pr_commit_ranks\nwhere \n commit_rank = 1\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select \n id, \n -- first_commit_sha,\n pr_coding_time as 'PR coding time from project_pr_metrics'\nfrom project_pr_metrics\nwhere id = '$pr_id'", + "refId": "B", + "select": [ + [ + { + "params": [ + "blueprint_id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprint_labels", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Step 4-1. Check if PR coding time in project_pr_metrics is correct (Adopt the Pull Request filter above)", + "type": "gauge" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 12, + "y": 54 + }, + "id": 54, + "options": { + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "text": {} + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with _pr_comment_ranks as(\n select \n pr.id as pr_id,\n pr.created_date as pr_created_date,\n prc.id as review_id,\n prc.created_date as review_created_date,\n row_number() over(partition by pr.id order by prc.created_date asc) as comment_rank\n from \n pull_requests pr\n left join pull_request_comments prc on pr.id = prc.pull_request_id\n where \n pr.id = '$pr_id'\n and prc.account_id!=pr.author_id\n)\n\nselect\n pr_id,\n review_id as first_review_id,\n pr_created_date,\n review_created_date as first_review_time,\n CEILING(TIMESTAMPDIFF(second,pr_created_date,review_created_date)/60) as 'PR pickup time from pr_comments'\nfrom \n _pr_comment_ranks\nwhere\n comment_rank = 1\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select \n id, \n -- first_review_id,\n pr_pickup_time as 'PR pickup time from project_pr_metrics'\nfrom project_pr_metrics\nwhere \n id = '$pr_id'\n and project_name in ($project)\n", + "refId": "B", + "select": [ + [ + { + "params": [ + "blueprint_id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprint_labels", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Step 4-2. Check if PR pickup time in project_pr_metrics is correct (Adopt the Pull Request filter above)", + "type": "gauge" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 0, + "y": 58 + }, + "id": 55, + "options": { + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "text": {} + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with _pr_comment_ranks as(\n select \n pr.id as pr_id,\n pr.merged_date as pr_merged_date,\n prc.id as review_id,\n prc.created_date as review_created_date,\n row_number() over(partition by pr.id order by prc.created_date asc) as comment_rank_asc\n from \n pull_requests pr\n left join pull_request_comments prc on pr.id = prc.pull_request_id\n where \n pr.id = '$pr_id'\n and prc.account_id!=pr.author_id\n)\n\nselect\n pr_id,\n review_id as first_review_id,\n review_created_date as first_review_time,\n CEILING(TIMESTAMPDIFF(second,review_created_date,pr_merged_date)/60) as 'PR review time from pr_comments'\nfrom \n _pr_comment_ranks\nwhere\n comment_rank_asc = 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select \n id, \n -- first_review_id,\n pr_review_time as 'PR review time from project_pr_metrics'\nfrom project_pr_metrics\nwhere \n id = '$pr_id'\n and project_name in ($project)\n", + "refId": "B", + "select": [ + [ + { + "params": [ + "blueprint_id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprint_labels", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Step 4-3. Check if PR review time in project_pr_metrics is correct (Adopt the Pull Request filter above)", + "type": "gauge" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 12, + "y": 58 + }, + "id": 56, + "options": { + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "text": {} + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select \n ppm.id as pr_id,\n ppm.deployment_commit_id,\n CEILING(TIMESTAMPDIFF(second,pr.merged_date,cdc.finished_date)/60) as 'PR deploy time from cicd_deployment_commits'\nfrom \n project_pr_metrics ppm\n left join cicd_deployment_commits cdc on ppm.deployment_commit_id = cdc.id\n left join pull_requests pr on ppm.id = pr.id\nwhere \n project_name in ($project)\n and cdc.result = 'SUCCESS'\n and cdc.`environment` = 'PRODUCTION'\n and ppm.id = '$pr_id'", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + }, + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select \n id, \n pr_deploy_time as 'PR deploy time from project_pr_metrics'\nfrom project_pr_metrics\nwhere \n id = '$pr_id'\n and project_name in ($project)\n", + "refId": "B", + "select": [ + [ + { + "params": [ + "blueprint_id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprint_labels", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Step 4-4. Check if PR deploy time in project_pr_metrics is correct (Adopt the Pull Request filter above)", + "type": "gauge" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 12, + "x": 0, + "y": 62 + }, + "id": 57, + "options": { + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": true, + "text": {} + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select \n ppm.id,\n (pr_coding_time + CEILING(TIMESTAMPDIFF(second,pr.created_date,pr.merged_date)/60) + pr_deploy_time) as 'PR cycle time from lower-level metrics',\n ppm.`pr_cycle_time` as 'PR cycle time from project_pr_metrics'\nfrom project_pr_metrics ppm\nleft join pull_requests pr on ppm.id = pr.id\nwhere \n project_name in ($project)\n and pr.id = '$pr_id'", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Step 4-5. Check if PR cycle time in project_pr_metrics is correct (Adopt the Pull Request filter above)", + "type": "gauge" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "ranks" + }, + "properties": [ + { + "id": "mappings", + "value": [ + { + "options": { + "from": 0, + "result": { + "color": "green", + "index": 0 + }, + "to": 0.5 + }, + "type": "range" + }, + { + "options": { + "from": 0.5, + "result": { + "color": "orange", + "index": 1 + }, + "to": 1 + }, + "type": "range" + } + ] + }, + { + "id": "custom.displayMode", + "value": "color-text" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "month" + }, + "properties": [ + { + "id": "custom.filterable", + "value": true + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 66 + }, + "id": 70, + "options": { + "showHeader": true + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _pr_stats as (\n-- get the cycle time of PRs deployed by the deployments finished each month\n\tSELECT\n\t\tdistinct\n\t\tdate_format(cdc.finished_date,'%y/%m') as month,\n\t\tpr.id,\n\t\tppm.pr_cycle_time\n\tFROM\n\t\tpull_requests pr\n\t\tjoin project_pr_metrics ppm on ppm.id = pr.id\n\t\tjoin project_mapping pm on pr.base_repo_id = pm.row_id and pm.`table` = 'repos'\n\t\tjoin cicd_deployment_commits cdc on ppm.deployment_commit_id = cdc.id\n\tWHERE\n\t\tpm.project_name in ($project) \n\t\tand pr.merged_date is not null\n\t\tand ppm.pr_cycle_time is not null\n\t\tand $__timeFilter(cdc.finished_date)\n),\n\n_find_median_clt_each_month_ranks as(\n\tSELECT *, percent_rank() over(PARTITION BY month order by pr_cycle_time) as ranks\n\tFROM _pr_stats\n)\n\nSELECT \n month, \n id, \n pr_cycle_time as change_lead_time_in_minutes, \n pr_cycle_time/60 as change_lead_time_in_hours, \n ranks \nFROM _find_median_clt_each_month_ranks\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Step 5 - check the median change lead time for each month in Figure 4 (Compare the change_lead_time with the max ranks in GREEN before the first occurence of ORANGE in each month)", + "type": "table" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 74 + }, + "id": 26, + "panels": [], + "title": "Check \"Change Failure Rate\" & \"Median Time to Restore Service\"", + "type": "row" + }, + { + "datasource": null, + "gridPos": { + "h": 4, + "w": 24, + "x": 0, + "y": 75 + }, + "id": 66, + "options": { + "content": "- See the definition and calculation logic of [Median Time to Restore Service](https://devlake.apache.org/docs/Metrics/MTTR)\n- Data Sources Required: \n - `Deployments` from Jenkins, GitLab CI, GitHub Action, BitBucket Pipelines, or Webhook, etc. \n - `Incidents` from Jira issues, GitHub issues, TAPD issues, PagerDuty Incidents, etc. \n- Transformation Required: Define `deployments` and `incidents` in [data transformations](https://devlake.apache.org/docs/Configuration/Tutorial#step-3---add-transformations-optional) while configuring the blueprint of a project.", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": null, + "gridPos": { + "h": 4, + "w": 24, + "x": 0, + "y": 79 + }, + "id": 67, + "options": { + "content": "- See the definition and calculation logic of [Change Failure Rate](https://devlake.apache.org/docs/Metrics/CFR)\n- Data Sources Required: \n - `Deployments` from Jenkins, GitLab CI, GitHub Action, BitBucket Pipelines, or Webhook, etc. \n - `Incidents` from Jira issues, GitHub issues, TAPD issues, PagerDuty Incidents, etc. \n- Transformation Required: Define `deployments` and `incidents` in [data transformations](https://devlake.apache.org/docs/Configuration/Tutorial#step-3---add-transformations-optional) while configuring the blueprint of a project.", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "rgba(255, 255, 255, 1)", + "mode": "fixed" + }, + "custom": { + "align": "auto", + "displayMode": "color-background" + }, + "mappings": [ + { + "options": { + "INCIDENT": { + "color": "green", + "index": 0 + }, + "This project is selected": { + "color": "green", + "index": 1 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 16, + "x": 0, + "y": 83 + }, + "id": 31, + "options": { + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- get the incident created within the selected time period in the top-right corner\nSELECT\n\tpm.project_name,\n\tIF(pm.project_name in ($project),'This project is selected','Not Selected') as select_status,\n\ti._raw_data_table,\n\ti.type, \n\tcount(1) as issue_count\nFROM\n\tissues i\n join board_issues bi on i.id = bi.issue_id\n join boards b on bi.board_id = b.id\n join project_mapping pm on b.id = pm.row_id and pm.`table` = 'boards'\nWHERE\n pm.project_name in ($project)\n-- \tand i.type = 'INCIDENT'\n\tand $__timeFilter(i.created_date)\nGROUP BY pm.project_name, select_status,i._raw_data_table, i.type", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Step 1. All types of issues in table.issues (rows with 2 green columns will be used to construct project_issue_metrics)", + "type": "table" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "Between one day and one week": { + "color": "yellow", + "index": 1 + }, + "Less than one day": { + "color": "green", + "index": 2 + }, + "Less than one hour": { + "color": "purple", + "index": 3 + }, + "More than one week": { + "color": "red", + "index": 0 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 8, + "x": 16, + "y": 83 + }, + "id": 42, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/^median_time_to_resolve$/", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Metric 3: Median time to restore service \nwith _incidents as (\n-- get the incidents created within the selected time period in the top-right corner\n\tSELECT\n\t distinct i.id,\n\t\tcast(lead_time_minutes as signed) as lead_time_minutes\n\tFROM\n\t\tissues i\n\t join board_issues bi on i.id = bi.issue_id\n\t join boards b on bi.board_id = b.id\n\t join project_mapping pm on b.id = pm.row_id and pm.`table` = 'boards'\n\tWHERE\n\t pm.project_name in ($project)\n\t\tand i.type = 'INCIDENT'\n\t\tand $__timeFilter(i.created_date)\n),\n\n_median_mttr_ranks as(\n\tSELECT *, percent_rank() over(order by lead_time_minutes) as ranks\n\tFROM _incidents\n),\n\n_median_mttr as(\n\tSELECT max(lead_time_minutes) as median_time_to_resolve\n\tFROM _median_mttr_ranks\n\tWHERE ranks <= 0.5\n)\n\nSELECT \n\tcase\n\t\tWHEN median_time_to_resolve < 60 then \"Less than one hour\"\n WHEN median_time_to_resolve < 24 * 60 then \"Less than one Day\"\n WHEN median_time_to_resolve < 7 * 24 * 60 then \"Between one day and one week\"\n WHEN median_time_to_resolve >= 7 * 24 * 60 then \"More than one week\"\n ELSE \"N/A.Please check if you have collected deployments/incidents.\"\n END as median_time_to_resolve\nFROM \n\t_median_mttr", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Figure 5 - Median Time to Restore Service", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "rgba(255, 255, 255, 1)", + "mode": "fixed" + }, + "custom": { + "align": "auto", + "displayMode": "color-background" + }, + "mappings": [ + { + "options": { + "INCIDENT": { + "color": "green", + "index": 0 + }, + "This project is selected": { + "color": "green", + "index": 1 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 16, + "x": 0, + "y": 89 + }, + "id": 14, + "options": { + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- get the incident created within the selected time period in the top-right corner\nSELECT\n\tpm.project_name,\n\tIF(pm.project_name in ($project),'This project is selected','Not Selected') as select_status,\n\ti._raw_data_table,\n\ti.type, \n\tcount(1) as issue_count\nFROM\n\tissues i\n join board_issues bi on i.id = bi.issue_id\n join boards b on bi.board_id = b.id\n join project_mapping pm on b.id = pm.row_id and pm.`table` = 'boards'\nWHERE\n pm.project_name in ($project)\n\tand i.type = 'INCIDENT'\n\tand $__timeFilter(i.created_date)\nGROUP BY pm.project_name,select_status, i._raw_data_table, i.type", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Step 2. Number of Incidents in the selected project(s)", + "type": "table" + }, + { + "datasource": null, + "gridPos": { + "h": 15, + "w": 16, + "x": 0, + "y": 93 + }, + "id": 61, + "options": { + "content": "\n\nIn this case:\n\n- Deployment-1 maps to Incident-1\n- Deployment-3 maps to Incident-2 and Incident-3\n- Deployment-2,4,5 doesn't map to any Incident", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "title": "Deployment - Incident Mapping and CFR calculation logic", + "type": "text" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Hours", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "median_time_to_resolve_in_hour" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 8, + "x": 16, + "y": 93 + }, + "id": 46, + "options": { + "barWidth": 0.6, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": {}, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "-- Metric 3: median time to restore service - MTTR\nwith _incidents as (\n-- get the number of incidents created each month\n\tSELECT\n\t distinct i.id,\n\t\tdate_format(i.created_date,'%y/%m') as month,\n\t\tcast(lead_time_minutes as signed) as lead_time_minutes\n\tFROM\n\t\tissues i\n\t join board_issues bi on i.id = bi.issue_id\n\t join boards b on bi.board_id = b.id\n\t join project_mapping pm on b.id = pm.row_id and pm.`table` = 'boards'\n\tWHERE\n\t pm.project_name in ($project)\n\t\tand i.type = 'INCIDENT'\n\t\tand i.lead_time_minutes is not null\n),\n\n_find_median_mttr_each_month_ranks as(\n\tSELECT *, percent_rank() over(PARTITION BY month order by lead_time_minutes) as ranks\n\tFROM _incidents\n),\n\n_mttr as(\n\tSELECT month, max(lead_time_minutes) as median_time_to_resolve\n\tFROM _find_median_mttr_each_month_ranks\n\tWHERE ranks <= 0.5\n\tGROUP BY month\n)\n\nSELECT \n\tcm.month,\n\tcase \n\t\twhen m.median_time_to_resolve is null then 0 \n\t\telse m.median_time_to_resolve/60 end as median_time_to_resolve_in_hour\nFROM \n\tcalendar_months cm\n\tLEFT JOIN _mttr m on cm.month = m.month\n WHERE $__timeFilter(cm.month_timestamp)", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Figure 6 - Median Time to Restore Service", + "type": "barchart" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "0-15%": { + "color": "purple", + "index": 3 + }, + "16%-20%": { + "color": "green", + "index": 2 + }, + "21%-30%": { + "color": "yellow", + "index": 1 + }, + "> 30%": { + "color": "red", + "index": 0 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 103 + }, + "id": 44, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/^change_failure_rate$/", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Metric 4: change failure rate\nwith _deployments as (\n-- When deploying multiple commits in one pipeline, GitLab and BitBucket may generate more than one deployment. However, DevLake consider these deployments as ONE production deployment and use the last one's finished_date as the finished date.\n\tSELECT\n\t\tcdc.cicd_deployment_id as deployment_id,\n\t\tmax(cdc.finished_date) as deployment_finished_date\n\tFROM \n\t\tcicd_deployment_commits cdc\n\t\tJOIN project_mapping pm on cdc.cicd_scope_id = pm.row_id and pm.`table` = 'cicd_scopes'\n\tWHERE\n\t\tpm.project_name in ($project)\n\t\tand cdc.result = 'SUCCESS'\n\t\tand cdc.environment = 'PRODUCTION'\n\tGROUP BY 1\n\tHAVING $__timeFilter(max(cdc.finished_date))\n),\n\n_failure_caused_by_deployments as (\n-- calculate the number of incidents caused by each deployment\n\tSELECT\n\t\td.deployment_id,\n\t\td.deployment_finished_date,\n\t\tcount(distinct case when i.type = 'INCIDENT' then d.deployment_id else null end) as has_incident\n\tFROM\n\t\t_deployments d\n\t\tleft join project_issue_metrics pim on d.deployment_id = pim.deployment_id\n\t\tleft join issues i on pim.id = i.id\n\tGROUP BY 1,2\n),\n\n_change_failure_rate as (\n\tSELECT \n\t\tcase \n\t\t\twhen count(deployment_id) is null then null\n\t\t\telse sum(has_incident)/count(deployment_id) end as change_failure_rate\n\tFROM\n\t\t_failure_caused_by_deployments\n)\n\nSELECT\n\tcase \n\t\twhen change_failure_rate <= .15 then \"0-15%\"\n\t\twhen change_failure_rate <= .20 then \"16%-20%\"\n\t\twhen change_failure_rate <= .30 then \"21%-30%\"\n\t\telse \"> 30%\" \n\tend as change_failure_rate\nFROM \n\t_change_failure_rate", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Figure 7 - Change Failure Rate", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "rgba(255, 255, 255, 1)", + "mode": "fixed" + }, + "custom": { + "align": "auto", + "displayMode": "color-background-solid", + "filterable": true + }, + "mappings": [ + { + "options": { + "DEPLOYMENT": { + "color": "green", + "index": 0 + }, + "INCIDENT": { + "color": "red", + "index": 1 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 8, + "x": 0, + "y": 108 + }, + "id": 58, + "options": { + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with _deployments as(\n select distinct \n d.cicd_deployment_id as deployment_id,\n d.result,\n d.environment,\n d.finished_date,\n d.cicd_scope_id,\n pm.project_name\n from \n cicd_deployment_commits d\n join project_mapping pm on d.cicd_scope_id = pm.row_id and pm.`table` = 'cicd_scopes'\n where \n -- only result needs to specified, not envioronment\n d.result = 'SUCCESS'\n -- choose your project_name\n and pm.project_name in ($project)\n),\n\n_incidents as(\n select distinct \n i.id as issue_id,\n i.type,\n i.created_date,\n pm.project_name\n from \n issues i\n join board_issues bi on i.id = bi.issue_id\n join project_mapping pm on bi.board_id = pm.row_id \n where \n i.type = 'INCIDENT'\n -- choose your project_name\n and pm.project_name in ($project)\n)\n\nselect deployment_id as id, 'DEPLOYMENT' as type, finished_date as time from _deployments\nunion\nselect issue_id as id, 'INCIDENT' as type, created_date as time from _incidents\norder by time", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Step 3. The sequence of DEPLOYMENTS and INCIDENTS", + "type": "table" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "rgba(255, 255, 255, 1)", + "mode": "fixed" + }, + "custom": { + "align": "auto", + "displayMode": "color-background-solid", + "filterable": true + }, + "mappings": [ + { + "options": { + "FALSE": { + "color": "green", + "index": 1 + }, + "TRUE": { + "color": "red", + "index": 0 + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 13, + "w": 8, + "x": 8, + "y": 108 + }, + "id": 59, + "options": { + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select \n -- in CFR we use deployment_commit_id as the deployment_id in a specific repo\n cdc.id as deployment_id,\n cdc.finished_date,\n pim.id as incident_id,\n if (pim.id is not null, 'TRUE', 'FALSE') as has_failure\nfrom \n cicd_deployment_commits cdc\n left join project_issue_metrics pim on cdc.id = pim.deployment_id\n left join project_mapping pm on cdc.cicd_scope_id = pm.row_id and pm.`table` = 'cicd_scopes'\nwhere \n pm.project_name in ($project)\n and $__timeFilter(cdc.finished_date)\norder by 2 desc\n ", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_tasks", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Step 4. Check if the DEPLOYMENT and INCIDENT mapping results are consistent with them in step 3 and figure 7&8", + "type": "table" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "max": 1, + "min": 0, + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "percentunit" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "change_failure_rate" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 8, + "x": 16, + "y": 111 + }, + "id": 48, + "options": { + "barWidth": 0.6, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "-- Metric 4: change failure rate per month\nwith _deployments as (\n-- When deploying multiple commits in one pipeline, GitLab and BitBucket may generate more than one deployment. However, DevLake consider these deployments as ONE production deployment and use the last one's finished_date as the finished date.\n\tSELECT\n\t\tcdc.cicd_deployment_id as deployment_id,\n\t\tmax(cdc.finished_date) as deployment_finished_date\n\tFROM \n\t\tcicd_deployment_commits cdc\n\t\tJOIN project_mapping pm on cdc.cicd_scope_id = pm.row_id and pm.`table` = 'cicd_scopes'\n\tWHERE\n\t\tpm.project_name in ($project)\n\t\tand cdc.result = 'SUCCESS'\n\t\tand cdc.environment = 'PRODUCTION'\n\tGROUP BY 1\n\tHAVING $__timeFilter(max(cdc.finished_date))\n),\n\n_failure_caused_by_deployments as (\n-- calculate the number of incidents caused by each deployment\n\tSELECT\n\t\td.deployment_id,\n\t\td.deployment_finished_date,\n\t\tcount(distinct case when i.type = 'INCIDENT' then d.deployment_id else null end) as has_incident\n\tFROM\n\t\t_deployments d\n\t\tleft join project_issue_metrics pim on d.deployment_id = pim.deployment_id\n\t\tleft join issues i on pim.id = i.id\n\tGROUP BY 1,2\n),\n\n_change_failure_rate_for_each_month as (\n\tSELECT \n\t\tdate_format(deployment_finished_date,'%y/%m') as month,\n\t\tcase \n\t\t\twhen count(deployment_id) is null then null\n\t\t\telse sum(has_incident)/count(deployment_id) end as change_failure_rate\n\tFROM\n\t\t_failure_caused_by_deployments\n\tGROUP BY 1\n)\n\nSELECT \n\tcm.month,\n\tcfr.change_failure_rate\nFROM \n\tcalendar_months cm\n\tLEFT JOIN _change_failure_rate_for_each_month cfr on cm.month = cfr.month\n\tWHERE $__timeFilter(cm.month_timestamp)", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Figure 8 - Change Failure Rate", + "type": "barchart" + } + ], + "refresh": "", + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "mysql", + "definition": "select distinct name from projects", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Project", + "multi": true, + "name": "project", + "options": [], + "query": "select distinct name from projects", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "allValue": null, + "current": { + "selected": false, + "text": "https://bitbucket.org/zhenmianws/helloworldrepo/pull-requests/1", + "value": "bitbucket:BitbucketPullRequest:1:zhenmianws/helloworldrepo:1" + }, + "datasource": "mysql", + "definition": "select concat(Url, '--', id) from pull_requests", + "description": null, + "error": null, + "hide": 0, + "includeAll": false, + "label": "Pull Request Url", + "multi": false, + "name": "pr_id", + "options": [], + "query": "select concat(Url, '--', id) from pull_requests", + "refresh": 1, + "regex": "/^(?.*)--(?.*)$/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-6M", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "DORA Dashboard Validation", + "uid": "KGkUnV-Vz", + "version": 75 +} \ No newline at end of file diff --git a/charts/devlake/dashboards/DemoAverageRequirementLeadTimeByAssignee.json b/charts/devlake/dashboards/DemoAverageRequirementLeadTimeByAssignee.json new file mode 100644 index 0000000..3f17d01 --- /dev/null +++ b/charts/devlake/dashboards/DemoAverageRequirementLeadTimeByAssignee.json @@ -0,0 +1,250 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 1, + "links": [ + { + "asDropdown": false, + "icon": "bolt", + "includeVars": false, + "keepTime": true, + "tags": [], + "targetBlank": false, + "title": "Homepage", + "tooltip": "", + "type": "link", + "url": "/grafana/d/0Rjxknc7z/demo-homepage?orgId=1" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": false, + "title": "Back to previous page", + "tooltip": "", + "type": "link", + "url": "/grafana/d/SupYz7c7z/demo-how-fast-do-we-respond-to-customer-requirements?orgId=1" + } + ], + "panels": [ + { + "datasource": "mysql", + "description": "1. Compare the average time spent in each state of a requirement in the last 2 months.\n2. The requirements being calculated are the requirements delivered in the last 2 months.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Days", + "axisPlacement": "auto", + "axisSoftMax": 8, + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 98, + "options": { + "barWidth": 0.6, + "groupWidth": 0.5, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "vertical", + "showValue": "always", + "text": { + "valueSize": 16 + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with _requirements as(\n select \n DATE_ADD(date(resolution_date), INTERVAL -DAY(date(resolution_date))+1 DAY) as time,\n assignee_name as assignee,\n avg(lead_time_minutes)/1440 as lead_time\n from issues i\n where \n type = 'REQUIREMENT'\n and assignee_id != ''\n and $__timeFilter(resolution_date)\n group by 1,2\n),\n\n\nthis_month as(\n\tselect \n\t\tDATE_ADD(date(CURDATE()), INTERVAL -DAY(date(CURDATE()))+1 DAY) as this_month\n),\n\nlast_month as(\n\tSELECT \n\t\tDATE_ADD(DATE_ADD(date(CURDATE()), INTERVAL -DAY(date(CURDATE()))+1 DAY), INTERVAL -1 MONTH) as last_month\n),\n\nthe_month_before_last as(\n\tSELECT \n\t\tDATE_ADD(DATE_ADD(date(CURDATE()), INTERVAL -DAY(date(CURDATE()))+1 DAY), INTERVAL -2 MONTH) as the_month_before_last\n),\n\nthis_month_record as(\n\tSELECT\n\t\tassignee,\n\t\tlead_time as this_month_count,\n\t\ttime as this_month\n\tfrom _requirements\n\tWHERE \n\t\ttime in (SELECT this_month from this_month)\n),\n\nlast_month_record as(\n\tSELECT\n\t\tassignee,\n\t\tlead_time as last_month_count,\n\t\ttime as last_month\n\tfrom _requirements\n\tWHERE \n\t\ttime in (SELECT last_month from last_month)\n),\n\nthe_month_before_last_record as(\n\tSELECT\n\t\tassignee,\n\t\tlead_time as the_month_before_last_count,\n\t\ttime as the_month_before_last\n\tfrom _requirements\n\tWHERE \n\t\ttime in (SELECT the_month_before_last from the_month_before_last)\n)\n\nSELECT\n COALESCE(NULLIF(tmr.assignee,''), NULLIF(lmr.assignee,''), tmblr.assignee) AS 'Assignee',\n\tCOALESCE(tmblr.the_month_before_last_count,0) AS \"The Month before Last\",\n\tCOALESCE(lmr.last_month_count,0) AS \"Last Month\",\n\tCOALESCE(tmr.this_month_count,0) AS \"This Month\",\n\tcase \n\t when lmr.last_month_count is null or tmr.this_month_count is null then '-'\n\t else concat(FORMAT(100 * (tmr.this_month_count - lmr.last_month_count)/lmr.last_month_count,1),'%') end as \"Changes in last 2 month\"\nFrom the_month_before_last_record tmblr \n left join last_month_record lmr on tmblr.assignee = lmr.assignee\n left join this_month_record tmr on tmblr.assignee = tmr.assignee\norder by 2", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Average Requirement Lead Time by Assignee (day)", + "type": "barchart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 12, + "w": 24, + "x": 0, + "y": 8 + }, + "id": 100, + "options": { + "showHeader": true + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with _requirements as(\n select \n DATE_ADD(date(resolution_date), INTERVAL -DAY(date(resolution_date))+1 DAY) as time,\n assignee_name as assignee,\n avg(lead_time_minutes)/1440 as lead_time\n from issues i\n where \n type = 'REQUIREMENT'\n and assignee_id != ''\n and $__timeFilter(resolution_date)\n group by 1,2\n),\n\n\nthis_month as(\n\tselect \n\t\tDATE_ADD(date(CURDATE()), INTERVAL -DAY(date(CURDATE()))+1 DAY) as this_month\n),\n\nlast_month as(\n\tSELECT \n\t\tDATE_ADD(DATE_ADD(date(CURDATE()), INTERVAL -DAY(date(CURDATE()))+1 DAY), INTERVAL -1 MONTH) as last_month\n),\n\nthe_month_before_last as(\n\tSELECT \n\t\tDATE_ADD(DATE_ADD(date(CURDATE()), INTERVAL -DAY(date(CURDATE()))+1 DAY), INTERVAL -2 MONTH) as the_month_before_last\n),\n\nthis_month_record as(\n\tSELECT\n\t\tassignee,\n\t\tlead_time as this_month_count,\n\t\ttime as this_month\n\tfrom _requirements\n\tWHERE \n\t\ttime in (SELECT this_month from this_month)\n),\n\nlast_month_record as(\n\tSELECT\n\t\tassignee,\n\t\tlead_time as last_month_count,\n\t\ttime as last_month\n\tfrom _requirements\n\tWHERE \n\t\ttime in (SELECT last_month from last_month)\n),\n\nthe_month_before_last_record as(\n\tSELECT\n\t\tassignee,\n\t\tlead_time as the_month_before_last_count,\n\t\ttime as the_month_before_last\n\tfrom _requirements\n\tWHERE \n\t\ttime in (SELECT the_month_before_last from the_month_before_last)\n)\n\nSELECT\n COALESCE(NULLIF(tmr.assignee,''), NULLIF(lmr.assignee,''), tmblr.assignee) AS 'Assignee',\n\tCOALESCE(tmblr.the_month_before_last_count,0) AS \"The Month before Last\",\n\tCOALESCE(lmr.last_month_count,0) AS \"Last Month\",\n\tCOALESCE(tmr.this_month_count,0) AS \"This Month\",\n\tcase \n\t when lmr.last_month_count is null or tmr.this_month_count is null then '-'\n\t else concat(FORMAT(100 * (tmr.this_month_count - lmr.last_month_count)/lmr.last_month_count,1),'%') end as \"Changes in last 2 month\"\nFrom the_month_before_last_record tmblr \n left join last_month_record lmr on tmblr.assignee = lmr.assignee\n left join this_month_record tmr on tmblr.assignee = tmr.assignee\norder by 2", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "type": "table" + }, + { + "datasource": null, + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 102, + "options": { + "content": "
\n\nThis dashboard is created based on this [data schema](https://devlake.apache.org/docs/DataModels/DevLakeDomainLayerSchema). Want to add more metrics? Please follow the [guide](https://devlake.apache.org/docs/Configuration/Dashboards/GrafanaUserGuide).", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + } + ], + "refresh": "", + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-6M", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Demo-Average Requirement Lead Time By Assignee", + "uid": "q27fk7cnk", + "version": 6 +} \ No newline at end of file diff --git a/charts/devlake/dashboards/DemoCommitCountByAuthor.json b/charts/devlake/dashboards/DemoCommitCountByAuthor.json new file mode 100644 index 0000000..e98fcf7 --- /dev/null +++ b/charts/devlake/dashboards/DemoCommitCountByAuthor.json @@ -0,0 +1,257 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 5, + "links": [ + { + "asDropdown": false, + "icon": "bolt", + "includeVars": false, + "keepTime": true, + "tags": [], + "targetBlank": false, + "title": "Homepage", + "tooltip": "", + "type": "link", + "url": "/grafana/d/0Rjxknc7z/demo-homepage?orgId=1" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": false, + "title": "Back to previous page", + "tooltip": "", + "type": "link", + "url": "/grafana/d/ddREk75nk/demo-is-this-month-more-productive-than-last?orgId=1" + } + ], + "panels": [ + { + "datasource": "mysql", + "description": "The number of commits from different commit authors.", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 50, + "options": { + "barWidth": 0.6, + "groupWidth": 0.5, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 14 + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with commit_data as(\n SELECT\n DATE_ADD(date(authored_date), INTERVAL -DAY(date(authored_date))+1 DAY) as time,\n c.author_name,\n count(*) as commit_count\n FROM commits c\n WHERE\n c.message not like '%Merge%'\n and $__timeFilter(authored_date)\n group by 2,1\n order by 2,1\n),\n\nthis_month as(\n select \n\t\tDATE_ADD(date(CURDATE()), INTERVAL -DAY(date(CURDATE()))+1 DAY) as this_month\n),\n\nlast_month as(\n\tselect \n\t\tDATE_ADD(DATE_ADD(date(CURDATE()), INTERVAL -DAY(date(CURDATE()))+1 DAY), INTERVAL -1 MONTH) as last_month\n),\n\nthe_month_before_last as(\n\tSELECT \n\t\tDATE_ADD(DATE_ADD(date(CURDATE()), INTERVAL -DAY(date(CURDATE()))+1 DAY), INTERVAL -2 MONTH) as the_month_before_last\n),\n\nthis_month_record as(\n\tSELECT\n\t\tauthor_name,\n\t\tcommit_count as this_month_count,\n\t\ttime as this_month\n\tfrom commit_data\n\tWHERE \n\t\ttime in (SELECT this_month from this_month)\n),\n\nlast_month_record as(\n\tSELECT\n\t\tauthor_name,\n\t\tcommit_count as last_month_count,\n\t\ttime as last_month\n\tfrom commit_data\n\tWHERE \n\t\ttime in (SELECT last_month from last_month)\n),\nthe_month_before_last_record as(\n\tSELECT\n\t\tauthor_name,\n\t\tcommit_count as the_month_before_last_count,\n\t\ttime as the_month_before_last\n\tfrom commit_data\n\tWHERE \n\t\ttime in (SELECT the_month_before_last from the_month_before_last)\n)\n\nSELECT\n\tCOALESCE(NULLIF(tmr.author_name,''), NULLIF(lmr.author_name,''), tmblr.author_name) AS 'Author Name',\n\tCOALESCE(tmblr.the_month_before_last_count,0) AS \"The Month before Last\",\n\tCOALESCE(lmr.last_month_count,0) AS \"Last Month\",\n\tCOALESCE(tmr.this_month_count,0) AS \"This Month\"\nFROM this_month_record tmr \nright join last_month_record lmr on tmr.author_name = lmr.author_name \nright join the_month_before_last_record tmblr on lmr.author_name = tmblr.author_name\nUNION\nSELECT\n\tCOALESCE(NULLIF(tmr.author_name,''), NULLIF(lmr.author_name,''), tmblr.author_name) AS 'Author Name',\n\tCOALESCE(tmblr.the_month_before_last_count,0) AS \"The Month before Last\",\n\tCOALESCE(lmr.last_month_count,0) AS \"Last Month\",\n\tCOALESCE(tmr.this_month_count,0) AS \"This Month\"\nFROM this_month_record tmr \nleft join last_month_record lmr on tmr.author_name = lmr.author_name \nleft join the_month_before_last_record tmblr on lmr.author_name = tmblr.author_name\norder by 2 desc\nlimit 20\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Commit Count by Author [Top 20]", + "type": "barchart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 7 + }, + "id": 38, + "options": { + "showHeader": true + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with commit_data as(\n SELECT\n DATE_ADD(date(authored_date), INTERVAL -DAY(date(authored_date))+1 DAY) as time,\n c.author_name,\n count(*) as commit_count\n FROM commits c\n WHERE\n c.message not like '%Merge%'\n and $__timeFilter(authored_date)\n group by 2,1\n order by 2,1\n),\n\nthis_month as(\n select \n\t\tDATE_ADD(date(CURDATE()), INTERVAL -DAY(date(CURDATE()))+1 DAY) as this_month\n),\n\nlast_month as(\n\tselect \n\t\tDATE_ADD(DATE_ADD(date(CURDATE()), INTERVAL -DAY(date(CURDATE()))+1 DAY), INTERVAL -1 MONTH) as last_month\n),\n\nthe_month_before_last as(\n\tSELECT \n\t\tDATE_ADD(DATE_ADD(date(CURDATE()), INTERVAL -DAY(date(CURDATE()))+1 DAY), INTERVAL -2 MONTH) as the_month_before_last\n),\n\nthis_month_record as(\n\tSELECT\n\t\tauthor_name,\n\t\tcommit_count as this_month_count,\n\t\ttime as this_month\n\tfrom commit_data\n\tWHERE \n\t\ttime in (SELECT this_month from this_month)\n),\n\nlast_month_record as(\n\tSELECT\n\t\tauthor_name,\n\t\tcommit_count as last_month_count,\n\t\ttime as last_month\n\tfrom commit_data\n\tWHERE \n\t\ttime in (SELECT last_month from last_month)\n),\nthe_month_before_last_record as(\n\tSELECT\n\t\tauthor_name,\n\t\tcommit_count as the_month_before_last_count,\n\t\ttime as the_month_before_last\n\tfrom commit_data\n\tWHERE \n\t\ttime in (SELECT the_month_before_last from the_month_before_last)\n)\n\n\nSELECT\n COALESCE(NULLIF(tmr.author_name,''), NULLIF(lmr.author_name,''), tmblr.author_name) AS 'Author Name',\n\tCOALESCE(tmblr.the_month_before_last_count,0) AS \"The Month before Last\",\n\tCOALESCE(lmr.last_month_count,0) AS \"Last Month\",\n\tCOALESCE(tmr.this_month_count,0) AS \"This Month\",\n\tcase \n\t when lmr.last_month_count is null or tmr.this_month_count is null then '-'\n\t else concat(FORMAT(100 * (tmr.this_month_count - lmr.last_month_count)/lmr.last_month_count,1),'%') end as \"Changes in last 2 month\"\nFROM this_month_record tmr \nright join last_month_record lmr on tmr.author_name = lmr.author_name \nright join the_month_before_last_record tmblr on lmr.author_name = tmblr.author_name\nunion\nSELECT\n COALESCE(NULLIF(tmr.author_name,''), NULLIF(lmr.author_name,''), tmblr.author_name) AS 'Author Name',\n\tCOALESCE(tmblr.the_month_before_last_count,0) AS \"The Month before Last\",\n\tCOALESCE(lmr.last_month_count,0) AS \"Last Month\",\n\tCOALESCE(tmr.this_month_count,0) AS \"This Month\",\n\tcase \n\t when lmr.last_month_count is null or tmr.this_month_count is null then '-'\n\t else concat(FORMAT(100 * (tmr.this_month_count - lmr.last_month_count)/lmr.last_month_count,1),'%') end as \"Changes in last 2 month\"\nFROM this_month_record tmr \nleft join last_month_record lmr on tmr.author_name = lmr.author_name \nleft join the_month_before_last_record tmblr on lmr.author_name = tmblr.author_name\norder by 4 desc\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "type": "table" + }, + { + "datasource": null, + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 17 + }, + "id": 52, + "options": { + "content": "
\n\nThis dashboard is created based on this [data schema](https://devlake.apache.org/docs/DataModels/DevLakeDomainLayerSchema). Want to add more metrics? Please follow the [guide](https://devlake.apache.org/docs/Configuration/Dashboards/GrafanaUserGuide).", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + } + ], + "refresh": "", + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-6M", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Demo-Commit Count by Author", + "uid": "F0iYknc7z", + "version": 3 +} \ No newline at end of file diff --git a/charts/devlake/dashboards/DemoDetailedBugInfo.json b/charts/devlake/dashboards/DemoDetailedBugInfo.json new file mode 100644 index 0000000..df10f93 --- /dev/null +++ b/charts/devlake/dashboards/DemoDetailedBugInfo.json @@ -0,0 +1,315 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 2, + "links": [ + { + "asDropdown": false, + "icon": "bolt", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": false, + "title": "Homepage", + "tooltip": "", + "type": "link", + "url": "/grafana/d/0Rjxknc7z/demo-homepage?orgId=1" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": false, + "title": "Back to previous page", + "tooltip": "", + "type": "link", + "url": "/grafana/d/G4DEk75nz/demo-was-our-quality-improved-or-not?orgId=1" + } + ], + "panels": [ + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 32, + "options": { + "barWidth": 0.3, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 16 + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with bugs as(\n select \n DATE_ADD(date(created_date), INTERVAL -DAY(date(created_date))+1 DAY) as time,\n count(*) as bug_count\n from issues i\n where \n type = 'BUG'\n and $__timeFilter(created_date)\n group by 1\n order by 1 desc\n)\n\nselect\n date_format(time,'%M %Y') as month,\n bug_count as 'Bug Count over Month'\nfrom bugs\norder by time asc", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Bug count over Month", + "type": "barchart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "title" + }, + "properties": [ + { + "id": "custom.width", + "value": 405 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "summary" + }, + "properties": [ + { + "id": "custom.width", + "value": 538 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "description" + }, + "properties": [ + { + "id": "custom.width", + "value": 753 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "created_date" + }, + "properties": [ + { + "id": "custom.width", + "value": 160 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "status" + }, + "properties": [ + { + "id": "custom.width", + "value": 284 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 8 + }, + "id": 30, + "options": { + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select \n title,\n description,\n case when assignee_id = '' then '-' else assignee_name end as assignee,\n status,\n created_date,\n url\n from issues i\n where \n type = 'BUG'\n and $__timeFilter(created_date)\n order by created_date desc", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "type": "table" + }, + { + "datasource": null, + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 34, + "options": { + "content": "
\n\nThis dashboard is created based on this [data schema](https://devlake.apache.org/docs/DataModels/DevLakeDomainLayerSchema). Want to add more metrics? Please follow the [guide](https://devlake.apache.org/docs/Configuration/Dashboards/GrafanaUserGuide).", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + } + ], + "refresh": "", + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-6M", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Demo-Detailed Bug Info", + "uid": "s48Lzn5nz", + "version": 8 +} \ No newline at end of file diff --git a/charts/devlake/dashboards/DemoHomepage.json b/charts/devlake/dashboards/DemoHomepage.json new file mode 100644 index 0000000..c299847 --- /dev/null +++ b/charts/devlake/dashboards/DemoHomepage.json @@ -0,0 +1,191 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 10, + "links": [], + "panels": [ + { + "cacheTimeout": null, + "datasource": null, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 0 + }, + "id": 2, + "interval": null, + "links": [], + "options": { + "content": "\n
\n

How fast do we respond to customer requirements?

\n
\n
", + "mode": "html" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": false, + "rawSql": "SELECT\n create_time AS \"time\",\n progress\nFROM ca_analysis\nWHERE\n $__timeFilter(create_time)\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "type": "text" + }, + { + "cacheTimeout": null, + "datasource": null, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 0 + }, + "id": 3, + "interval": null, + "links": [], + "options": { + "content": "\n
\n

Was our quality improved or not?

\n
\n
", + "mode": "html" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": false, + "rawSql": "SELECT\n create_time AS \"time\",\n progress\nFROM ca_analysis\nWHERE\n $__timeFilter(create_time)\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "type": "text" + }, + { + "cacheTimeout": null, + "datasource": null, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 0 + }, + "id": 4, + "interval": null, + "links": [], + "options": { + "content": "\n
\n

Is this month more productive than last?

\n
\n
", + "mode": "html" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": false, + "rawSql": "SELECT\n create_time AS \"time\",\n progress\nFROM ca_analysis\nWHERE\n $__timeFilter(create_time)\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "type": "text" + } + ], + "refresh": "", + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-6M", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Demo-Homepage", + "uid": "0Rjxknc7z", + "version": 2 +} \ No newline at end of file diff --git a/charts/devlake/dashboards/DemoHowFastDoWeRespondToCustomerRequirements.json b/charts/devlake/dashboards/DemoHowFastDoWeRespondToCustomerRequirements.json new file mode 100644 index 0000000..863541e --- /dev/null +++ b/charts/devlake/dashboards/DemoHowFastDoWeRespondToCustomerRequirements.json @@ -0,0 +1,223 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 11, + "links": [ + { + "asDropdown": false, + "icon": "bolt", + "includeVars": false, + "keepTime": true, + "tags": [], + "targetBlank": false, + "title": "Homepage", + "tooltip": "", + "type": "link", + "url": "/grafana/d/0Rjxknc7z/demo-homepage?orgId=1" + } + ], + "panels": [ + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 17, + "interval": "", + "links": [ + { + "title": "Drill down by Assignee", + "url": "/grafana/d/q27fk7cnk/demo-average-requirement-lead-time-by-assignee?orgId=1" + } + ], + "options": { + "barWidth": 0.25, + "groupWidth": 0.74, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 18 + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _requirements as(\n select \n DATE_ADD(date(resolution_date), INTERVAL -DAY(date(resolution_date))+1 DAY) as time,\n avg(lead_time_minutes)/1440 as lead_time_days\n from issues i\n where \n type = 'REQUIREMENT'\n and $__timeFilter(resolution_date)\n group by time\n)\n\nselect\n date_format(time,'%M %Y') as month,\n lead_time_days as 'Average Requirement Lead Time (day)'\nfrom _requirements\norder by time asc", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Average Requirement Lead Time over time (day)", + "type": "barchart" + }, + { + "datasource": null, + "gridPos": { + "h": 2, + "w": 5, + "x": 0, + "y": 9 + }, + "id": 103, + "options": { + "content": "
\n\n[Drill down by assignee](/d/q27fk7cnk/demo-average-requirement-lead-time-by-assignee?orgId=1)\n ", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": null, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 11 + }, + "id": 101, + "options": { + "content": "
\n \"Merico\"\n

MARI Guide - Requirement Lead Time

\n
\n\nSection | Description\n:----------------- | :-------------\nMetric Definition | Total duration of requirements from proposal to delivery. It can be divided by flow status in the practice domain or project management system to count the time share of each phase and help locate the links that drag out the requirement delivery cycle.\nMetric Value | The Requirement Lead Time reflects the rapid responsiveness of the R&D team.
In theory, the faster you can deliver value to customers, the better, but other aspects such as whether the delivered value meets customer expectations, requirement throughput, and delivery quality must be considered together. Fast delivery does not necessarily equate to good R&D practices.\n\n***\n#### *M (Measure)*\n1. Count the average or 80th percentile requiremnt lead time for different times.\n2. Counts the average or 80th percentile requiremnt lead time for different projects.
\n3. Count the length of time that requirements stay in different practice domains (requirements analysis, design, development, testing, release) or in different states.\n\n##### *A (Analyze)*\n1. Compare the requirement delivery speed of different projects to find the fastest and slowest delivering projects.\n2. Analyze the trend of the average requirement lead time within each cycle, make a vertical comparison, and locate the key points such as maximum value, minimum value, continuous up cycle, and continuous down cycle.\n3. Analyze the trend of the delivery cycle of 80% of the requirements within each cycle, make a longitudinal comparison, and locate the key points such as maximum value, minimum value, continuous up cycle, and continuous down cycle.

\nWhy choose the 80% quantile instead of using the average?
\nThe point of statistics is to make predictions with real and valid data to support better decisions, while the mean and median cannot have the role of supporting predictions.
\nTypically, the mean and 80% quantile statistics will appear twice as far apart, and the 80% and 99% quantile tend to be approximately twice as related.
\nTherefore, the 80% quantile is a good balance point for prediction.\n
\n4. Analysis compares the length of time requirement stays in different practice domains or different states to identify the most time-consuming links and find the key bottlenecks that affect overall delivery speed.\n5. Requirement lead time is correlated with requirement throughput to identify whether the requirement delivery trend is healthy or not.\n - Healthy trend: requirement lead time is shortened and requirement throughput is increased.\n - Unhealthy trend: longer requirement lead time and lower requirement throughput.\n\n\n##### *R (Review)*\nBased on the analysis results, focus on a few key points and use Ishikawa diagram (fishbone diagram) or Root Cause Analysis (RCA) to conduct root cause analysis, research and review. For example, if the requirement delivery cycle becomes longer in several consecutive statistical cycles, it is necessary to further investigate the length of stay of requirements in different phases and find the longest phase for root cause analysis.\n\n1. The requirements phase takes too long: unclear requirements, frequent changes, overly granular requirements, requirements priorities not clearly defined, insufficient resources or experience of requirements analysts or product managers?\n2. The design phase takes too long: unclear requirement documents, insufficient resources or experience of R&D leaders or architects?\n3. The development phase takes too long: unclear design documents, uneven task distribution, high stream load (parallel tasks), too much technical debt, too many bugs, insufficient resources or experience of developers?\n4. The testing phase takes too long: unclear requirements documentation, poor code quality, few automated tests, insufficient resources or experience of testers?\n5. The release phase takes too long: too long build or deployment time, insufficient resources or experience of operation and maintenance staff?\n\n##### *I (Improve)*\nBased on the review results, focus on the key root causes, and give targeted improvement measures in terms of norms, processes, tools and behaviors, etc., with clear improvement targets, improvement measures, verification cycles and responsible persons.\n\nThe following are the improvement ideas for reference:\n\n1. Communicate with customers or business parties to clarify requirements, reasonably disassemble requirements and define priorities, and invite business parties, R&D leaders and testing leaders to review requirements.\n2. Invite product managers, R&D personnel, and test leaders to conduct design reviews.\n3. Reduce requirement or task granularity, distribute tasks evenly, reduce flow load, increase unit testing, and solve technical debt and code problems in time to reduce the number of bugs and rework.\n4. Test left, develop self-test, code review, increase automated testing, and improve continuous integration capabilities.\n5. Automate deployment, shorten build time, and improve continuous delivery.\n6. Reasonable resource allocation and necessary training for each job holder.\n7. The improvement results should also be quantifiable to facilitate continuous metrics and tracking of improvement effects.", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": null, + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 21 + }, + "id": 105, + "options": { + "content": "
\n\nThis dashboard is created based on this [data schema](https://devlake.apache.org/docs/DataModels/DevLakeDomainLayerSchema). Want to add more metrics? Please follow the [guide](https://devlake.apache.org/docs/Configuration/Dashboards/GrafanaUserGuide).", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + } + ], + "refresh": "", + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-6M", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Demo-How fast do we respond to customer requirements?", + "uid": "SupYz7c7z", + "version": 4 +} \ No newline at end of file diff --git a/charts/devlake/dashboards/DemoIsThisMonthMoreProductiveThanLast.json b/charts/devlake/dashboards/DemoIsThisMonthMoreProductiveThanLast.json new file mode 100644 index 0000000..520b41f --- /dev/null +++ b/charts/devlake/dashboards/DemoIsThisMonthMoreProductiveThanLast.json @@ -0,0 +1,253 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 12, + "links": [ + { + "asDropdown": false, + "icon": "bolt", + "includeVars": false, + "keepTime": true, + "tags": [], + "targetBlank": false, + "title": "Homepage", + "tooltip": "", + "type": "link", + "url": "/grafana/d/0Rjxknc7z/demo-homepage?orgId=1" + } + ], + "panels": [ + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "links": [ + { + "targetBlank": true, + "title": "Break down by user1", + "url": "/grafana/d/cHnTA7K7z/is-this-month-more-productive-than-last-by-users?orgId=1" + } + ], + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "Commit Count" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 36, + "links": [ + { + "targetBlank": false, + "title": "Drill down by Commit Author", + "url": "/d/F0iYknc7z/demo-commit-count-by-author?orgId=1" + } + ], + "options": { + "barWidth": 0.25, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": {}, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _commits as(\n SELECT\n DATE_ADD(date(authored_date), INTERVAL -DAY(date(authored_date))+1 DAY) as time,\n count(*) as commit_count\n FROM commits\n WHERE\n message not like '%Merge%'\n and $__timeFilter(authored_date)\n group by 1\n)\n\nSELECT \n date_format(time,'%M %Y') as month,\n commit_count as \"Commit Count\"\nFROM _commits\nORDER BY time", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Commit Count over Time", + "type": "barchart" + }, + { + "datasource": null, + "gridPos": { + "h": 2, + "w": 5, + "x": 0, + "y": 9 + }, + "id": 40, + "options": { + "content": "
\n\n[Drill down by commit author](/d/F0iYknc7z/demo-commit-count-by-author?orgId=1)\n ", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": null, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 11 + }, + "id": 38, + "options": { + "content": "
\n \"Merico\"\n

MARI Guide - Commit Count

\n
\n\nSection | Description\n:------------------ | :-------------\nMetric Definition | The total number of commits.\nMetric Value | The number of commits reflects the frequency of code commits and encourages multiple small step commits per day. While paying attention to the number of times, you should also observe the number of lines of code per commit.\n\n***\n\n#### *M (Measure)*\nThe number of commits can be counted in time, project, team or individual dimensions, and the above 4 dimensions can be cross-tabulated, e.g., the number of commits per week for a project, the average number of commits per person per day for a team.\n\n##### *A (Analyze)*\n1. By project dimension, analyze and compare the number of code commits of different projects horizontally, and locate the projects with the maximum, minimum and lower than average values for research.\n2. By team dimension, analyze and compare the number of code commits of different teams horizontally, and locate the teams with the maximum, minimum, and lower than average values for research.\n3. By individual dimension, analyze and compare the number of code commits of different personnel horizontally, and locate the individuals with the maximum, minimum, and lower than average values for research.\n4. Analyze the trend of the number of code commits in each cycle, compare vertically, and locate the maximum, minimum, and continuously increasing or decreasing cycles for research.\n\n##### *R (Review)*\nBased on the results of metrics analysis, use Ishikawa diagram (fishbone diagram) or root cause analysis (RCA) to analyze, investigate and review the root causes of projects/teams/individuals with low (e.g. lower than average) code submission times in a cycle:\n1. too many complicated requirements with large granularity (estimated workload)?\n2. uneven and full task distribution?\n3. no specification for small step submission?\n\n##### *I (Improve)*\nBased on the review results, focus on the key root causes, give targeted improvement measures in terms of specification, process, tools, behavior, etc., and clarify the improvement target, improvement measures, verification cycle and responsible person.\nTo address the root causes of low code submission in the cycle, the following improvement measures were taken: 1.\n1. reduce the granularity of requirements.\n2. distribute tasks evenly so that each person has a full workload each day.\n3. set small step commit specifications, such as an average number of commits per person per day greater than 1, an average number of lines per commit less than 100, etc.", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": null, + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 21 + }, + "id": 42, + "options": { + "content": "
\n\nThis dashboard is created based on this [data schema](https://devlake.apache.org/docs/DataModels/DevLakeDomainLayerSchema). Want to add more metrics? Please follow the [guide](https://devlake.apache.org/docs/Configuration/Dashboards/GrafanaUserGuide).", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + } + ], + "refresh": "", + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-6M", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Demo-Is this month more productive than last?", + "uid": "ddREk75nk", + "version": 3 +} \ No newline at end of file diff --git a/charts/devlake/dashboards/DemoWasOurQualityImprovedOrNot.json b/charts/devlake/dashboards/DemoWasOurQualityImprovedOrNot.json new file mode 100644 index 0000000..acb70c6 --- /dev/null +++ b/charts/devlake/dashboards/DemoWasOurQualityImprovedOrNot.json @@ -0,0 +1,220 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 6, + "links": [ + { + "asDropdown": false, + "icon": "bolt", + "includeVars": false, + "keepTime": false, + "tags": [], + "targetBlank": false, + "title": "Homepage", + "tooltip": "", + "type": "link", + "url": "/grafana/d/0Rjxknc7z/demo-homepage?orgId=1" + } + ], + "panels": [ + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 35, + "links": [ + { + "targetBlank": false, + "title": "See Detailed Bug Info", + "url": "/grafana/d/s48Lzn5nz/demo-detailed-bug-info?orgId=1" + } + ], + "options": { + "barWidth": 0.3, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "always", + "text": { + "valueSize": 14 + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with line_of_code as (\n\tselect \n\t DATE_ADD(date(authored_date), INTERVAL -DAY(date(authored_date))+1 DAY) as time,\n\t sum(additions + deletions) as line_count\n\tfrom \n\t commits\n\twhere \n\t message not like 'Merge%'\n\t and $__timeFilter(authored_date)\n\tgroup by 1\n),\n\n\nbug_count as(\n select \n DATE_ADD(date(created_date), INTERVAL -DAY(date(created_date))+1 DAY) as time,\n count(*) as bug_count\n from issues i\n where \n type = 'BUG'\n and $__timeFilter(created_date)\n group by 1\n),\n\n\nbug_count_per_1k_loc as(\n select \n loc.time,\n 1.0 * bc.bug_count / loc.line_count * 1000 as bug_count_per_1k_loc\n from \n line_of_code loc\n left join bug_count bc on bc.time = loc.time\n where\n bc.bug_count is not null \n and loc.line_count is not null \n and loc.line_count != 0\n)\n\nselect \n date_format(time,'%M %Y') as month,\n bug_count_per_1k_loc as 'Bug Count per 1000 Lines of Code'\nfrom bug_count_per_1k_loc \norder by time;", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Bug Count per 1k Lines of Code", + "type": "barchart" + }, + { + "datasource": null, + "gridPos": { + "h": 2, + "w": 5, + "x": 0, + "y": 8 + }, + "id": 37, + "options": { + "content": "
\n\n[See Detailed Bug Info](/d/s48Lzn5nz/demo-detailed-bug-info?orgId=1)\n ", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": null, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 32, + "options": { + "content": "
\n \"Merico\"\n

MARI Guide - Bug Count per 1k Lines of Code

\n
\n\nSection | Description\n:----------------- | :-------------\nMetric Definition | The ratio of the number of bugs found to the corresponding amount of code or code changes, to characterize the density of overall bugs, including bugs found in testing and online. For example, bug count per 1k lines of code, bug count per 1k code equivalent.\nMetric Value | The bug rate, as a quality indicator, represents the density of bugs, and is one of the important indicators used to assess the quality of software products and testing quality. Usually, the cost of fixing detected bugs is higher in the later stage of the software development life cycle, and this metric is valuable for analyzing and evaluating both online quality and bug fixing cost.\n\n***\n#### *M (Measure)*\n1. Bug count per 1k lines of code by project.\n2. Trends in 'Bug count per 1k lines of code' over time.\n3. Measure historical data to establish year-over-year and historical baseline reference values for 'Bug count per 1k lines of code'.\n\n##### *A (Analyze)*\n1. Year-over-year analysis: The bug rate of similar projects in the same period is compared and analyzed, and the improvement effect of product quality is observed through the rise and fall of the data.\n2. Circumferential analysis: Analyze the bug rate of projects in the recent year, analyze the change of online bug rate according to the time axis, and compare with the historical baseline at the same time to give a judgment analysis of the rise and fall of indicators.\n3. Trend analysis: analyze the trend of bug rate over time (days, weeks, months), judge the trend rise, and evaluate whether the stable cycle of product quality is reasonable by observing changes such as trend slowing-down and smoothing.\n4. Horizontal analysis: Compare the bug rate of multiple projects as a reference to evaluate the quality of software products online.\n5. Classification analysis: Classify and analyze the types of bugs, severity levels, and modules they belong to, and identify the key issues that show aggregated distribution.\n\n##### *R (Review)*\nFor the high severity level of online bugs should be a complete review, according to the timeline, role dimensions, the sequence of events on the root cause of bugs to dig, locate the key issues.\nAccording to the quantitative conclusions drawn from the analysis, further data drilling and root cause mining can be organized for bugs in several dimensions, including whether they are missed, the module they belong to, the cause, the occurrence cycle, and the resolution.\n1. bug escape rate: derived from [number of online bugs / (number of online bugs + number of bugs found in test)], this indicator can be compared with historical data, if the data exceeds the acceptable range of history and testing department, then it is necessary to conduct leak analysis. If the data exceeds the acceptable interval of history and testing department, it is necessary to analyze the missed test and confirm whether the use case is missed or not covered, so as to strengthen the use case design and management.\n2. defective module: The defective module can be located to the key module where the problem is concentrated, and targeted improvement measures are required for each link from requirements, design, development to testing, and typical problems are located for the bugive module to establish targeted measures.\n3. bug generation causes: through the cause analysis of bugs, similar bugs bugs can be put together, so that bugs belonging to the same category and accounting for a high percentage of bugs will be highlighted, so that it is easy to take out the bugs with more concentrated causes and jointly discuss the next improvement measures to precisely reduce the number of similar bugs.\n4. bug occurrence cycle: analyze the bug occurrence cycle, determine whether the users use the system frequently, whether the system has been updated or optimized, whether the system has been refactored, etc., which will cause a long and short bug occurrence cycle after the launch, through the analysis of the bug cycle length, to draw some valuable conclusions about the stability of the system.\n5. bug resolution: statistics on the resolution of bugs, which bugs are not reproduced, which are temporarily handled, and which are in need of continuous improvement. For the temporary resolution of bugs, analyze whether it will cause another bug elsewhere in the system, whether the user can receive the temporary resolution, what development and testing need to focus on similar bugs, and whether similar bugs need to be tested elsewhere for horizontal expansion. Those that require continuous improvement need to be further tracked by testing until the problem is resolved.\n\n##### *I (Improve)*\nThrough root cause mining, starting from the key bugs, the key problems of each link to locate, in accordance with the principle that the later the bugs are found, the higher the cost and complexity of the solution, in addition to the test design and implementation to start improving (refer to the improvement links of the number of bugs on the line), more should start the construction of quality from the upstream of the software engineering stage, to achieve the forward movement of the bug discovery stage, such as\n1. optimizing static scan rules according to the type, number and severity level of static scan problems to reduce false positives and expose as many serious problems as possible (quality over quantity).\n2. Define the requirement of resolution ratio for different severity level problems to control the backlog of serious problems.\n3. Establish code review system, strategy, and encourage the promotion of code review implementation.\n4. Establish unit test coverage ratio or unit test coverage condition requirements, e.g. functions with circle complexity greater than 10 shall be covered by unit tests.\nImplement improvement measures and clarify the improvement target, improvement measures, verification cycle and responsible person. Do a new round of MARI (Measure, Analysis, Review, and Verification) for the improvement effect to quantify the improvement effect.", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": null, + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 39, + "options": { + "content": "
\n\nThis dashboard is created based on this [data schema](https://devlake.apache.org/docs/DataModels/DevLakeDomainLayerSchema). Want to add more metrics? Please follow the [guide](https://devlake.apache.org/docs/Configuration/Dashboards/GrafanaUserGuide).", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + } + ], + "refresh": "", + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-6M", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Demo-Was our quality improved or not?", + "uid": "G4DEk75nz", + "version": 4 +} \ No newline at end of file diff --git a/charts/devlake/dashboards/EngineeringOverview.json b/charts/devlake/dashboards/EngineeringOverview.json new file mode 100644 index 0000000..4749fda --- /dev/null +++ b/charts/devlake/dashboards/EngineeringOverview.json @@ -0,0 +1,1849 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 25, + "iteration": 1682062941722, + "links": [], + "panels": [ + { + "datasource": null, + "gridPos": { + "h": 3, + "w": 13, + "x": 0, + "y": 0 + }, + "id": 32, + "options": { + "content": "- Use Cases: This dashboard is to overview the Git and project management metrics.\n- Data Source Required: Jira + GitHub, or Jira + GitLab.", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "title": "Dashboard Introduction", + "type": "text" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "orange", + "value": 10 + }, + { + "color": "red", + "value": 20 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 3 + }, + "id": 8, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select\n count(*)\nfrom\n lake.issues i\n\tjoin board_issues bi on i.id = bi.issue_id\n\tjoin boards b on bi.board_id = b.id\n\tjoin project_mapping pm on b.id = pm.row_id\nwhere\n pm.project_name in ($project) and\n i.priority in ($priority) and\n i.type = 'BUG' and\n date(i.created_date) between STR_TO_DATE('$month','%Y-%m-%d') and STR_TO_DATE('$month','%Y-%m-%d') + INTERVAL 1 MONTH - INTERVAL 1 DAY;", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Critical Defects Identified", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 18, + "x": 6, + "y": 3 + }, + "id": 22, + "options": { + "barWidth": 0.46, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with _issues as(\n select\n DATE_ADD(date(i.created_date), INTERVAL -DAY(date(i.created_date))+1 DAY) as time,\n count(*) as defect_count\n from\n lake.issues i\n join board_issues bi on i.id = bi.issue_id\n\t join boards b on bi.board_id = b.id\n\t join project_mapping pm on b.id = pm.row_id\n where\n pm.project_name in ($project) and\n i.priority in ($priority)\n and i.type = 'BUG'\n and $__timeFilter(i.created_date)\n and i.created_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\n group by time\n)\n\nselect\n date_format(time,'%M %Y') as month,\n defect_count\nfrom _issues\norder by time asc\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Critical Defects Identified over Month", + "type": "barchart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 14 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 11 + }, + "id": 10, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "/^value$/", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select \r\n avg(lead_time_minutes/1440) as value\r\nfrom issues i\r\n\tjoin board_issues bi on i.id = bi.issue_id\r\n\tjoin boards b on bi.board_id = b.id\r\n\tjoin project_mapping pm on b.id = pm.row_id\r\nwhere \r\n pm.project_name in ($project) and\r\n i.type in ($type)\r\n and i.status = 'DONE'\r\n and $__timeFilter(i.resolution_date)", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Mean Issue Lead Time in Days [Issues Resolved in Select Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Lead Time(days)", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 18, + "x": 6, + "y": 11 + }, + "id": 23, + "interval": "", + "options": { + "barWidth": 0.5, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _issues as(\n SELECT\n DATE_ADD(date(i.resolution_date), INTERVAL -DAY(date(i.resolution_date))+1 DAY) as time,\n AVG(i.lead_time_minutes/1440) as issue_lead_time\n FROM issues i\n\t join board_issues bi on i.id = bi.issue_id\n\t join boards b on bi.board_id = b.id\n\t join project_mapping pm on b.id = pm.row_id\n WHERE\n pm.project_name in ($project)\n and i.status = \"DONE\"\n and $__timeFilter(i.resolution_date)\n and i.resolution_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\n group by 1\n)\n\nSELECT \n date_format(time,'%M %Y') as month,\n issue_lead_time as \"Mean Requirement Lead Time in Days\"\nFROM _issues\nORDER BY time", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Mean Requirement Lead Time in Days [Of Issues Resolved per Month]", + "type": "barchart" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 10 + }, + { + "color": "green", + "value": 15 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 17 + }, + "id": 14, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select\n count(distinct author_name)\nfrom\n lake.commits c\n join lake.repo_commits rc on c.sha = rc.commit_sha\n join project_mapping pm on rc.repo_id = pm.row_id\nwhere\n date(authored_date) between\n STR_TO_DATE('$month','%Y-%m-%d') and\n STR_TO_DATE('$month','%Y-%m-%d') + INTERVAL 1 MONTH - INTERVAL 1 DAY and\n pm.project_name in ($project);", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Number of Developers", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 18, + "x": 6, + "y": 17 + }, + "id": 24, + "options": { + "barWidth": 0.5, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with _developers as(\n select\n DATE_ADD(date(c.authored_date), INTERVAL -DAY(date(c.authored_date))+1 DAY) as time,\n count(distinct author_name) as developer_count\n from\n lake.commits c\n join lake.repo_commits rc on c.sha = rc.commit_sha\n join project_mapping pm on rc.repo_id = pm.row_id\n where\n $__timeFilter(c.authored_date)\n and c.authored_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\n and pm.project_name in ($project)\n group by time\n)\n\nselect\n date_format(time,'%M %Y') as month,\n developer_count\nfrom _developers\norder by time asc", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Number of Developers", + "type": "barchart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "#EAB839", + "value": 60 + }, + { + "color": "green", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 25 + }, + "id": 6, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with _num_issues_with_sprint_updated as (\n select\n count(*) as num_issues_with_sprint_updated\n from\n lake.issues i\n join board_issues bi on i.id = bi.issue_id\n\t join boards b on bi.board_id = b.id\n\t join project_mapping pm on b.id = pm.row_id\n join lake.issue_changelogs c on i.id = c.issue_id\n where\n pm.project_name in ($project) and\n c.field_name = 'Sprint' and\n c.original_from_value != '' and\n c.original_to_value != '' and\n date(i.created_date) between\n STR_TO_DATE('$month','%Y-%m-%d') and\n STR_TO_DATE('$month','%Y-%m-%d') + INTERVAL 1 MONTH - INTERVAL 1 DAY\n),\n\n_total_num_issues as (\n select\n count(*) as total_num_issues\n from\n lake.issues i\n join board_issues bi on i.id = bi.issue_id\n\t join boards b on bi.board_id = b.id\n\t join project_mapping pm on b.id = pm.row_id\n where\n pm.project_name in ($project) and\n date(i.created_date) between\n STR_TO_DATE('$month','%Y-%m-%d') and\n STR_TO_DATE('$month','%Y-%m-%d') + INTERVAL 1 MONTH - INTERVAL 1 DAY\n)\n\nselect\n now() as time,\n 100 - 100 * (select 1.0 * num_issues_with_sprint_updated from _num_issues_with_sprint_updated) / (select total_num_issues from _total_num_issues) as ratio;", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "On-time Delivery", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 10, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 60 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 18, + "x": 6, + "y": 25 + }, + "id": 25, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with _num_issues_with_sprint_updated as (\n select\n DATE_ADD(date(i.created_date), INTERVAL -DAY(date(i.created_date))+1 DAY) as time,\n count(*) as num_issues_with_sprint_updated\n from\n lake.issues i\n join board_issues bi on i.id = bi.issue_id\n\t join boards b on bi.board_id = b.id\n\t join project_mapping pm on b.id = pm.row_id\n join lake.issue_changelogs c on i.id = c.issue_id\n where\n pm.project_name in ($project) and\n c.field_name = 'Sprint'\n and c.original_from_value != '' \n and c.original_to_value != ''\n and $__timeFilter(i.created_date)\n and i.created_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\n group by time\n),\n\n_total_num_issues as (\n select\n DATE_ADD(date(i.created_date), INTERVAL -DAY(date(i.created_date))+1 DAY) as time,\n count(*) as total_num_issues\n from\n lake.issues i\n join board_issues bi on i.id = bi.issue_id\n\t join boards b on bi.board_id = b.id\n\t join project_mapping pm on b.id = pm.row_id\n where\n pm.project_name in ($project) and\n $__timeFilter(i.created_date)\n and i.created_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\n group by time\n)\n\nselect\n x.time,\n 100 - 100 * (1.0 * x.num_issues_with_sprint_updated / y.total_num_issues) as delivery_rate\nfrom \n _num_issues_with_sprint_updated x \n join _total_num_issues y on x.time = y.time", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "On-time Delivery over Month", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 20 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 33 + }, + "id": 4, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select\n count(*)\nfrom\n lake.pull_requests pr\n join project_mapping pm on pr.base_repo_id = pm.row_id\nwhere\n pr.merged_date is not null \n and date(pr.merged_date) between\n STR_TO_DATE('$month','%Y-%m-%d')\n and STR_TO_DATE('$month','%Y-%m-%d') + INTERVAL 1 MONTH - INTERVAL 1 DAY \n and pm.project_name in ($project);", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "PRs merged", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 18, + "x": 6, + "y": 33 + }, + "id": 26, + "options": { + "barWidth": 0.5, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with _merged_prs as(\n select\n DATE_ADD(date(pr.merged_date), INTERVAL -DAY(date(pr.merged_date))+1 DAY) as time,\n count(*) as pr_merged_count\n from\n lake.pull_requests pr\n join project_mapping pm on pr.base_repo_id = pm.row_id\n where\n pm.project_name in ($project)\n and pr.merged_date is not null\n and $__timeFilter(pr.merged_date)\n and pr.merged_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\n group by time\n)\n\nselect\n date_format(time,'%M %Y') as month,\n pr_merged_count\nfrom _merged_prs\norder by time asc", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "PRs Merged over Month", + "type": "barchart" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "orange", + "value": 20 + }, + { + "color": "red", + "value": 40 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 41 + }, + "id": 16, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select \n 100*sum(case when id in (select pull_request_id from pull_request_issues) then 1 else 0 end)/count(*) as unlinked_pr_rate\nfrom lake.pull_requests pr\njoin project_mapping pm on pr.base_repo_id = pm.row_id\nwhere pm.project_name in ($project)", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Unlinked PRs %", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 10, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 18, + "x": 6, + "y": 41 + }, + "id": 28, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select\n DATE_ADD(date(created_date), INTERVAL -DAY(date(created_date))+1 DAY) as time,\n 100*sum(case when id in (select pull_request_id from pull_request_issues) then 1 else 0 end)/count(*) as unlinked_pr_rate\nfrom lake.pull_requests pr\njoin project_mapping pm on pr.base_repo_id = pm.row_id\nwhere pm.project_name in ($project)\nand $__timeFilter(created_date)\nand created_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\ngroup by time\n\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Unlinked PRs Ratio over Month", + "type": "timeseries" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 50 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 49 + }, + "id": 12, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with _commits_groupby_name_and_date as (\n select\n author_name,\n date(authored_date) as _day,\n count(*)\n from\n lake.commits c\n join lake.repo_commits rc on c.sha = rc.commit_sha\n join project_mapping pm on rc.repo_id = pm.row_id\n where\n pm.project_name in ($project) and\n WEEKDAY(authored_date) between 0 and 4 and\n date(authored_date) between\n STR_TO_DATE('$month','%Y-%m-%d') and\n STR_TO_DATE('$month','%Y-%m-%d') + INTERVAL 1 MONTH - INTERVAL 1 DAY\n group by\n author_name, date(authored_date)\n)\n\nselect 100 * count(*) / (count(distinct author_name) * count(distinct _day))\nfrom _commits_groupby_name_and_date;", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Coding Days %", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 10, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 18, + "x": 6, + "y": 49 + }, + "id": 29, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with _commits_groupby_name_and_date as (\n select\n author_name,\n date(authored_date) as _day,\n count(*)\n from\n lake.commits c\n join lake.repo_commits rc on c.sha = rc.commit_sha\n join project_mapping pm on rc.repo_id = pm.row_id\n where\n pm.project_name in ($project) and\n (WEEKDAY(authored_date) between 0 and 4)\n and $__timeFilter(authored_date)\n and authored_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\n group by 1,2\n)\n\nselect\n DATE_ADD(_day, INTERVAL -DAY(_day)+1 DAY) as time,\n 100*count(*)/(count(distinct author_name) * count(distinct _day)) as working_days_percentatages_per_month\nfrom _commits_groupby_name_and_date\ngroup by time", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Percentage of Coding Days Each Month", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "d" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 57 + }, + "id": 2, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select\n AVG(TIMESTAMPDIFF(MINUTE, pr.created_date, pr.merged_date) / 1440)\nfrom\n lake.pull_requests pr\n join project_mapping pm on pr.base_repo_id = pm.row_id\nwhere\n pm.project_name in ($project) and\n pr.merged_date is not null\n and date(pr.created_date) between\n STR_TO_DATE('$month','%Y-%m-%d') \n and STR_TO_DATE('$month','%Y-%m-%d') + INTERVAL 1 MONTH - INTERVAL 1 DAY", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_raw_github_api_repositories", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "PR Cycle Time", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 10, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "d" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 18, + "x": 6, + "y": 57 + }, + "id": 30, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select\n DATE_ADD(date(pr.created_date), INTERVAL -DAY(date(pr.created_date))+1 DAY) as time,\n AVG(TIMESTAMPDIFF(MINUTE, pr.created_date, pr.merged_date) / 1440) as pr_cycle_time_in_days\nfrom\n lake.pull_requests pr\n join project_mapping pm on pr.base_repo_id = pm.row_id\nwhere\n pm.project_name in ($project) and\n pr.merged_date is not null\n and $__timeFilter(pr.created_date)\n and pr.created_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\ngroup by time\norder by time", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_raw_github_api_repositories", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "PR Cycle Time over Month", + "type": "timeseries" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 68, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "d" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 65 + }, + "id": 20, + "options": { + "barWidth": 0.27, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select\n i.priority as 'Priority',\n AVG(TIMESTAMPDIFF(MINUTE, i.created_date, NOW()) / 1440) as 'Average Age'\nfrom\n lake.issues i\n join board_issues bi on i.id = bi.issue_id\n\tjoin boards b on bi.board_id = b.id\n\tjoin project_mapping pm on b.id = pm.row_id\nwhere\n pm.project_name in ($project) and\n i.status = 'TODO'\n and i.type = 'BUG'\n and i.priority in ($priority)\ngroup by\n i.priority", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Average Age of Critical Outstanding Defects by Priority", + "type": "barchart" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 65 + }, + "id": 21, + "options": { + "displayLabels": [ + "name", + "percent" + ], + "legend": { + "displayMode": "table", + "placement": "right", + "values": [ + "value", + "percent" + ] + }, + "pieType": "pie", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select\n sum(case when i.type = 'BUG' then 1 else 0 end) as 'Bug',\n sum(case when i.type = 'BUG' and epic_key != '' then 1 else 0 end) as 'Strategic',\n sum(case when i.type != 'BUG' and epic_key = '' then 1 else 0 end) as 'Non-Strategic'\nfrom\n issues i\n join board_issues bi on i.id = bi.issue_id\n\tjoin boards b on bi.board_id = b.id\n\tjoin project_mapping pm on b.id = pm.row_id\nwhere\n pm.project_name in ($project) and\n i.resolution_date is not null and\n date(resolution_date) between\n STR_TO_DATE('$month','%Y-%m-%d') and\n STR_TO_DATE('$month','%Y-%m-%d') + INTERVAL 1 MONTH - INTERVAL 1 DAY", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprints", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Work Done % [Selected Month]", + "type": "piechart" + }, + { + "datasource": null, + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 73 + }, + "id": 34, + "options": { + "content": "
\n\nThis dashboard is created based on this [data schema](https://devlake.apache.org/docs/DataModels/DevLakeDomainLayerSchema). Want to add more metrics? Please follow the [guide](https://devlake.apache.org/docs/Configuration/Dashboards/GrafanaUserGuide).", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + } + ], + "refresh": "", + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "mysql", + "definition": "select distinct name from projects", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Project", + "multi": true, + "name": "project", + "options": [], + "query": "select distinct name from projects", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "allValue": null, + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": "mysql", + "definition": "select distinct priority from issues", + "description": "Customize what prioriti(es) are considered \"critical\"", + "error": null, + "hide": 0, + "includeAll": true, + "label": "Prioriti(es) of Critical Issues", + "multi": true, + "name": "priority", + "options": [], + "query": "select distinct priority from issues", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "allValue": null, + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "mysql", + "definition": "select distinct type from issues", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Issue Type", + "multi": false, + "name": "type", + "options": [], + "query": "select distinct type from issues", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "allValue": null, + "current": { + "selected": false, + "text": "2022-12", + "value": "2022-12-01" + }, + "datasource": "mysql", + "definition": "select\n distinct(concat(date_format(DATE_ADD(date(created_date), INTERVAL -DAY(date(created_date))+1 DAY), '%Y-%m') , ':', date_format(DATE_ADD(date(created_date), INTERVAL -DAY(date(created_date))+1 DAY), '%Y-%m-%d'))) as month\nfrom\n lake.issues i\norder by month desc", + "description": null, + "error": null, + "hide": 0, + "includeAll": false, + "label": "Month", + "multi": false, + "name": "month", + "options": [], + "query": "select\n distinct(concat(date_format(DATE_ADD(date(created_date), INTERVAL -DAY(date(created_date))+1 DAY), '%Y-%m') , ':', date_format(DATE_ADD(date(created_date), INTERVAL -DAY(date(created_date))+1 DAY), '%Y-%m-%d'))) as month\nfrom\n lake.issues i\norder by month desc", + "refresh": 1, + "regex": "/^(?.*):(?.*)$/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-6M", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Engineering Overview", + "uid": "ZF6abXX7z", + "version": 3 +} \ No newline at end of file diff --git a/charts/devlake/dashboards/EngineeringThroughputAndCycleTime.json b/charts/devlake/dashboards/EngineeringThroughputAndCycleTime.json new file mode 100644 index 0000000..eeeb80e --- /dev/null +++ b/charts/devlake/dashboards/EngineeringThroughputAndCycleTime.json @@ -0,0 +1,1649 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 13, + "iteration": 1682062957718, + "links": [], + "panels": [ + { + "datasource": null, + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 111, + "options": { + "content": "- Use Cases: This dashboard shows the engineering throughput and and cycle time, which helps to identify productivity and bottlenecks of the development process.\n- Data Source Required: GitHub and Jira([transformation](https://devlake.apache.org/docs/UserManuals/ConfigUI/Jira#step-3---adding-transformation-rules-optional) required to tell DevLake what the story_points field is)", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "title": "Dashboard Introduction", + "type": "text" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 3 + }, + "id": 89, + "panels": [], + "title": "1. Throughput/Quality", + "type": "row" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "custom": { + "axisLabel": "Pull Request Count", + "axisPlacement": "auto", + "barAlignment": 1, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "PR: Opened" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PR: Merged" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 4 + }, + "id": 79, + "options": { + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n DATE_ADD(date(pr.created_date), INTERVAL -$interval(date(pr.created_date))+1 DAY) as time,\n count(distinct pr.id) as \"PR: Opened\",\n count(distinct case when pr.merged_date is not null then id else null end) as \"PR: Merged\"\nFROM pull_requests pr\n join project_mapping pm on pr.base_repo_id = pm.row_id\nWHERE\n $__timeFilter(pr.created_date)\n and pm.project_name in ($project)\ngroup by 1\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "PRs Opened/Merged", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Issue Count", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Issues Opened" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Issues Completed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 4 + }, + "id": 74, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n DATE_ADD(date(i.created_date), INTERVAL -$interval(date(i.created_date))+1 DAY) as time,\n count(distinct i.id) as 'Issues Opened',\n count(distinct case when i.status = 'DONE' then i.id else null end) as 'Issues Completed'\nFROM issues i\n\tjoin board_issues bi on i.id = bi.issue_id\n\tjoin boards b on bi.board_id = b.id\n\tjoin project_mapping pm on b.id = pm.row_id\nWHERE\n $__timeFilter(i.created_date)\n and pm.project_name in ($project)\ngroup by 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Issue Opened/Completed", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Story Points", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 4 + }, + "id": 98, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n DATE_ADD(date(i.created_date), INTERVAL -$interval(date(i.created_date))+1 DAY) as time,\n sum(case when i.status = 'DONE' then i.story_point else 0 end) as 'Story Points Completed'\nFROM issues i\n\tjoin board_issues bi on i.id = bi.issue_id\n\tjoin boards b on bi.board_id = b.id\n\tjoin project_mapping pm on b.id = pm.row_id\nWHERE\n $__timeFilter(i.created_date)\n and pm.project_name in ($project)\ngroup by 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Issue Story Points Completed", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "PR Review Depth", + "axisPlacement": "auto", + "barAlignment": 1, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 11 + }, + "id": 99, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n DATE_ADD(date(pr.created_date), INTERVAL -$interval(date(pr.created_date))+1 DAY) as time,\n count(distinct prc.id)/count(distinct pr.id) as \"PR Review Depth\"\nFROM \n pull_requests pr\n left join pull_request_comments prc on pr.id = prc.pull_request_id\n join project_mapping pm on pr.base_repo_id = pm.row_id\nWHERE\n $__timeFilter(pr.created_date)\n and pm.project_name in ($project)\n and pr.merged_date is not null\ngroup by 1\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "PR Review Depth", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Bug Count", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 11 + }, + "id": 100, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n DATE_ADD(date(i.created_date), INTERVAL -$interval(date(i.created_date))+1 DAY) as time,\n count(distinct i.id) as 'P0/P1 Bugs'\nFROM issues i\n\tjoin board_issues bi on i.id = bi.issue_id\n\tjoin boards b on bi.board_id = b.id\n\tjoin project_mapping pm on b.id = pm.row_id\nWHERE\n $__timeFilter(i.created_date)\n and pm.project_name in ($project)\n and i.type = 'BUG'\n and i.priority in ($priority)\ngroup by 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "P0/P1 Bugs", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "PR Size", + "axisPlacement": "auto", + "barAlignment": 1, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 11 + }, + "id": 101, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _pr_commits_data as(\n SELECT\n DATE_ADD(date(pr.created_date), INTERVAL -$interval(date(pr.created_date))+1 DAY) as time,\n pr.id as pr_id,\n prc.commit_sha,\n sum(c.additions)+sum(c.deletions) as loc\n FROM \n pull_requests pr\n left join pull_request_commits prc on pr.id = prc.pull_request_id\n left join commits c on prc.commit_sha = c.sha\n join project_mapping pm on pr.base_repo_id = pm.row_id\n WHERE\n $__timeFilter(pr.created_date)\n and pm.project_name in ($project)\n group by 1,2,3\n)\n\nSELECT \n time,\n sum(loc)/count(distinct pr_id) as 'PR Size'\nFROM _pr_commits_data\nGROUP BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "PR Size", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 18 + }, + "id": 108, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n DATE_ADD(date(pr.created_date), INTERVAL -$interval(date(pr.created_date))+1 DAY) as time,\n sum(case when pr.id not in (SELECT pull_request_id FROM pull_request_comments) then 1 else 0 end) as \"PRs Merged w/o Review\"\nFROM \n pull_requests pr\n join project_mapping pm on pr.base_repo_id = pm.row_id\nWHERE\n $__timeFilter(pr.created_date)\n and pm.project_name in ($project)\n and pr.merged_date is not null\nGROUP BY 1\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "PRs Merged w/o Review", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 25 + }, + "id": 103, + "panels": [], + "title": "2. Cycle Time", + "type": "row" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "PR: Opened" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PR: Merged" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "super-light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 26 + }, + "id": 109, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _prs as(\n SELECT\n pr.id,\n pr.created_date as pr_issued_date,\n -- convert null to 0 if a PR has no cycle_time to make sure cycle_time equals the sum of the four metrics below\n\t\tcoalesce(prm.pr_cycle_time/60,0) as cycle_time\n FROM pull_requests pr\n left join project_pr_metrics prm on pr.id = prm.id\n join project_mapping pm on pr.base_repo_id = pm.row_id\n WHERE\n $__timeFilter(pr.created_date)\n and pr.created_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\n and pm.project_name in ($project)\n GROUP BY 1,2,3\n)\n\nSELECT \n DATE_ADD(date(pr_issued_date), INTERVAL -DAYOFMONTH(date(pr_issued_date))+1 DAY) as time,\n avg(cycle_time) as 'PR Cycle Time(h)'\nFROM _prs\nGROUP BY 1\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "PR Cycle Time", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 33 + }, + "id": 120, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _prs as(\n SELECT\n pr.id,\n pr.created_date as pr_issued_date,\n -- convert null to 0 if a PR has no coding_time to make sure cycle_time equals the sum of the four sub-metrics\n\t\tcoalesce(prm.pr_coding_time/60,0) as coding_time\n FROM pull_requests pr\n left join project_pr_metrics prm on pr.id = prm.id\n join project_mapping pm on pr.base_repo_id = pm.row_id\n WHERE\n $__timeFilter(pr.created_date)\n and pr.created_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\n and pm.project_name in ($project)\n GROUP BY 1,2,3\n)\n\nSELECT \n DATE_ADD(date(pr_issued_date), INTERVAL -$interval(date(pr_issued_date))+1 DAY) as time,\n avg(coding_time) as 'Coding Time(h)'\nFROM _prs\nGROUP BY 1\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "PR Coding Time", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "PR: Opened" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PR: Merged" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "super-light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 33 + }, + "id": 117, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _prs as(\n SELECT\n pr.id,\n pr.created_date as pr_issued_date,\n -- convert null to 0 if a PR has no pickup_time to make sure cycle_time equals the sum of the four sub-metrics\n\t\tcoalesce(prm.pr_pickup_time/60,0) as pickup_time\n FROM pull_requests pr\n left join project_pr_metrics prm on pr.id = prm.id\n join project_mapping pm on pr.base_repo_id = pm.row_id\n WHERE\n $__timeFilter(pr.created_date)\n and pr.created_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\n and pm.project_name in ($project)\n GROUP BY 1,2,3\n)\n\nSELECT \n DATE_ADD(date(pr_issued_date), INTERVAL -$interval(date(pr_issued_date))+1 DAY) as time,\n avg(pickup_time) as 'Pickup Time(h)'\nFROM _prs\nGROUP BY 1\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "PR Pickup Time", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "PR: Opened" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PR: Merged" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "super-light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 33 + }, + "id": 118, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _prs as(\n SELECT\n pr.id,\n pr.created_date as pr_issued_date,\n -- convert null to 0 if a PR has no review_time to make sure cycle_time equals the sum of the four sub-metrics\n\t\tcoalesce(prm.pr_review_time/60,0) as review_time\n FROM pull_requests pr\n left join project_pr_metrics prm on pr.id = prm.id\n join project_mapping pm on pr.base_repo_id = pm.row_id\n WHERE\n $__timeFilter(pr.created_date)\n and pr.created_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\n and pm.project_name in ($project)\n GROUP BY 1,2,3\n)\n\nSELECT \n DATE_ADD(date(pr_issued_date), INTERVAL -$interval(date(pr_issued_date))+1 DAY) as time,\n avg(review_time) as 'Review Time(h)'\nFROM _prs\nGROUP BY 1\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "PR Review Time", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "PR: Opened" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "PR: Merged" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "super-light-green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 33 + }, + "id": 119, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _prs as(\n SELECT\n pr.id,\n pr.created_date as pr_issued_date,\n -- convert null to 0 if a PR has no deploy_time to make sure cycle_time equals the sum of the four sub-metrics\n\t\tcoalesce(prm.pr_deploy_time/60,0) as deploy_time\n FROM pull_requests pr\n left join project_pr_metrics prm on pr.id = prm.id\n join project_mapping pm on pr.base_repo_id = pm.row_id\n WHERE\n $__timeFilter(pr.created_date)\n and pr.created_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\n and pm.project_name in ($project)\n GROUP BY 1,2,3\n)\n\nSELECT \n DATE_ADD(date(pr_issued_date), INTERVAL -$interval(date(pr_issued_date))+1 DAY) as time,\n avg(deploy_time) as 'PR Deploy Time(h)'\nFROM _prs\nGROUP BY 1\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "PR Deploy Time", + "type": "timeseries" + }, + { + "datasource": null, + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 40 + }, + "id": 113, + "options": { + "content": "
\n\nThis dashboard is created based on this [data schema](https://devlake.apache.org/docs/DataModels/DevLakeDomainLayerSchema). Want to add more metrics? Please follow the [guide](https://devlake.apache.org/docs/Configuration/Dashboards/GrafanaUserGuide).", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + } + ], + "refresh": "", + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "mysql", + "definition": "select distinct name from projects", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Project", + "multi": true, + "name": "project", + "options": [], + "query": "select distinct name from projects", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "allValue": "", + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": "mysql", + "definition": "select distinct priority from issues where priority != ''", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "P0+P1 Priority", + "multi": true, + "name": "priority", + "options": [], + "query": "select distinct priority from issues where priority != ''", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "allValue": null, + "current": { + "selected": false, + "text": "Month", + "value": "DAYOFMONTH" + }, + "description": "", + "error": null, + "hide": 0, + "includeAll": false, + "label": "Time Interval", + "multi": false, + "name": "interval", + "options": [ + { + "selected": true, + "text": "Month", + "value": "DAYOFMONTH" + }, + { + "selected": false, + "text": "Week", + "value": "WEEKDAY" + } + ], + "query": "Month : DAYOFMONTH, Week : WEEKDAY", + "queryValue": "", + "skipUrlSync": false, + "type": "custom" + } + ] + }, + "time": { + "from": "now-6M", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Engineering Throughput and Cycle Time", + "uid": "Jaaimc67k", + "version": 3 +} \ No newline at end of file diff --git a/charts/devlake/dashboards/EngineeringThroughputAndCycleTimeTeamView.json b/charts/devlake/dashboards/EngineeringThroughputAndCycleTimeTeamView.json new file mode 100644 index 0000000..dad862b --- /dev/null +++ b/charts/devlake/dashboards/EngineeringThroughputAndCycleTimeTeamView.json @@ -0,0 +1,2782 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 7, + "iteration": 1682062968493, + "links": [], + "panels": [ + { + "datasource": null, + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 142, + "options": { + "content": "- Use Cases: This dashboard shows the engineering throughput and and cycle time, which helps to identify productivity and bottlenecks of the development process.\n- Data Source Required: GitHub and Jira([transformation](https://devlake.apache.org/docs/UserManuals/ConfigUI/Jira#step-3---adding-transformation-rules-optional) required to tell DevLake what the story_points field is). You also need to do [team configuration](https://devlake.apache.org/docs/Configuration/TeamConfiguration) to use this dashboard.", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "title": "Dashboard Introduction", + "type": "text" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 3 + }, + "id": 89, + "panels": [], + "title": "1. Total and Avg PRs Opened/Merged", + "type": "row" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "custom": { + "axisLabel": "Pull Request Count", + "axisPlacement": "auto", + "barAlignment": 1, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Team1: Total PR Opened" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Team2: Total PR Opened" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 4 + }, + "id": 111, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _prs as(\n SELECT\n pr.id,\n pr.url,\n pr.created_date,\n pr.merged_date,\n pr.author_id,\n u.id as user_id,\n u.name as user_name,\n t.id as team_id,\n t.name as team\n FROM pull_requests pr\n join user_accounts ua on pr.author_id = ua.account_id\n join users u on ua.user_id = u.id\n join team_users tu on u.id = tu.user_id\n join teams t on tu.team_id = t.id\n join project_mapping pm on pr.base_repo_id = pm.row_id\n WHERE\n $__timeFilter(pr.created_date)\n and pm.project_name in ($project)\n)\n\nSELECT\n DATE_ADD(date(created_date), INTERVAL -$interval(date(created_date))+1 DAY) as time,\n count(distinct case when team_id in ($team1) then id else null end) as \"Team1: Total PR Opened\",\n count(distinct case when team_id in ($team2) then id else null end) as \"Team2: Total PR Opened\"\nFROM _prs\nGROUP BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Total PRs Opened", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "custom": { + "axisLabel": "Pull Request Count", + "axisPlacement": "auto", + "barAlignment": 1, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Team1: PR Opened per Member" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Team2: PR Opened per Member" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 4 + }, + "id": 110, + "options": { + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _prs as(\n SELECT\n pr.id,\n pr.url,\n pr.created_date,\n pr.merged_date,\n pr.author_id,\n u.id as user_id,\n u.name as user_name,\n t.id as team_id,\n t.name as team\n FROM pull_requests pr\n join project_mapping pm on pr.base_repo_id = pm.row_id\n join user_accounts ua on pr.author_id = ua.account_id\n join users u on ua.user_id = u.id\n join team_users tu on u.id = tu.user_id\n join teams t on tu.team_id = t.id\n WHERE\n $__timeFilter(pr.created_date)\n and pm.project_name in ($project)\n)\n\nSELECT\n DATE_ADD(date(created_date), INTERVAL -$interval(date(created_date))+1 DAY) as time,\n count(distinct case when team_id in ($team1) then id else null end)/(select count(distinct user_id) from team_users where team_id in ($team1)) as \"Team1: PR Opened per Member\",\n count(distinct case when team_id in ($team2) then id else null end)/(select count(distinct user_id) from team_users where team_id in ($team2)) as \"Team2: PR Opened per Member\",\n count(distinct id)/(select count(*) from users) as \"Org: PR Opened per Member\"\nFROM _prs\nGROUP BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "PRs Opened per Member", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "custom": { + "axisLabel": "Pull Request Count", + "axisPlacement": "auto", + "barAlignment": 1, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Team1: Total PR Merged" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Team2: Total PR Merged" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 11 + }, + "id": 79, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _prs as(\n SELECT\n pr.id,\n pr.url,\n pr.created_date,\n pr.merged_date,\n pr.author_id,\n u.id as user_id,\n u.name as user_name,\n t.id as team_id,\n t.name as team\n FROM pull_requests pr\n join project_mapping pm on pr.base_repo_id = pm.row_id\n join user_accounts ua on pr.author_id = ua.account_id\n join users u on ua.user_id = u.id\n join team_users tu on u.id = tu.user_id\n join teams t on tu.team_id = t.id\n WHERE\n $__timeFilter(pr.created_date)\n and pm.project_name in ($project)\n)\n\nSELECT\n DATE_ADD(date(created_date), INTERVAL -$interval(date(created_date))+1 DAY) as time,\n count(distinct case \n when team_id in ($team1) and merged_date is not null then id \n when team_id in ($team1) and merged_date is null then null end) as \"Team1: Total PR Merged\",\n count(distinct case \n when team_id in ($team2) and merged_date is not null then id \n when team_id in ($team2) and merged_date is null then null end) as \"Team2: Total PR Merged\"\nFROM _prs\nGROUP BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Total PRs Merged", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "custom": { + "axisLabel": "Pull Request Count", + "axisPlacement": "auto", + "barAlignment": 1, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Team1: PR Merged per Member" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Team2: PR Merged per Member" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 11 + }, + "id": 112, + "options": { + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _prs as(\n SELECT\n pr.id,\n pr.url,\n pr.created_date,\n pr.merged_date,\n pr.author_id,\n u.id as user_id,\n u.name as user_name,\n t.id as team_id,\n t.name as team\n FROM pull_requests pr\n join project_mapping pm on pr.base_repo_id = pm.row_id\n join user_accounts ua on pr.author_id = ua.account_id\n join users u on ua.user_id = u.id\n join team_users tu on u.id = tu.user_id\n join teams t on tu.team_id = t.id\n WHERE\n $__timeFilter(pr.created_date)\n and pm.project_name in ($project)\n)\n\nSELECT\n DATE_ADD(date(created_date), INTERVAL -$interval(date(created_date))+1 DAY) as time,\n count(distinct case \n when team_id in ($team1) and merged_date is not null then id \n when team_id in ($team1) and merged_date is null then null end)/(select count(distinct user_id) from team_users where team_id in ($team1)) as \"Team1: PR Merged per Member\",\n count(distinct case \n when team_id in ($team2) and merged_date is not null then id\n when team_id in ($team2) and merged_date is null then null end)/(select count(distinct user_id) from team_users where team_id in ($team2)) as \"Team2: PR Merged per Member\",\n count(distinct case when merged_date is not null then id end)/(select count(*) from users) as \"Org: PR Merged per Member\"\nFROM _prs\nGROUP BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "PRs Merged per Member", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 18 + }, + "id": 114, + "panels": [], + "title": "2. Issue Completed", + "type": "row" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Issue Count", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Team1: Issues Completed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Team2: Issues Completed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 19 + }, + "id": 74, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _issues as(\n SELECT\n i.id,\n i.url,\n i.created_date,\n i.status,\n i.assignee_id,\n i.story_point,\n i.priority,\n u.id as user_id,\n u.name as user_name,\n t.id as team_id,\n t.name as team\n FROM issues i\n\t join board_issues bi on i.id = bi.issue_id\n\t join boards b on bi.board_id = b.id\n\t join project_mapping pm on b.id = pm.row_id\n \tjoin user_accounts ua on i.assignee_id = ua.account_id\n join users u on ua.user_id = u.id\n join team_users tu on u.id = tu.user_id\n join teams t on tu.team_id = t.id\n WHERE\n $__timeFilter(i.created_date)\n and pm.project_name in ($project)\n)\n\nSELECT\n DATE_ADD(date(created_date), INTERVAL -$interval(date(created_date))+1 DAY) as time,\n -- count(i.id) as 'Issues Opened',\n count(case when status = 'DONE' and team_id in ($team1) then id else null end) as 'Team1: Issues Completed',\n count(case when status = 'DONE' and team_id in ($team2) then id else null end) as 'Team2: Issues Completed'\nFROM _issues\nGROUP BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Total Issue Completed", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Issue Count", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Team1: Issues Completed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Team2: Issues Completed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 19 + }, + "id": 115, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _issues as(\n SELECT\n i.id,\n i.url,\n i.created_date,\n i.status,\n i.assignee_id,\n i.story_point,\n i.priority,\n u.id as user_id,\n u.name as user_name,\n t.id as team_id,\n t.name as team\n FROM issues i\n\t join board_issues bi on i.id = bi.issue_id\n\t join boards b on bi.board_id = b.id\n\t join project_mapping pm on b.id = pm.row_id\n \tjoin user_accounts ua on i.assignee_id = ua.account_id\n join users u on ua.user_id = u.id\n join team_users tu on u.id = tu.user_id\n join teams t on tu.team_id = t.id\n WHERE\n $__timeFilter(i.created_date)\n and pm.project_name in ($project)\n)\n\nSELECT\n DATE_ADD(date(created_date), INTERVAL -$interval(date(created_date))+1 DAY) as time,\n count(case when status = 'DONE' and team_id in ($team1) then id else null end)/(select count(distinct user_id) from team_users where team_id in ($team1)) as 'Team1: Issues Completed per Member',\n count(case when status = 'DONE' and team_id in ($team2) then id else null end)/(select count(distinct user_id) from team_users where team_id in ($team2)) as 'Team2: Issues Completed per Member',\n count(distinct id)/(select count(*) from users) as \"Org: Issues Completed per Member\"\nFROM _issues\nGROUP BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Issue Completed per Member", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 26 + }, + "id": 126, + "panels": [], + "title": "3. Story Points Completed", + "type": "row" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Issue Count", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Team1: Story Points Completed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Team2: Story Points Completed" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 27 + }, + "id": 116, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _issues as(\n SELECT\n i.id,\n i.url,\n i.created_date,\n i.status,\n i.assignee_id,\n i.story_point,\n i.priority,\n u.id as user_id,\n u.name as user_name,\n t.id as team_id,\n t.name as team\n FROM issues i\n\t join board_issues bi on i.id = bi.issue_id\n\t join boards b on bi.board_id = b.id\n\t join project_mapping pm on b.id = pm.row_id\n \tjoin user_accounts ua on i.assignee_id = ua.account_id\n join users u on ua.user_id = u.id\n join team_users tu on u.id = tu.user_id\n join teams t on tu.team_id = t.id\n WHERE\n $__timeFilter(i.created_date)\n and pm.project_name in ($project)\n)\n\nSELECT\n DATE_ADD(date(created_date), INTERVAL -$interval(date(created_date))+1 DAY) as time,\n -- count(i.id) as 'Issues Opened',\n sum(case when status = 'DONE' and team_id in ($team1) then story_point else 0 end) as 'Team1: Story Points Completed',\n sum(case when status = 'DONE' and team_id in ($team2) then story_point else 0 end) as 'Team2: Story Points Completed'\nFROM _issues\nGROUP BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Total Story Points Completed", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Issue Count", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Team1: Story Points Completed per Member" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Team2: Story Points Completed per Member" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 27 + }, + "id": 117, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _issues as(\n SELECT\n i.id,\n i.url,\n i.created_date,\n i.status,\n i.assignee_id,\n i.story_point,\n i.priority,\n u.id as user_id,\n u.name as user_name,\n t.id as team_id,\n t.name as team\n FROM issues i\n\t join board_issues bi on i.id = bi.issue_id\n\t join boards b on bi.board_id = b.id\n\t join project_mapping pm on b.id = pm.row_id\n \tjoin user_accounts ua on i.assignee_id = ua.account_id\n join users u on ua.user_id = u.id\n join team_users tu on u.id = tu.user_id\n join teams t on tu.team_id = t.id\n WHERE\n $__timeFilter(i.created_date)\n and pm.project_name in ($project)\n)\n\nSELECT\n DATE_ADD(date(created_date), INTERVAL -$interval(date(created_date))+1 DAY) as time,\n sum(case when status = 'DONE' and team_id in ($team1) then story_point else 0 end)/(select count(distinct user_id) from team_users where team_id in ($team1)) as 'Team1: Story Points Completed per Member',\n sum(case when status = 'DONE' and team_id in ($team2) then story_point else 0 end)/(select count(distinct user_id) from team_users where team_id in ($team2)) as 'Team2: Story Points Completed per Member',\n count(distinct id)/(select count(*) FROM users) as \"Org: Story Points Completed per Member\"\nFROM _issues\nGROUP BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Story Points Completed per Member", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 34 + }, + "id": 124, + "panels": [], + "title": "4. PR Review Depth and PR Size", + "type": "row" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "custom": { + "axisLabel": "Pull Request Count", + "axisPlacement": "auto", + "barAlignment": 1, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Team1: PR Review Depth" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Team2: PR Review Depth" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 35 + }, + "id": 122, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _merged_prs as(\n SELECT\n pr.id,\n pr.url,\n pr.created_date,\n pr.merged_date,\n pr.author_id,\n prc.id as comment_id,\n u.id as user_id,\n u.name as user_name,\n t.id as team_id,\n t.name as team\n FROM pull_requests pr\n join project_mapping pm on pr.base_repo_id = pm.row_id\n left join pull_request_comments prc on pr.id = prc.pull_request_id\n join user_accounts ua on pr.author_id = ua.account_id\n join users u on ua.user_id = u.id\n join team_users tu on u.id = tu.user_id\n join teams t on tu.team_id = t.id\n WHERE\n $__timeFilter(pr.created_date)\n and pm.project_name in ($project)\n and pr.merged_date is not null\n)\n\nselect\n DATE_ADD(date(created_date), INTERVAL -$interval(date(created_date))+1 DAY) as time,\n count(distinct case when team_id in ($team1) then comment_id else null end)/(select count(distinct user_id) from team_users where team_id in ($team1)) as \"Team1: PR Review Depth\",\n count(distinct case when team_id in ($team2) then comment_id else null end)/(select count(distinct user_id) from team_users where team_id in ($team2)) as \"Team2: PR Review Depth\",\n count(distinct comment_id)/(select count(*) FROM users) as \"Org: PR Review Depth\"\nFROM _merged_prs\nGROUP BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": " Average PR Review Depth per Team", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "custom": { + "axisLabel": "Pull Request Count", + "axisPlacement": "auto", + "barAlignment": 1, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Team1: PR Size" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Team2: PR Size" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 35 + }, + "id": 127, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _prs as(\n SELECT\n pr.id,\n pr.url,\n pr.created_date,\n pr.merged_date,\n pr.author_id,\n prc.commit_sha,\n c.additions + c.deletions as loc,\n u.id as user_id,\n u.name as user_name,\n t.id as team_id,\n t.name as team\n FROM pull_requests pr\n join project_mapping pm on pr.base_repo_id = pm.row_id\n left join pull_request_commits prc on pr.id = prc.pull_request_id\n left join commits c on prc.commit_sha = c.sha\n join user_accounts ua on pr.author_id = ua.account_id\n join users u on ua.user_id = u.id\n join team_users tu on u.id = tu.user_id\n join teams t on tu.team_id = t.id\n WHERE\n $__timeFilter(pr.created_date)\n and pm.project_name in ($project)\n)\n\nselect\n DATE_ADD(date(created_date), INTERVAL -$interval(date(created_date))+1 DAY) as time,\n sum(case when team_id in ($team1) then loc else null end)/(select count(distinct user_id) from team_users where team_id in ($team1)) as \"Team1: PR Size\",\n sum(case when team_id in ($team2) then loc else null end)/(select count(distinct user_id) from team_users where team_id in ($team2)) as \"Team2: PR Size\",\n sum(loc)/(select count(*) FROM users) as \"Org: PR Size\"\nFROM _prs\nGROUP BY 1\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": " Average PR Size by Team", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 42 + }, + "id": 119, + "panels": [], + "title": "5. P0/P1 Bugs", + "type": "row" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Bug Count", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Team1: P0/P1 Bugs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Team2: P0/P1 Bugs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 43 + }, + "id": 100, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _bugs as(\n SELECT\n i.id,\n i.url,\n i.created_date,\n i.status,\n i.assignee_id,\n i.story_point,\n i.priority,\n u.id as user_id,\n u.name as user_name,\n t.id as team_id,\n t.name as team\n FROM issues i\n\t join board_issues bi on i.id = bi.issue_id\n\t join boards b on bi.board_id = b.id\n\t join project_mapping pm on b.id = pm.row_id\n \tjoin user_accounts ua on i.assignee_id = ua.account_id\n join users u on ua.user_id = u.id\n join team_users tu on u.id = tu.user_id\n join teams t on tu.team_id = t.id\n WHERE\n $__timeFilter(i.created_date)\n and pm.project_name in ($project)\n and i.type = 'BUG'\n)\n\nSELECT\n DATE_ADD(date(created_date), INTERVAL -$interval(date(created_date))+1 DAY) as time,\n count(case when team_id in ($team1) then id else null end) as 'Team1: P0/P1 Bugs',\n count(case when team_id in ($team2) then id else null end) as 'Team2: P0/P1 Bugs'\nFROM _bugs\nWHERE\n -- please choose the priorities in the filter above\n priority in ($priority)\nGROUP BY 1\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Total P0/P1 Bugs", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Bug Count", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Team1: P0/P1 Bugs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Team2: P0/P1 Bugs" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 43 + }, + "id": 121, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _bugs as(\n SELECT\n i.id,\n i.url,\n i.created_date,\n i.status,\n i.assignee_id,\n i.story_point,\n i.priority,\n u.id as user_id,\n u.name as user_name,\n t.id as team_id,\n t.name as team\n FROM issues i\n\t join board_issues bi on i.id = bi.issue_id\n\t join boards b on bi.board_id = b.id\n\t join project_mapping pm on b.id = pm.row_id\n \tjoin user_accounts ua on i.assignee_id = ua.account_id\n join users u on ua.user_id = u.id\n join team_users tu on u.id = tu.user_id\n join teams t on tu.team_id = t.id\n WHERE\n $__timeFilter(i.created_date)\n and pm.project_name in ($project)\n and i.type = 'BUG'\n)\n\nSELECT\n DATE_ADD(date(created_date), INTERVAL -$interval(date(created_date))+1 DAY) as time,\n count(case when team_id in ($team1) then id else null end)/(select count(distinct user_id) from team_users where team_id in ($team1)) as 'Team1: P0/P1 Bugs per Member',\n count(case when team_id in ($team2) then id else null end)/(select count(distinct user_id) from team_users where team_id in ($team2)) as 'Team2: P0/P1 Bugs per Member',\n count(distinct id)/(select count(*) FROM users) as \"Org: P0/P1 Bugs per Member\"\nFROM _bugs\nWHERE\n -- please choose the priorities in the filter above\n priority in ($priority)\nGROUP BY 1\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "P0/P1 Bugs per Member", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 50 + }, + "id": 103, + "panels": [], + "title": "6. Cycle Time", + "type": "row" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Team1: Avg Cycle Time(h)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Team2: Avg Cycle Time(h)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 51 + }, + "id": 136, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _prs as(\n SELECT\n pr.id,\n pr.created_date as pr_issued_date,\n -- convert null to 0 if a PR has no cycle_time to make sure cycle_time equals the sum of the four metrics below\n\t\tcoalesce(prm.pr_cycle_time/60,0) as cycle_time,\n\t\tpr.author_id,\n u.id as user_id,\n u.name as user_name,\n t.id as team_id,\n t.name as team\n FROM pull_requests pr\n join project_mapping pm on pr.base_repo_id = pm.row_id\n\t\tleft join project_pr_metrics prm on pr.id = prm.id\n left join user_accounts ua on pr.author_id = ua.account_id\n left join users u on ua.user_id = u.id\n left join team_users tu on u.id = tu.user_id\n left join teams t on tu.team_id = t.id\n WHERE\n $__timeFilter(pr.created_date)\n and pm.project_name in ($project)\n GROUP BY 1,2,3,4,5,6,7,8\n)\n\nSELECT \n DATE_ADD(date(pr_issued_date), INTERVAL -$interval(date(pr_issued_date))+1 DAY) as time,\n avg(case when team_id in ($team1) then cycle_time end) as 'Team1: Avg Cycle Time(h)',\n avg(case when team_id in ($team2) then cycle_time end) as 'Team2: Avg Cycle Time(h)'\nFROM _prs\nGROUP BY 1\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Total Cycle Time(h)", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Team1: Avg Coding Time(h)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Team2: Avg Coding Time(h)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 58 + }, + "id": 140, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _prs as(\n SELECT\n pr.id,\n pr.created_date as pr_issued_date,\n -- convert null to 0 if a PR has no coding_time to make sure cycle_time equals the sum of the four sub-metrics\n\t\tcoalesce(prm.pr_coding_time/60,0) as coding_time,\n\t\tpr.author_id,\n u.id as user_id,\n u.name as user_name,\n t.id as team_id,\n t.name as team\n FROM pull_requests pr\n join project_mapping pm on pr.base_repo_id = pm.row_id\n\t\tleft join project_pr_metrics prm on pr.id = prm.id\n left join user_accounts ua on pr.author_id = ua.account_id\n left join users u on ua.user_id = u.id\n left join team_users tu on u.id = tu.user_id\n left join teams t on tu.team_id = t.id\n WHERE\n $__timeFilter(pr.created_date)\n and pm.project_name in ($project)\n GROUP BY 1,2,3,4,5,6,7,8\n)\n\nSELECT \n DATE_ADD(date(pr_issued_date), INTERVAL -$interval(date(pr_issued_date))+1 DAY) as time,\n avg(case when team_id in ($team1) then coding_time end) as 'Team1: Avg Coding Time(h)',\n avg(case when team_id in ($team2) then coding_time end) as 'Team2: Avg Coding Time(h)'\nFROM _prs\nGROUP BY 1\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "PR Coding Time(h)", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Team1: Avg Pickup Time(h)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Team2: Avg Pickup Time(h)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 6, + "y": 58 + }, + "id": 134, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _prs as(\n SELECT\n pr.id,\n pr.created_date as pr_issued_date,\n -- convert null to 0 if a PR has no pickup_time to make sure cycle_time equals the sum of the four sub-metrics\n\t\tcoalesce(prm.pr_pickup_time/60,0) as pickup_time,\n\t\tpr.author_id,\n u.id as user_id,\n u.name as user_name,\n t.id as team_id,\n t.name as team\n FROM pull_requests pr\n join project_mapping pm on pr.base_repo_id = pm.row_id\n\t\tleft join project_pr_metrics prm on pr.id = prm.id\n left join user_accounts ua on pr.author_id = ua.account_id\n left join users u on ua.user_id = u.id\n left join team_users tu on u.id = tu.user_id\n left join teams t on tu.team_id = t.id\n WHERE\n $__timeFilter(pr.created_date)\n and pm.project_name in ($project)\n GROUP BY 1,2,3,4,5,6,7,8\n)\n\nSELECT \n DATE_ADD(date(pr_issued_date), INTERVAL -$interval(date(pr_issued_date))+1 DAY) as time,\n avg(case when team_id in ($team1) then pickup_time end) as 'Team1: Avg Pickup Time(h)',\n avg(case when team_id in ($team2) then pickup_time end) as 'Team2: Avg Pickup Time(h)'\nFROM _prs\nGROUP BY 1\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "PR Pickup Time(h)", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Team1: Avg Review Time(h)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Team2: Avg Review Time(h)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 58 + }, + "id": 135, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _prs as(\n SELECT\n pr.id,\n pr.created_date as pr_issued_date,\n -- convert null to 0 if a PR has no review_time to make sure cycle_time equals the sum of the four sub-metrics\n\t\tcoalesce(prm.pr_review_time/60,0) as review_time,\n\t\tpr.author_id,\n u.id as user_id,\n u.name as user_name,\n t.id as team_id,\n t.name as team\n FROM pull_requests pr\n join project_mapping pm on pr.base_repo_id = pm.row_id\n\t\tleft join project_pr_metrics prm on pr.id = prm.id\n left join user_accounts ua on pr.author_id = ua.account_id\n left join users u on ua.user_id = u.id\n left join team_users tu on u.id = tu.user_id\n left join teams t on tu.team_id = t.id\n WHERE\n $__timeFilter(pr.created_date)\n and pm.project_name in ($project)\n GROUP BY 1,2,3,4,5,6,7,8\n)\n\nSELECT \n DATE_ADD(date(pr_issued_date), INTERVAL -$interval(date(pr_issued_date))+1 DAY) as time,\n avg(case when team_id in ($team1) then review_time end) as 'Team1: Avg Review Time(h)',\n avg(case when team_id in ($team2) then review_time end) as 'Team2: Avg Review Time(h)'\nFROM _prs\nGROUP BY 1\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "PR Review Time(h)", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Team1: Avg Review Time(h)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Team2: Avg Review Time(h)" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 58 + }, + "id": 145, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _prs as(\n SELECT\n pr.id,\n pr.created_date as pr_issued_date,\n -- convert null to 0 if a PR has no deploy_time to make sure cycle_time equals the sum of the four sub-metrics\n\t\tcoalesce(prm.pr_deploy_time/60,0) as deploy_time,\n\t\tpr.author_id,\n u.id as user_id,\n u.name as user_name,\n t.id as team_id,\n t.name as team\n FROM pull_requests pr\n join project_mapping pm on pr.base_repo_id = pm.row_id\n\t\tleft join project_pr_metrics prm on pr.id = prm.id\n left join user_accounts ua on pr.author_id = ua.account_id\n left join users u on ua.user_id = u.id\n left join team_users tu on u.id = tu.user_id\n left join teams t on tu.team_id = t.id\n WHERE\n $__timeFilter(pr.created_date)\n and pm.project_name in ($project)\n GROUP BY 1,2,3,4,5,6,7,8\n)\n\nSELECT \n DATE_ADD(date(pr_issued_date), INTERVAL -$interval(date(pr_issued_date))+1 DAY) as time,\n avg(case when team_id in ($team1) then deploy_time end) as 'Team1: Avg Deploy Time(h)',\n avg(case when team_id in ($team2) then deploy_time end) as 'Team2: Avg Deploy Time(h)'\nFROM _prs\nGROUP BY 1\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "PR Deploy Time(h)", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 65 + }, + "id": 139, + "panels": [], + "title": "7. PRs Merged w/o Review", + "type": "row" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Team1: PRs Merged w/o Review" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Team2: PRs Merged w/o Review" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 66 + }, + "id": 108, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _merged_prs as(\n SELECT\n pr.id,\n pr.url,\n pr.created_date,\n pr.merged_date,\n pr.author_id,\n u.id as user_id,\n u.name as user_name,\n t.id as team_id,\n t.name as team\n FROM pull_requests pr\n join project_mapping pm on pr.base_repo_id = pm.row_id\n join user_accounts ua on pr.author_id = ua.account_id\n join users u on ua.user_id = u.id\n join team_users tu on u.id = tu.user_id\n join teams t on tu.team_id = t.id\n WHERE\n $__timeFilter(pr.created_date)\n and pm.project_name in ($project)\n and pr.merged_date is not null\n)\n\nSELECT\n DATE_ADD(date(created_date), INTERVAL -$interval(date(created_date))+1 DAY) as time,\n count(distinct case when team_id in ($team1) and id not in (SELECT pull_request_id FROM pull_request_comments) then id else null end) as \"Team1: PRs Merged w/o Review\",\n count(distinct case when team_id in ($team2) and id not in (SELECT pull_request_id FROM pull_request_comments) then id else null end) as \"Team2: PRs Merged w/o Review\"\nFROM _merged_prs\nGROUP BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "PRs Merged w/o Review", + "type": "timeseries" + }, + { + "datasource": null, + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 73 + }, + "id": 144, + "options": { + "content": "
\n\nThis dashboard is created based on this [data schema](https://devlake.apache.org/docs/DataModels/DevLakeDomainLayerSchema). Want to add more metrics? Please follow the [guide](https://devlake.apache.org/docs/Configuration/Dashboards/GrafanaUserGuide).", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + } + ], + "refresh": "", + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "mysql", + "definition": "select distinct name from projects", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Project", + "multi": true, + "name": "project", + "options": [], + "query": "select distinct name from projects", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "allValue": "", + "current": { + "isNone": true, + "selected": false, + "text": "None", + "value": "" + }, + "datasource": "mysql", + "definition": "select concat(name, '--', id) as text from teams", + "description": null, + "error": null, + "hide": 0, + "includeAll": false, + "label": "Team1", + "multi": false, + "name": "team1", + "options": [], + "query": "select concat(name, '--', id) as text from teams", + "refresh": 1, + "regex": "/^(?.*)--(?.*)$/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "allValue": "", + "current": { + "isNone": true, + "selected": false, + "text": "None", + "value": "" + }, + "datasource": "mysql", + "definition": "select concat(name, '--', id) as text from teams", + "description": null, + "error": null, + "hide": 0, + "includeAll": false, + "label": "Team2", + "multi": false, + "name": "team2", + "options": [], + "query": "select concat(name, '--', id) as text from teams", + "refresh": 1, + "regex": "/^(?.*)--(?.*)$/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "allValue": "", + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": "mysql", + "definition": "select distinct priority from issues where priority != ''", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "P0+P1 Priority", + "multi": true, + "name": "priority", + "options": [], + "query": "select distinct priority from issues where priority != ''", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "allValue": null, + "current": { + "selected": false, + "text": "Month", + "value": "DAYOFMONTH" + }, + "description": "", + "error": null, + "hide": 0, + "includeAll": false, + "label": "Time Interval", + "multi": false, + "name": "interval", + "options": [ + { + "selected": true, + "text": "Month", + "value": "DAYOFMONTH" + }, + { + "selected": false, + "text": "Week", + "value": "WEEKDAY" + } + ], + "query": "Month : DAYOFMONTH, Week : WEEKDAY", + "queryValue": "", + "skipUrlSync": false, + "type": "custom" + } + ] + }, + "time": { + "from": "now-6M", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Engineering Throughput and Cycle Time - Team View", + "uid": "nJ1ijje7k", + "version": 6 +} \ No newline at end of file diff --git a/charts/devlake/dashboards/GitHub.json b/charts/devlake/dashboards/GitHub.json new file mode 100644 index 0000000..5dd0ce3 --- /dev/null +++ b/charts/devlake/dashboards/GitHub.json @@ -0,0 +1,2003 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 26, + "iteration": 1683710488565, + "links": [], + "panels": [ + { + "datasource": null, + "gridPos": { + "h": 3, + "w": 13, + "x": 0, + "y": 0 + }, + "id": 99, + "options": { + "content": "- Use Cases: This dashboard shows the basic Git and Code Review metrics from GitHub.\n- Data Source Required: GitHub", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "title": "Dashboard Introduction", + "type": "text" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 3 + }, + "id": 89, + "panels": [], + "title": "1. User Requirements (Issues)", + "type": "row" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 7, + "x": 0, + "y": 4 + }, + "id": 62, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select \n\tcount(distinct i.id)\nfrom \n\tissues i\n\tjoin board_issues bi on i.id = bi.issue_id\n\tjoin boards b on bi.board_id = b.id\nwhere\n $__timeFilter(i.created_date)\n and b.id in ($repo_id)\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "1.1 Number of New Issues [Selected Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Issue Count", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 17, + "x": 7, + "y": 4 + }, + "id": 74, + "options": { + "barWidth": 0.5, + "groupWidth": 0.7, + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _issues as(\n SELECT\n DATE_ADD(date(i.created_date), INTERVAL -DAY(date(i.created_date))+1 DAY) as time,\n count(distinct i.id) as issue_count\n FROM issues i\n \tjoin board_issues bi on i.id = bi.issue_id\n \tjoin boards b on bi.board_id = b.id\n WHERE\n $__timeFilter(i.created_date)\n and i.created_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\n and b.id in ($repo_id)\n group by 1\n)\n\nSELECT \n date_format(time,'%M %Y') as month,\n issue_count as \"Issue Count\"\nFROM _issues\nORDER BY time\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "1.2 Number of New Issues [Each Month]", + "type": "barchart" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 87, + "panels": [], + "title": "2. How issues are handled?", + "type": "row" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 7, + "x": 0, + "y": 11 + }, + "id": 43, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select \n\tcount(distinct i.id)\nfrom \n\tissues i\n\tjoin board_issues bi on i.id = bi.issue_id\n\tjoin boards b on bi.board_id = b.id\nwhere\n $__timeFilter(i.created_date)\n and b.id in ($repo_id)\n and i.status = \"DONE\"\n\n\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "2.1 Number of Closed Issues [Issues Created in Selected Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "fixed" + }, + "custom": { + "axisLabel": "Issue Count", + "axisPlacement": "auto", + "barAlignment": 1, + "drawStyle": "bars", + "fillOpacity": 50, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "closed_issue_count" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "orange", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 6, + "w": 17, + "x": 7, + "y": 11 + }, + "id": 76, + "options": { + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n DATE_ADD(date(i.created_date), INTERVAL -DAYOFMONTH(date(i.created_date))+1 DAY) as time,\n count(distinct case when status != 'DONE' then i.id else null end) as open_issue_count,\n count(distinct case when status = 'DONE' then i.id else null end) as closed_issue_count\nFROM issues i\n\tjoin board_issues bi on i.id = bi.issue_id\n\tjoin boards b on bi.board_id = b.id\nWHERE\n $__timeFilter(i.created_date)\n and i.created_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\n and b.id in ($repo_id)\ngroup by 1\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "2.2 Number of Open and Closed Issues [Issues Created in Each Month]", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 14 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 7, + "x": 0, + "y": 17 + }, + "id": 64, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select \n\tAVG(i.lead_time_minutes/1440) issue_lead_time_in_days\nfrom \n\tissues i\n\tjoin board_issues bi on i.id = bi.issue_id\n\tjoin boards b on bi.board_id = b.id\nwhere\n $__timeFilter(i.resolution_date)\n and i.resolution_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\n and b.id in ($repo_id)\n and i.status = \"DONE\"", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "2.3 Mean Issue Lead Time in Days [Issues Closed in Selected Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 17, + "x": 7, + "y": 17 + }, + "id": 75, + "options": { + "barWidth": 0.5, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _issues as(\n SELECT\n DATE_ADD(date(i.resolution_date), INTERVAL -DAY(date(i.resolution_date))+1 DAY) as time,\n AVG(i.lead_time_minutes/1440) as issue_lead_time\n FROM issues i\n \tjoin board_issues bi on i.id = bi.issue_id\n \tjoin boards b on bi.board_id = b.id\n WHERE\n b.id in ($repo_id)\n and i.status = \"DONE\"\n and $__timeFilter(i.resolution_date)\n and i.resolution_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\n group by 1\n)\n\nSELECT \n date_format(time,'%M %Y') as month,\n issue_lead_time as \"Mean Issue Lead Time in Days\"\nFROM _issues\nORDER BY time\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "2.4 Mean Issue Lead Time in Days [Issues Closed in Each Month]", + "type": "barchart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Queue Time (Days)", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 23 + }, + "id": 93, + "options": { + "barWidth": 0.1, + "groupWidth": 0.7, + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": {}, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Get the queue time of all outstanding bugs\nwith _outstanding_issues as(\n select \n b.name as repo_name,\n i.issue_key as issue_key,\n i.title,\n i.created_date,\n (TIMESTAMPDIFF(MINUTE, i.created_date,NOW()))/1440 as queue_time_in_days,\n concat(b.url,'/',i.issue_key) as url\n from \n issues i\n left join board_issues bi on i.id = bi.issue_id\n left join boards b on bi.board_id = b.id\n where\n b.id in ($repo_id)\n and $__timeFilter(i.created_date)\n and i.status != 'DONE'\n)\n\nselect title, queue_time_in_days from _outstanding_issues\norder by 2 desc", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "2.5 Queue Time in Days [All Open Issues]", + "type": "barchart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "=avg_bug_age" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "issue_key" + }, + "properties": [ + { + "id": "custom.width", + "value": 110 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "title" + }, + "properties": [ + { + "id": "custom.width", + "value": 590 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "created_date" + }, + "properties": [ + { + "id": "custom.width", + "value": 149 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "queue_time_in_days" + }, + "properties": [ + { + "id": "custom.width", + "value": 155 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "repo_name" + }, + "properties": [ + { + "id": "custom.width", + "value": 256 + } + ] + } + ] + }, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 29 + }, + "id": 92, + "options": { + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Get the queue time of all outstanding bugs\nselect \n b.name as repo_name,\n i.issue_key as issue_key,\n i.title,\n i.created_date,\n (TIMESTAMPDIFF(MINUTE, i.created_date,NOW()))/1440 as queue_time_in_days,\n concat(b.url,'/',i.issue_key) as url\nfrom \n issues i\n left join board_issues bi on i.id = bi.issue_id\n left join boards b on bi.board_id = b.id\nwhere\n b.id in ($repo_id)\n and $__timeFilter(i.created_date)\n and i.status != 'DONE'\norder by queue_time_in_days desc", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "2.6 List of Outstanding Issues Order By Queue Time [All Open Issues]", + "type": "table" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 35 + }, + "id": 83, + "panels": [], + "title": "3. Contribution (PRs)", + "type": "row" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 36 + }, + "id": 68, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select\n\tcount(*) as pull_request_count\nfrom \n\tpull_requests pr\nwhere\n $__timeFilter(created_date)\n\tand base_repo_id in ($repo_id)\n\t\n\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "3.1 Number of New Pull Requests [Selected Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 18, + "x": 6, + "y": 36 + }, + "id": 77, + "options": { + "barWidth": 0.5, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _prs as(\n SELECT\n DATE_ADD(date(created_date), INTERVAL -DAY(date(created_date))+1 DAY) as time,\n count(*) as pr_count\n FROM pull_requests\n WHERE\n base_repo_id in ($repo_id)\n and $__timeFilter(created_date)\n and created_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\n group by 1\n)\n\nSELECT \n date_format(time,'%M %Y') as month,\n pr_count as \"Pull Request Count\"\nFROM _prs\nORDER BY time\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "3.2 Total Number of New Pull Requests [Each Month]", + "type": "barchart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Merged PR Count", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 54, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 42 + }, + "id": 59, + "options": { + "barWidth": 0.5, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "-- The PR/MR statuses are standardized to DevLake's statuses 'OPEN', 'MERGED' and 'CLOSED'. You can check out the original status from the field `original_status`\nselect\n author_name,\n\tcount(*) as merged_pull_request_count\nfrom \n\tpull_requests pr\nwhere\n $__timeFilter(created_date)\n\tand base_repo_id in ($repo_id)\n and pr.status = 'MERGED'\ngroup by 1\norder by 2 desc\nlimit 20\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "3.3 Top Contributors By Merged PRs", + "type": "barchart" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 48 + }, + "id": 85, + "panels": [], + "title": "4. How PRs are handled?", + "type": "row" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 49 + }, + "id": 66, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "-- The PR/MR statuses are standardized to DevLake's statuses 'OPEN', 'MERGED' and 'CLOSED'. You can check out the original status from the field `original_status`\nselect\n count(distinct case when status = 'MERGED' then id else null end)/count(distinct case when status in ('CLOSED', 'MERGED') then id else null end) as ratio\nfrom \n\tpull_requests pr\nwhere\n $__timeFilter(created_date)\n\tand base_repo_id in ($repo_id)", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "4.1 Ratio of Non-merging Pull Requests of All Closed PRs", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Pull Request Count", + "axisPlacement": "auto", + "barAlignment": 1, + "drawStyle": "bars", + "fillOpacity": 50, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 18, + "x": 6, + "y": 49 + }, + "id": 79, + "options": { + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "-- The PR/MR statuses are standardized to DevLake's statuses 'OPEN', 'MERGED' and 'CLOSED'. You can check out the original status from the field `original_status`\nSELECT\n DATE_ADD(date(created_date), INTERVAL -DAYOFMONTH(date(created_date))+1 DAY) as time,\n count(distinct case when status = 'OPEN' then id else null end) as \"PR: Open\",\n count(distinct case when status = 'CLOSED' then id else null end) as \"PR: Closed without merging\",\n count(distinct case when status = 'MERGED' then id else null end) as \"PR: Closed and merged\"\nFROM pull_requests\nWHERE\n $__timeFilter(created_date)\n and created_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\n and base_repo_id in ($repo_id)\ngroup by 1\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "4.2 Pull Request Status Distribution [Each Month]", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 55 + }, + "id": 80, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "-- The PR/MR statuses are standardized to DevLake's statuses 'OPEN', 'MERGED' and 'CLOSED'. You can check out the original status from the field `original_status`\nselect\n\tcount(*) as merged_pull_request_count\nfrom \n\tpull_requests pr\nwhere\n $__timeFilter(created_date)\n\tand base_repo_id in ($repo_id)\n\tand pr.status = 'CLOSED'", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "4.3 Number of Pull Requests Closed without Merging [Selected Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Ratio", + "axisPlacement": "auto", + "barAlignment": 1, + "drawStyle": "line", + "fillOpacity": 1, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 15, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 18, + "x": 6, + "y": 55 + }, + "id": 81, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "-- The PR/MR statuses are standardized to DevLake's statuses 'OPEN', 'MERGED' and 'CLOSED'. You can check out the original status from the field `original_status`\nSELECT\n DATE_ADD(date(created_date), INTERVAL -DAYOFMONTH(date(created_date))+1 DAY) as time,\n count(distinct case when status = 'CLOSED' then id else null end)/count(distinct case when status in ('CLOSED', 'MERGED') then id else null end) as ratio\nFROM pull_requests\nWHERE\n $__timeFilter(created_date)\n and base_repo_id in ($repo_id)\ngroup by 1\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "4.4 Ratio of Non-merging Pull Requests of All Closed PRs [Each Month]", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 61 + }, + "id": 72, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select\n\tavg(TIMESTAMPDIFF(Minute,created_date,merged_date)/1440)\nfrom \n\tpull_requests\nwhere \n $__timeFilter(created_date)\n\tand base_repo_id in ($repo_id)\n\tand merged_date is not null\n\n\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "4.5 Mean Time to Merge of Pull Requests in Days [Selected Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 18, + "x": 6, + "y": 61 + }, + "id": 95, + "options": { + "barWidth": 0.5, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _prs as(\n SELECT\n DATE_ADD(date(created_date), INTERVAL -DAY(date(created_date))+1 DAY) as time,\n avg(TIMESTAMPDIFF(Minute,created_date,merged_date)/1440) as time_to_merge\n FROM pull_requests\n WHERE\n $__timeFilter(created_date)\n and created_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\n and base_repo_id in ($repo_id)\n group by 1\n)\n\nSELECT \n date_format(time,'%M %Y') as month,\n time_to_merge as \"Time to Merge\"\nFROM _prs\nORDER BY time\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "4.6 Mean Time to Merge of Pull Requests in Days [Each Month]", + "type": "barchart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 67 + }, + "id": 96, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select\n\tavg(TIMESTAMPDIFF(Minute,created_date,closed_date)/1440) as time_to_close\nfrom \n\tpull_requests\nwhere \n $__timeFilter(created_date)\n\tand base_repo_id in ($repo_id)\n\tand status in ('CLOSED', 'MERGED')\n\n\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "4.7 Mean Time to Close of Pull Requests in Days [Selected Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 18, + "x": 6, + "y": 67 + }, + "id": 97, + "options": { + "barWidth": 0.5, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _prs as(\n SELECT\n DATE_ADD(date(created_date), INTERVAL -DAY(date(created_date))+1 DAY) as time,\n avg(TIMESTAMPDIFF(Minute,created_date,closed_date)/1440) as time_to_close\n FROM pull_requests\n WHERE\n $__timeFilter(created_date)\n and created_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\n and base_repo_id in ($repo_id)\n and status in ('CLOSED', 'MERGED')\n group by 1\n)\n\nSELECT \n date_format(time,'%M %Y') as month,\n time_to_close as \"Time to Close\"\nFROM _prs\nORDER BY time\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "4.8 Mean Time to Close of Pull Requests in Days [Each Month]", + "type": "barchart" + }, + { + "datasource": null, + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 73 + }, + "id": 101, + "options": { + "content": "
\n\nThis dashboard is created based on this [data schema](https://devlake.apache.org/docs/DataModels/DevLakeDomainLayerSchema). Want to add more metrics? Please follow the [guide](https://devlake.apache.org/docs/Configuration/Dashboards/GrafanaUserGuide).", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + } + ], + "refresh": "", + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": "", + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": "mysql", + "definition": "select concat(name, '--', id) as text from repos where id like 'github%'", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Repo", + "multi": true, + "name": "repo_id", + "options": [], + "query": "select concat(name, '--', id) as text from repos where id like 'github%'", + "refresh": 1, + "regex": "/^(?.*)--(?.*)$/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-6M", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "GitHub", + "uid": "KXWvOFQnz", + "version": 10 +} \ No newline at end of file diff --git a/charts/devlake/dashboards/GithubReleaseQualityAndContributionAnalysis.json b/charts/devlake/dashboards/GithubReleaseQualityAndContributionAnalysis.json new file mode 100644 index 0000000..aa8b9bc --- /dev/null +++ b/charts/devlake/dashboards/GithubReleaseQualityAndContributionAnalysis.json @@ -0,0 +1,2650 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 22, + "iteration": 1682062991983, + "links": [], + "panels": [ + { + "datasource": null, + "gridPos": { + "h": 3, + "w": 13, + "x": 0, + "y": 0 + }, + "id": 57, + "options": { + "content": "- Use Cases: This dashboard can be used to track bugs.\n- Data Source Required: GitHub ([transformation](https://devlake.apache.org/docs/UserManuals/ConfigUI/GitHub#step-3---adding-transformation-rules-optional) required. Additional settings are required to get version data).", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "title": "Dashboard Introduction", + "type": "text" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 3 + }, + "id": 45, + "panels": [], + "title": "Quality", + "type": "row" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [], + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 7, + "x": 0, + "y": 4 + }, + "id": 15, + "options": { + "displayLabels": [ + "name", + "percent" + ], + "legend": { + "displayMode": "table", + "placement": "right", + "values": [ + "percent", + "value" + ] + }, + "pieType": "donut", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": true + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Get the bug distribution in major versions\nwith bugs_in_each_tag as(\n\tselect \n\t\tSUBSTRING_INDEX(rid.new_ref_id,'refs/tags/', -1) as tag_name, \n\t\tSUBSTRING_INDEX(rid.new_ref_id,':', 4) as repo_id,\n\t\ti.issue_key, i.type, i.title, i.description\n\tfrom\n\t\trefs_issues_diffs rid\n\t\tleft join issues i on rid.issue_id = i.id\n\twhere\n\t\tSUBSTRING_INDEX(rid.new_ref_id,':', 4) in ($repo_id)\n\t\tand i.type = 'BUG'\n)\n\n\nSELECT \n\tconcat(SUBSTRING_INDEX(biet.tag_name,'.',3), '.x') as minor_version,\n\tcount(*) as bug_count\nFROM \n\tbugs_in_each_tag biet\nGROUP BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "1. Bug Distribution [Minor Versions]", + "type": "piechart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Bug Count", + "axisPlacement": "left", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 2 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "cost_percentage(bugfixing commits/total commits)" + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + { + "id": "custom.axisLabel", + "value": "Cost Percentage(%)" + }, + { + "id": "custom.axisPlacement", + "value": "right" + }, + { + "id": "unit", + "value": "percentunit" + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 17, + "x": 7, + "y": 4 + }, + "id": 29, + "options": { + "barWidth": 0.7, + "groupWidth": 0.3, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Get the number of fixed bugs in the last 5 tags\nwith refs_commits_diffs as(\n SELECT\n new_refs.id as new_ref_id, old_refs.id as old_ref_id, commits_diffs.commit_sha, new_commit_sha, old_commit_sha\n FROM\n commits_diffs\n LEFT JOIN refs new_refs on new_refs.commit_sha = commits_diffs.new_commit_sha\n LEFT JOIN refs old_refs on old_refs.commit_sha = commits_diffs.old_commit_sha\n),\n\n_last_5_tags as(\n SELECT \n distinct SUBSTRING_INDEX(new_ref_id,':', -1) as new_ref_id, SUBSTRING_INDEX(old_ref_id,':', -1) as old_ref_id\n -- distinct new_ref_id, old_ref_id\n FROM \n refs_commits_diffs\n WHERE\n\t\tSUBSTRING_INDEX(new_ref_id,':', 4) in ($repo_id)\n\tORDER BY 1 desc\n\tLIMIT 5\n),\n\n_bugs_of_tags as(\n\tselect \n\t\tSUBSTRING_INDEX(rid.new_ref_id,'tags/', -1) as tag_name, \n\t\t-- SUBSTRING_INDEX(rid.new_ref_id,':', 3) as repo_id,\n\t\tcount(*) as bug_count\n\tfrom\n\t\trefs_issues_diffs rid\n\t\tleft join issues i on rid.issue_id = i.id\n\twhere\n\t\tSUBSTRING_INDEX(rid.new_ref_id,':', 4) in ($repo_id)\n\t\t-- and rid.new_ref_id in (SELECT new_ref_id FROM _last_5_tags)\n\t\tand SUBSTRING_INDEX(rid.new_ref_id,':', -1) in (SELECT new_ref_id FROM _last_5_tags)\n\t\tand i.type = 'BUG'\n\t-- GROUP BY 1,2\n\t GROUP BY 1\n),\n\n_combine_pr as (\n select pull_request_id as id, commit_sha from pull_request_commits left join pull_requests p on pull_request_commits.pull_request_id = p.id\n where p.base_repo_id in ($repo_id)\n union\n select id, merge_commit_sha as commit_sha from pull_requests where base_repo_id in ($repo_id)\n),\n\n_commit_count_of_pr as(\n select\n SUBSTRING_INDEX(rcd.new_ref_id,'tags/', -1) as tag_name, \n\t\tSUBSTRING_INDEX(rcd.new_ref_id,':', 4) as repo_id,\n pr.id as pull_request_id,\n count(c.sha) as commit_count\n FROM \n refs_commits_diffs rcd\n\t\tleft join commits c on rcd.commit_sha = c.sha\n\t\t-- left join pull_request_commits prc on c.sha = prc.commit_sha\n\t\tleft join _combine_pr pr on c.sha = pr.commit_sha\n\twhere\n\t\tSUBSTRING_INDEX(rcd.new_ref_id,':', 4) in ($repo_id)\n\t\t-- and rcd.new_ref_id in (SELECT new_ref_id FROM _last_5_tags)\n\t\tand SUBSTRING_INDEX(rcd.new_ref_id,':', -1) in (SELECT SUBSTRING_INDEX(new_ref_id,':', -1) FROM _last_5_tags)\n\tgroup by 1,2,3\n),\n\n_pr_worktype as(\n select\n distinct pri.pull_request_id,i.type\n from\n pull_request_issues pri\n left join pull_requests pr on pri.pull_request_id = pr.id\n left join issues i on pri.issue_id = i.id\n where \n i.issue_key != 0\n),\n\n_pr_elco_and_worktype as(\n select\n ccop.tag_name, \n sum(case when pw.type = 'BUG' then commit_count else 0 end)/sum(commit_count) as cost_percentage\n from \n _commit_count_of_pr ccop\n left join _pr_worktype pw on ccop.pull_request_id = pw.pull_request_id\n GROUP BY 1\n)\n\nSELECT \n\tbot.tag_name,\n\tbot.bug_count,\n\tpeaw.cost_percentage as \"cost_percentage(bugfixing commits/total commits)\"\nFROM \n\t_bugs_of_tags bot\n\tjoin _pr_elco_and_worktype peaw on bot.tag_name = peaw.tag_name\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "2.1 Ratio of Bug Fix Commits [Last 5 Tags]", + "type": "barchart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 11 + }, + "id": 55, + "options": { + "displayLabels": [ + "percent" + ], + "legend": { + "displayMode": "table", + "placement": "right", + "values": [ + "percent", + "value" + ] + }, + "pieType": "donut", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": true + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Get the severity distribution in bugs\n-- Get the work-type distribution in the last n tags\nwith refs_commits_diffs as(\n SELECT\n new_refs.id as new_ref_id, old_refs.id as old_ref_id, commits_diffs.commit_sha, new_commit_sha, old_commit_sha\n FROM\n commits_diffs\n LEFT JOIN refs new_refs on new_refs.commit_sha = commits_diffs.new_commit_sha\n LEFT JOIN refs old_refs on old_refs.commit_sha = commits_diffs.old_commit_sha\n),\n\n_last_n_tags as(\n SELECT \n -- distinct new_ref_id, old_ref_id\n distinct SUBSTRING_INDEX(new_ref_id,':', -1) as new_ref_id, SUBSTRING_INDEX(old_ref_id,':', -1) as old_ref_id\n FROM \n refs_commits_diffs\n WHERE\n\t\tSUBSTRING_INDEX(new_ref_id,':', 4) in ($repo_id)\n\tORDER BY 1 desc\n\tLIMIT 1\n),\n\nbugs_in_each_tag as(\n\tselect \n\t\tSUBSTRING_INDEX(rid.new_ref_id,'refs/tags/', -1) as tag_name, \n\t\tSUBSTRING_INDEX(rid.new_ref_id,':', 4) as repo_id,\n\t\ti.issue_key, i.type, i.title, i.description, i.severity \n\tfrom\n\t\trefs_issues_diffs rid\n\t\tleft join issues i on rid.issue_id = i.id\n\twhere\n\t\tSUBSTRING_INDEX(rid.new_ref_id,':', 4) in ($repo_id)\n\t\t-- and rid.new_ref_id in (SELECT new_ref_id FROM _last_n_tags)\n\t\tand SUBSTRING_INDEX(rid.new_ref_id,':', -1) in (SELECT new_ref_id FROM _last_n_tags)\n\t\tand i.type = 'BUG'\n)\n\nSELECT \n concat(biet.tag_name, \" \", case when biet.severity != '' then biet.severity else 'UNKNOWN' end) as severity,\n count(*) as bug_count\nFROM \n\tbugs_in_each_tag biet\nGROUP BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "2.2 Severity Distribution [Last Tag]", + "type": "piechart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "dev_eq" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": false + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "v22.3.2.2-lts UNKNOWN" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "v22.3.2.2-lts REQUIREMENT" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "yellow", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "v22.3.2.2-lts BUG" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 11 + }, + "id": 53, + "options": { + "displayLabels": [ + "percent" + ], + "legend": { + "displayMode": "table", + "placement": "right", + "values": [ + "percent", + "value" + ] + }, + "pieType": "donut", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": true + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Get the severity distribution in bugs\n-- Get the work-type distribution in the last n tags\nwith refs_commits_diffs as(\n SELECT\n new_refs.id as new_ref_id, old_refs.id as old_ref_id, commits_diffs.commit_sha, new_commit_sha, old_commit_sha\n FROM\n commits_diffs\n LEFT JOIN refs new_refs on new_refs.commit_sha = commits_diffs.new_commit_sha\n LEFT JOIN refs old_refs on old_refs.commit_sha = commits_diffs.old_commit_sha\n),\n\n_last_n_tags as(\n SELECT \n -- distinct new_ref_id, old_ref_id\n distinct SUBSTRING_INDEX(new_ref_id,':', -1) as new_ref_id, SUBSTRING_INDEX(old_ref_id,':', -1) as old_ref_id\n FROM \n refs_commits_diffs\n WHERE\n\t\tSUBSTRING_INDEX(new_ref_id,':', 4) in ($repo_id)\n\tORDER BY 1 desc\n\tLIMIT 1,1\n),\n\nbugs_in_each_tag as(\n\tselect \n\t\tSUBSTRING_INDEX(rid.new_ref_id,'refs/tags/', -1) as tag_name, \n\t\tSUBSTRING_INDEX(rid.new_ref_id,':', 4) as repo_id,\n\t\ti.issue_key, i.type, i.title, i.description, i.severity \n\tfrom\n\t\trefs_issues_diffs rid\n\t\tleft join issues i on rid.issue_id = i.id\n\twhere\n\t\tSUBSTRING_INDEX(rid.new_ref_id,':', 4) in ($repo_id)\n\t\t-- and rid.new_ref_id in (SELECT new_ref_id FROM _last_n_tags)\n\t\tand SUBSTRING_INDEX(rid.new_ref_id,':', -1) in (SELECT new_ref_id FROM _last_n_tags)\n\t\tand i.type = 'BUG'\n)\n\nSELECT \n concat(biet.tag_name, \" \", case when biet.severity != '' then biet.severity else 'UNKNOWN' end) as severity,\n count(*) as bug_count\nFROM \n\tbugs_in_each_tag biet\nGROUP BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "2.3 Severity Distribution [The Tag before Last]", + "type": "piechart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 11 + }, + "id": 51, + "options": { + "displayLabels": [ + "percent" + ], + "legend": { + "displayMode": "table", + "placement": "right", + "values": [ + "percent", + "value" + ] + }, + "pieType": "donut", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": true + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Get the severity distribution in bugs\n-- Get the work-type distribution in the last n tags\nwith refs_commits_diffs as(\n SELECT\n new_refs.id as new_ref_id, old_refs.id as old_ref_id, commits_diffs.commit_sha, new_commit_sha, old_commit_sha\n FROM\n commits_diffs\n LEFT JOIN refs new_refs on new_refs.commit_sha = commits_diffs.new_commit_sha\n LEFT JOIN refs old_refs on old_refs.commit_sha = commits_diffs.old_commit_sha\n),\n\n_last_n_tags as(\n SELECT \n -- distinct new_ref_id, old_ref_id\n distinct SUBSTRING_INDEX(new_ref_id,':', -1) as new_ref_id, SUBSTRING_INDEX(old_ref_id,':', -1) as old_ref_id\n FROM \n refs_commits_diffs\n WHERE\n\t\tSUBSTRING_INDEX(new_ref_id,':', 4) in ($repo_id)\n\tORDER BY 1 desc\n\tLIMIT 2,1\n),\n\nbugs_in_each_tag as(\n\tselect \n\t\tSUBSTRING_INDEX(rid.new_ref_id,'refs/tags/', -1) as tag_name, \n\t\tSUBSTRING_INDEX(rid.new_ref_id,':', 4) as repo_id,\n\t\ti.issue_key, i.type, i.title, i.description, i.severity \n\tfrom\n\t\trefs_issues_diffs rid\n\t\tleft join issues i on rid.issue_id = i.id\n\twhere\n\t\tSUBSTRING_INDEX(rid.new_ref_id,':', 4) in ($repo_id)\n\t\t-- and rid.new_ref_id in (SELECT new_ref_id FROM _last_n_tags)\n\t\tand SUBSTRING_INDEX(rid.new_ref_id,':', -1) in (SELECT new_ref_id FROM _last_n_tags)\n\t\tand i.type = 'BUG'\n)\n\nSELECT \n concat(biet.tag_name, \" \", case when biet.severity != '' then biet.severity else 'UNKNOWN' end) as severity,\n count(*) as bug_count\nFROM \n\tbugs_in_each_tag biet\nGROUP BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "2.4 Severity Distribution [The 2nd Tag before Last]", + "type": "piechart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "cost_percentage(bugfixing commits/total commits)" + }, + "properties": [ + { + "id": "unit", + "value": "percentunit" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "issue_key" + }, + "properties": [ + { + "id": "custom.width", + "value": 89 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "title" + }, + "properties": [ + { + "id": "custom.width", + "value": 457 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "assignee_name" + }, + "properties": [ + { + "id": "custom.width", + "value": 131 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "lead_time_in_days" + }, + "properties": [ + { + "id": "custom.width", + "value": 147 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "tag_name" + }, + "properties": [ + { + "id": "custom.width", + "value": 147 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "repo_name" + }, + "properties": [ + { + "id": "custom.width", + "value": 180 + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 24, + "x": 0, + "y": 18 + }, + "id": 43, + "options": { + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Get the number of fixed bugs in the last 5 tags\nwith refs_commits_diffs as(\n SELECT\n new_refs.id as new_ref_id, old_refs.id as old_ref_id, commits_diffs.commit_sha, new_commit_sha, old_commit_sha\n FROM\n commits_diffs\n LEFT JOIN refs new_refs on new_refs.commit_sha = commits_diffs.new_commit_sha\n LEFT JOIN refs old_refs on old_refs.commit_sha = commits_diffs.old_commit_sha\n),\n\n_last_5_tags as(\n SELECT \n -- distinct new_ref_id, old_ref_id\n distinct SUBSTRING_INDEX(new_ref_id,':', -1) as new_ref_id, SUBSTRING_INDEX(old_ref_id,':', -1) as old_ref_id\n FROM \n refs_commits_diffs\n WHERE\n\t\tSUBSTRING_INDEX(new_ref_id,':', 4) in ($repo_id)\n\tORDER BY 1 desc\n\tLIMIT 5\n)\n\t\nselect distinct\n\tb.name as repo_name,\n\tSUBSTRING_INDEX(rid.new_ref_id,'tags/', -1) as tag_name, \n\ti.issue_key as issue_key,\n\ti.title,\n\ti.assignee_name,\n\ti.lead_time_minutes/1440 as lead_time_in_days,\n\tconcat(b.url,'/',i.issue_key) as url\nfrom\n\trefs_issues_diffs rid\n\tleft join issues i on rid.issue_id = i.id\n\tjoin boards b on SUBSTRING_INDEX(rid.new_ref_id,':', 4) = b.id\nwhere\n\tSUBSTRING_INDEX(rid.new_ref_id,':', 4) in ($repo_id)\n\t-- and rid.new_ref_id in (SELECT new_ref_id FROM _last_5_tags)\n\tand SUBSTRING_INDEX(rid.new_ref_id,':', -1) in (SELECT SUBSTRING_INDEX(new_ref_id,':', -1) FROM _last_5_tags)\n\tand i.type = 'BUG'\norder by tag_name desc", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "2.5 List of Fixed Bugs [Last 5 Tags]", + "type": "table" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [], + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 11, + "x": 0, + "y": 25 + }, + "id": 30, + "options": { + "displayLabels": [ + "percent", + "name" + ], + "legend": { + "displayMode": "table", + "placement": "right", + "values": [ + "percent", + "value" + ] + }, + "pieType": "donut", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": true + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Component distribution of bugs fixed in the last 5 tags\nwith refs_commits_diffs as(\n SELECT\n new_refs.id as new_ref_id, old_refs.id as old_ref_id, commits_diffs.commit_sha, new_commit_sha, old_commit_sha\n FROM\n commits_diffs\n LEFT JOIN refs new_refs on new_refs.commit_sha = commits_diffs.new_commit_sha\n LEFT JOIN refs old_refs on old_refs.commit_sha = commits_diffs.old_commit_sha\n),\n\n_last_5_tags as(\n SELECT \n -- distinct new_ref_id, old_ref_id\n distinct SUBSTRING_INDEX(new_ref_id,':', -1) as new_ref_id, SUBSTRING_INDEX(old_ref_id,':', -1) as old_ref_id\n FROM \n refs_commits_diffs\n WHERE\n\t\tSUBSTRING_INDEX(new_ref_id,':', 4) in ($repo_id)\n\tORDER BY 1 desc\n\tLIMIT 5\n),\n\nbugs_in_each_tag as(\n\tselect \n\t\tSUBSTRING_INDEX(rid.new_ref_id,'refs/', -1) as tag_name, \n\t\tSUBSTRING_INDEX(rid.new_ref_id,':', 4) as repo_id,\n\t\ti.issue_key, i.component, i.severity, i.title, i.description\n\tfrom\n\t\trefs_issues_diffs rid\n\t\tleft join issues i on rid.issue_id = i.id\n\twhere\n\t\tSUBSTRING_INDEX(rid.new_ref_id,':', 4) in ($repo_id)\n\t\t-- and rid.new_ref_id in (SELECT new_ref_id FROM _last_5_tags)\n\t\tand SUBSTRING_INDEX(rid.new_ref_id,':', -1) in (SELECT new_ref_id FROM _last_5_tags)\n\t\tand i.type = 'BUG'\n)\n\n\nSELECT\n\tcase when component = '' then 'unlabeled' else 'labeled' end as component,\n\tcount(*) as bug_count\nFROM \n\tbugs_in_each_tag biet\nGROUP BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "3.1 Ratio of Issues with 'Component' Label [Last 5 Tags]", + "type": "piechart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [], + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 13, + "x": 11, + "y": 25 + }, + "id": 31, + "options": { + "displayLabels": [ + "percent", + "name" + ], + "legend": { + "displayMode": "table", + "placement": "right", + "values": [ + "percent", + "value" + ] + }, + "pieType": "donut", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": true + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Component distribution of bugs fixed in the last 5 tags\nwith refs_commits_diffs as(\n SELECT\n new_refs.id as new_ref_id, old_refs.id as old_ref_id, commits_diffs.commit_sha, new_commit_sha, old_commit_sha\n FROM\n commits_diffs\n LEFT JOIN refs new_refs on new_refs.commit_sha = commits_diffs.new_commit_sha\n LEFT JOIN refs old_refs on old_refs.commit_sha = commits_diffs.old_commit_sha\n),\n\n_last_5_tags as(\n SELECT \n -- distinct new_ref_id, old_ref_id\n distinct SUBSTRING_INDEX(new_ref_id,':', -1) as new_ref_id, SUBSTRING_INDEX(old_ref_id,':', -1) as old_ref_id\n FROM \n refs_commits_diffs\n WHERE\n\t\tSUBSTRING_INDEX(new_ref_id,':', 4) in ($repo_id)\n\tORDER BY 1 desc\n\tLIMIT 5\n),\n\nbugs_in_each_tag as(\n\tselect \n\t\tSUBSTRING_INDEX(rid.new_ref_id,'refs/', -1) as tag_name, \n\t\tSUBSTRING_INDEX(rid.new_ref_id,':', 4) as repo_id,\n\t\ti.issue_key, i.component, i.severity, i.title, i.description\n\tfrom\n\t\trefs_issues_diffs rid\n\t\tleft join issues i on rid.issue_id = i.id\n\twhere\n\t\tSUBSTRING_INDEX(rid.new_ref_id,':', 4) in ($repo_id)\n\t\t-- and rid.new_ref_id in (SELECT new_ref_id FROM _last_5_tags)\n\t\tand SUBSTRING_INDEX(rid.new_ref_id,':', -1) in (SELECT new_ref_id FROM _last_5_tags)\n\t\tand i.type = 'BUG'\n)\n\n\nSELECT\n\tcomponent,\n\tcount(*) as bug_count\nFROM \n\tbugs_in_each_tag biet\nwhere \n component != ''\nGROUP BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "3.2 Source of Bugs by Component [Last 5 Tags]", + "type": "piechart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 0.25 + }, + { + "color": "green", + "value": 0.4 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 32 + }, + "id": 23, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Get the % of contributors who fixed 80% of bugs in the last 5 tags\nwith refs_commits_diffs as(\n SELECT\n new_refs.id as new_ref_id, old_refs.id as old_ref_id, commits_diffs.commit_sha, new_commit_sha, old_commit_sha\n FROM\n commits_diffs\n LEFT JOIN refs new_refs on new_refs.commit_sha = commits_diffs.new_commit_sha\n LEFT JOIN refs old_refs on old_refs.commit_sha = commits_diffs.old_commit_sha\n),\n\n_last_5_tags as(\n SELECT \n -- distinct new_ref_id, old_ref_id\n distinct SUBSTRING_INDEX(new_ref_id,':', -1) as new_ref_id, SUBSTRING_INDEX(old_ref_id,':', -1) as old_ref_id\n FROM \n refs_commits_diffs\n WHERE\n\t\tSUBSTRING_INDEX(new_ref_id,':', 4) in ($repo_id)\n\tORDER BY 1 desc\n\tLIMIT 5\n),\n\n_bugs as(\n\tselect \n\t\ti.issue_key, i.type, i.severity, i.title, i.description,\n\t\tpr.id, pr.author_name as pr_author, pr.created_date,\n\t\trank() over(partition by i.id order by pr.created_date asc) as pr_rank\n\tfrom\n\t\trefs_issues_diffs rid\n\t\tleft join issues i on rid.issue_id = i.id\n\t\tleft join pull_request_issues pri on i.id = pri.issue_id\n\t\tleft join pull_requests pr on pri.pull_request_id = pr.id\n\twhere\n\t\tSUBSTRING_INDEX(rid.new_ref_id,':', 4) in ($repo_id)\n\t\t-- and rid.new_ref_id in (SELECT new_ref_id FROM _last_5_tags)\n\t\tand SUBSTRING_INDEX(rid.new_ref_id,':', -1) in (SELECT new_ref_id FROM _last_5_tags)\n\t\tand i.type = 'BUG'\n\torder by i.issue_key\n),\n\n_bug_fixed_count as(\n SELECT \n pr_author,\n count(*) bug_fixed_count\n FROM _bugs\n WHERE pr_rank = 1\n GROUP BY 1\n),\n\n_bug_fixed_count_running_total as(\n SELECT \n *, \n sum(bug_fixed_count) OVER (Order by bug_fixed_count desc) AS running_total\n FROM \n _bug_fixed_count\n),\n\n_percentile as(\n SELECT \n pr_author,\n bug_fixed_count,\n running_total/sum(bug_fixed_count) OVER () AS cumulative_percentage\n FROM \n _bug_fixed_count_running_total\n)\n\n\nSELECT \n count(case when cumulative_percentage <= 0.8 then pr_author else null end)/count(*) as \"% of contributors who fixed 80% of the bugs\"\nFROM _percentile", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "4.1 Contributor Fixing 80%+ Bugs [Last 5 Tags]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Bug Fixed Count", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 2 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 18, + "x": 6, + "y": 32 + }, + "id": 18, + "options": { + "barWidth": 0.5, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "hidden", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Get the bug fixer distribution in the last 5 tags\nwith refs_commits_diffs as(\n SELECT\n new_refs.id as new_ref_id, old_refs.id as old_ref_id, commits_diffs.commit_sha, new_commit_sha, old_commit_sha\n FROM\n commits_diffs\n LEFT JOIN refs new_refs on new_refs.commit_sha = commits_diffs.new_commit_sha\n LEFT JOIN refs old_refs on old_refs.commit_sha = commits_diffs.old_commit_sha\n),\n\n_last_5_tags as(\n SELECT \n -- distinct new_ref_id, old_ref_id\n distinct SUBSTRING_INDEX(new_ref_id,':', -1) as new_ref_id, SUBSTRING_INDEX(old_ref_id,':', -1) as old_ref_id\n FROM \n refs_commits_diffs\n WHERE\n\t\tSUBSTRING_INDEX(new_ref_id,':', 4) in ($repo_id)\n\tORDER BY 1 desc\n\tLIMIT 5\n),\n\n_bugs as(\n\tselect \n\t\ti.issue_key, i.type, i.severity, i.title, i.description,\n\t\tpr.id, pr.author_name as pr_author, pr.created_date,\n\t\trank() over(partition by i.id order by pr.created_date asc) as pr_rank\n\tfrom\n\t\trefs_issues_diffs rid\n\t\tleft join issues i on rid.issue_id = i.id\n\t\tleft join pull_request_issues pri on i.id = pri.issue_id\n\t\tleft join pull_requests pr on pri.pull_request_id = pr.id\n\twhere\n\t\tSUBSTRING_INDEX(rid.new_ref_id,':', 4) in ($repo_id)\n\t\t-- and rid.new_ref_id in (SELECT new_ref_id FROM _last_5_tags)\n\t\tand SUBSTRING_INDEX(rid.new_ref_id,':', -1) in (SELECT new_ref_id FROM _last_5_tags)\n\t\tand i.type = 'BUG'\n\torder by i.issue_key\n)\n\nSELECT \n pr_author,\n count(*) bug_fixed_count\nFROM _bugs\nWHERE pr_rank = 1\nGROUP BY 1\nORDER BY 2 desc\nlimit 10", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "4.2 Top Bug Fixers [Last 5 Tags]", + "type": "barchart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 0, + "y": 39 + }, + "id": 33, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Get the avg bug age in history\nselect \n avg(lead_time_minutes)/1440 as average_bug_age\nfrom issues\nleft join board_issues bi on issues.id = bi.issue_id\nwhere \n type = 'BUG'\n and status = 'DONE'\n and bi.board_id in ($repo_id)", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "5.1 Mean Bug Age in Days [All History]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Bug Fixed Count", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 2 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 20, + "x": 4, + "y": 39 + }, + "id": 32, + "options": { + "barWidth": 0.7, + "groupWidth": 0.3, + "legend": { + "calcs": [], + "displayMode": "hidden", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Get the bug age in the last 5 tags\nwith refs_commits_diffs as(\n SELECT\n new_refs.id as new_ref_id, old_refs.id as old_ref_id, commits_diffs.commit_sha, new_commit_sha, old_commit_sha\n FROM\n commits_diffs\n LEFT JOIN refs new_refs on new_refs.commit_sha = commits_diffs.new_commit_sha\n LEFT JOIN refs old_refs on old_refs.commit_sha = commits_diffs.old_commit_sha\n),\n\n_last_5_tags as(\n SELECT \n distinct SUBSTRING_INDEX(new_ref_id,':', -1) as new_ref_id, SUBSTRING_INDEX(old_ref_id,':', -1) as old_ref_id\n FROM \n refs_commits_diffs\n WHERE\n\t\tSUBSTRING_INDEX(new_ref_id,':', 4) in ($repo_id)\n\tORDER BY 1 desc\n\tLIMIT 5\n),\n\n_bugs as(\n\tselect distinct\n\t\tSUBSTRING_INDEX(rid.new_ref_id,'tags/', -1) as tag_name,\n\t\ti.id,\n\t\ti.lead_time_minutes\n\tfrom\n\t\trefs_issues_diffs rid\n\t\tleft join issues i on rid.issue_id = i.id\n\t\tleft join pull_request_issues pri on i.id = pri.issue_id\n\twhere\n\t\tSUBSTRING_INDEX(rid.new_ref_id,':', 4) in ($repo_id)\n\t\t-- and rid.new_ref_id in (SELECT new_ref_id FROM _last_5_tags)\n\t\tand SUBSTRING_INDEX(rid.new_ref_id,':', -1) in (SELECT new_ref_id FROM _last_5_tags)\n\t\tand i.type = 'BUG'\n),\n\n_bugs_percentile as(\n select \n *,\n percent_rank() over (partition by tag_name order by lead_time_minutes) as percentile\n from _bugs order by 1\n),\n\n_avg_bug_age as(\n select \n tag_name,\n avg(lead_time_minutes)/1440 as average_bug_age\n from _bugs_percentile\n group by 1\n),\n\n_50th_bug_age as(\n select \n tag_name,\n min(lead_time_minutes)/1440 as \"50th_bug_age\"\n from _bugs_percentile\n where percentile >= 0.5\n group by 1\n)\n\nselect \n aba.*,\n eba.50th_bug_age\nfrom \n _avg_bug_age aba\n join _50th_bug_age eba on aba.tag_name = eba.tag_name", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "5.2 Mean + Median Bug Age Days [Last 5 Tags]", + "type": "barchart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 0, + "y": 45 + }, + "id": 34, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Get the 80th perccentile bug age in history\nwith _bugs_percentile as(\n select \n id,\n lead_time_minutes,\n percent_rank() over (order by lead_time_minutes) as percentile\n from issues\n where \n type = 'BUG'\n and status = 'DONE'\n)\n\nselect \n min(lead_time_minutes)/1440 as \"80th_bug_age\"\nfrom \n _bugs_percentile\nwhere \n percentile >= 0.5\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "5.3 Median Bug Age in Days [All History]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "key" + }, + "properties": [ + { + "id": "custom.width", + "value": 109 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "title" + }, + "properties": [ + { + "id": "custom.width", + "value": 725 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "name" + }, + "properties": [ + { + "id": "custom.width", + "value": 182 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "lead_time_in_days" + }, + "properties": [ + { + "id": "custom.width", + "value": 136 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "issue_key" + }, + "properties": [ + { + "id": "custom.width", + "value": 79 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "url" + }, + "properties": [ + { + "id": "custom.width", + "value": 784 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "tag_name" + }, + "properties": [ + { + "id": "custom.width", + "value": 150 + } + ] + } + ] + }, + "gridPos": { + "h": 6, + "w": 20, + "x": 4, + "y": 45 + }, + "id": 38, + "options": { + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Get the bug fixer distribution in the last 5 tags\nwith refs_commits_diffs as(\n SELECT\n new_refs.id as new_ref_id, old_refs.id as old_ref_id, commits_diffs.commit_sha, new_commit_sha, old_commit_sha\n FROM\n commits_diffs\n LEFT JOIN refs new_refs on new_refs.commit_sha = commits_diffs.new_commit_sha\n LEFT JOIN refs old_refs on old_refs.commit_sha = commits_diffs.old_commit_sha\n),\n\n_last_5_tags as(\n SELECT \n -- distinct new_ref_id, old_ref_id\n distinct SUBSTRING_INDEX(new_ref_id,':', -1) as new_ref_id, SUBSTRING_INDEX(old_ref_id,':', -1) as old_ref_id\n FROM \n refs_commits_diffs\n WHERE\n\t\tSUBSTRING_INDEX(new_ref_id,':', 4) in ($repo_id)\n\tORDER BY 1 desc\n\tLIMIT 5\n),\n\n_bugs as(\n\tselect distinct\n\t b.name,\n\t\tSUBSTRING_INDEX(rid.new_ref_id,'tags/', -1) as tag_name,\n\t\ti.issue_key as issue_key,\n i.title,\n i.lead_time_minutes/1440 as lead_time_in_days,\n concat(b.url,'/',i.issue_key) as url\n\tfrom\n\t\trefs_issues_diffs rid\n\t\tleft join issues i on rid.issue_id = i.id\n\t\tleft join pull_request_issues pri on i.id = pri.issue_id\n\t\tjoin boards b on SUBSTRING_INDEX(rid.new_ref_id,':', 4) = b.id\n\twhere\n\t\tSUBSTRING_INDEX(rid.new_ref_id,':', 4) in ($repo_id)\n\t\t-- and rid.new_ref_id in (SELECT new_ref_id FROM _last_5_tags)\n\t\tand SUBSTRING_INDEX(rid.new_ref_id,':', -1) in (SELECT new_ref_id FROM _last_5_tags)\n\t\tand i.type = 'BUG'\n),\n\n_bug_age_rank as(\n select \n *,\n row_number() over (partition by tag_name order by lead_time_in_days desc) as bug_age_rank\n from _bugs\n)\n\nselect \n name,\n tag_name,\n issue_key,\n title,\n lead_time_in_days,\n url\nfrom _bug_age_rank\nwhere bug_age_rank <=10 \norder by tag_name, lead_time_in_days desc", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "5.4 List of Long-Lead Bugs [Closed Bugs in Last 5 Tags]", + "type": "table" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [], + "unit": "short" + }, + "overrides": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "bug_count" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "=avg_bug_age" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 51 + }, + "id": 35, + "options": { + "displayLabels": [ + "name", + "percent" + ], + "legend": { + "displayMode": "hidden", + "placement": "bottom", + "values": [ + "value", + "percent" + ] + }, + "pieType": "donut", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": true + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Get the avg bug age in history\nwith _avg_bug_age as(\n select \n type,\n avg(lead_time_minutes) as average_bug_age\n from \n issues\n left join board_issues bi on issues.id = bi.issue_id\n where \n type = 'BUG'\n and status = 'DONE'\n and bi.board_id in ($repo_id)\n group by 1\n),\n\n\n_bug_queue_time as(\n select \n i.id,\n abg.average_bug_age,\n TIMESTAMPDIFF(MINUTE,created_date,NOW()) as queue_time,\n case when TIMESTAMPDIFF(MINUTE,created_date,NOW()) >= average_bug_age then \">=avg_bug_age\" else \" Mean]", + "type": "piechart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "=avg_bug_age" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "issue_key" + }, + "properties": [ + { + "id": "custom.width", + "value": 81 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "title" + }, + "properties": [ + { + "id": "custom.width", + "value": 535 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "created_date" + }, + "properties": [ + { + "id": "custom.width", + "value": 149 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "queue_time_in_days" + }, + "properties": [ + { + "id": "custom.width", + "value": 140 + } + ] + } + ] + }, + "gridPos": { + "h": 6, + "w": 18, + "x": 6, + "y": 51 + }, + "id": 39, + "options": { + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Get the queue time of all backlog bugs\nselect \n b.name as repo_name,\n i.issue_key as issue_key,\n i.title,\n i.created_date,\n (TIMESTAMPDIFF(MINUTE, i.created_date,NOW()))/3600 as queue_time_in_days,\n concat(b.url,'/',i.issue_key) as url\nfrom \n issues i\n left join board_issues bi on i.id = bi.issue_id\n left join boards b on bi.board_id = b.id\nwhere\n i.type = 'BUG'\n and i.status != 'DONE'\n and b.id in ($repo_id)\norder by queue_time_in_days desc", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "5.6 List of Outstanding Bugs [All Open Bugs]", + "type": "table" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 57 + }, + "id": 47, + "panels": [], + "title": "Contribution", + "type": "row" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 58 + }, + "id": 41, + "options": { + "barWidth": 0.3, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "hidden", + "placement": "bottom" + }, + "orientation": "horizontal", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "-- Get the bug distribution in last 5 tags\nwith refs_commits_diffs as(\n SELECT\n new_refs.id as new_ref_id, old_refs.id as old_ref_id, commits_diffs.commit_sha, new_commit_sha, old_commit_sha\n FROM\n commits_diffs\n LEFT JOIN refs new_refs on new_refs.commit_sha = commits_diffs.new_commit_sha\n LEFT JOIN refs old_refs on old_refs.commit_sha = commits_diffs.old_commit_sha\n),\n\n_last_5_tags as(\n SELECT \n -- distinct new_ref_id, old_ref_id\n distinct SUBSTRING_INDEX(new_ref_id,':', -1) as new_ref_id, SUBSTRING_INDEX(old_ref_id,':', -1) as old_ref_id\n FROM \n refs_commits_diffs\n WHERE\n\t\tSUBSTRING_INDEX(new_ref_id,':', 4) in ($repo_id)\n\tORDER BY 1 desc\n\tLIMIT 10\n)\n\nselect \n\tSUBSTRING_INDEX(rcd.new_ref_id,'refs/tags/', -1) as tag_name,\n\tSUBSTRING_INDEX(rcd.old_ref_id,'refs/tags/', -1) as old_tag_name,\n\tcount(*) as commit_count\nfrom\n\trefs_commits_diffs rcd\n\tleft join commits c on rcd.commit_sha = c.sha\nwhere\n\tSUBSTRING_INDEX(rcd.new_ref_id,':', 4) in ($repo_id)\n\t-- and rcd.new_ref_id in (select new_ref_id from _last_5_tags)\n\tand SUBSTRING_INDEX(rcd.new_ref_id,':', -1) in (SELECT new_ref_id FROM _last_5_tags)\ngroup by 1,2\norder by 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "6.1 Number of New Commits Per Tag", + "type": "barchart" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "message" + }, + "properties": [ + { + "id": "custom.width", + "value": 395 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "additions" + }, + "properties": [ + { + "id": "custom.width", + "value": 92 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "deletions" + }, + "properties": [ + { + "id": "custom.width", + "value": 86 + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 18, + "x": 6, + "y": 58 + }, + "id": 42, + "options": { + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "-- Get the bug distribution in last 5 tags\nwith refs_commits_diffs as(\n SELECT\n new_refs.id as new_ref_id, old_refs.id as old_ref_id, commits_diffs.commit_sha, new_commit_sha, old_commit_sha\n FROM\n commits_diffs\n LEFT JOIN refs new_refs on new_refs.commit_sha = commits_diffs.new_commit_sha\n LEFT JOIN refs old_refs on old_refs.commit_sha = commits_diffs.old_commit_sha\n),\n\n_last_5_tags as(\n SELECT \n -- distinct new_ref_id, old_ref_id\n distinct SUBSTRING_INDEX(new_ref_id,':', -1) as new_ref_id, SUBSTRING_INDEX(old_ref_id,':', -1) as old_ref_id\n FROM \n refs_commits_diffs\n WHERE\n\t\tSUBSTRING_INDEX(new_ref_id,':', 4) in ($repo_id)\n\tORDER BY 1 desc\n\tLIMIT 10\n)\n\nselect \n\tSUBSTRING_INDEX(rcd.new_ref_id,'refs/tags/', -1) as new_tag_name,\n\tSUBSTRING_INDEX(rcd.old_ref_id,'refs/tags/', -1) as compared_tag_name,\n\tc.sha,\n\tc.message,\n\tc.additions,\n\tc.deletions,\n\tc.author_name\nfrom\n\trefs_commits_diffs rcd\n\tleft join commits c on rcd.commit_sha = c.sha\nwhere\n\tSUBSTRING_INDEX(rcd.new_ref_id,':', 4) in ($repo_id)\n\t-- and rcd.new_ref_id in (select new_ref_id from _last_5_tags)\n\tand SUBSTRING_INDEX(rcd.new_ref_id,':', -1) in (SELECT new_ref_id FROM _last_5_tags)\norder by 1 desc", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "6.2 Commit List for Drill-Down [Last 5 Tags]", + "type": "table" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "v22.3.2.2-lts BUG" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "v22.3.2.2-lts UNKNOWN" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 0, + "y": 65 + }, + "id": 26, + "options": { + "displayLabels": [ + "percent" + ], + "legend": { + "displayMode": "table", + "placement": "right", + "values": [ + "percent", + "value" + ] + }, + "pieType": "donut", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": true + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Get the work-type distribution in the last 5 tags\nwith refs_commits_diffs as(\n SELECT\n new_refs.id as new_ref_id, old_refs.id as old_ref_id, commits_diffs.commit_sha, new_commit_sha, old_commit_sha\n FROM\n commits_diffs\n LEFT JOIN refs new_refs on new_refs.commit_sha = commits_diffs.new_commit_sha\n LEFT JOIN refs old_refs on old_refs.commit_sha = commits_diffs.old_commit_sha\n),\n\n_last_5_tags as(\n SELECT \n -- distinct new_ref_id, old_ref_id\n distinct SUBSTRING_INDEX(new_ref_id,':', -1) as new_ref_id, SUBSTRING_INDEX(old_ref_id,':', -1) as old_ref_id\n FROM \n refs_commits_diffs\n WHERE\n\t\tSUBSTRING_INDEX(new_ref_id,':', 4) in ($repo_id)\n\tORDER BY 1 desc\n\tLIMIT 1\n),\n\n_combine_pr as (\n select pull_request_id as id, commit_sha, p.pull_request_key as pull_request_key from pull_request_commits left join pull_requests p on pull_request_commits.pull_request_id = p.id\n where base_repo_id in ($repo_id)\n union\n select id, merge_commit_sha, pull_request_key as commit_sha from pull_requests where base_repo_id in ($repo_id)\n),\n\n_commit_count_of_pr as(\n select\n SUBSTRING_INDEX(rcd.new_ref_id,'tags/', -1) as tag_name,\n pr.id as pull_request_id,\n count(c.sha) as pr_commit_count\n FROM \n refs_commits_diffs rcd\n\t\tleft join commits c on rcd.commit_sha = c.sha\n\t\t-- left join pull_request_commits prc on c.sha = prc.commit_sha\n\t\tleft join _combine_pr pr on c.sha = pr.commit_sha\n\twhere\n\t\tSUBSTRING_INDEX(rcd.new_ref_id,':', 4) in ($repo_id)\n\t\t-- and rcd.new_ref_id in (SELECT new_ref_id FROM _last_5_tags)\n\t\tand SUBSTRING_INDEX(rcd.new_ref_id,':', -1) in (SELECT new_ref_id FROM _last_5_tags)\n\tgroup by 1,2\n),\n\n_pr_issues as(\n select\n pri.pull_request_id,\n pri.issue_id,\n i.issue_key,\n i.type,\n row_number() over(partition by issue_id ORDER by pr.created_date asc) as pr_rank\n from\n pull_request_issues pri\n left join pull_requests pr on pri.pull_request_id = pr.id\n left join issues i on pri.issue_id = i.id\n where \n i.issue_key != 0\n),\n\n_final_results as(\n select\n distinct ccop.*, pi.type\n from \n _commit_count_of_pr ccop\n left join _pr_issues pi on ccop.pull_request_id = pi.pull_request_id\n where pi.pr_rank = 1\n order by 1\n)\n\nSELECT\n tag_name,\n case when type != '' then type else 'UNKNOWN' end as type,\n sum(pr_commit_count) as commit_count\nfrom _final_results\ngroup by 1,2", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "7.1 Work-Type Distribution [Last Tag]", + "type": "piechart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "v22.2.3.5-stable UNKNOWN" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "v22.2.3.5-stable BUG" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 8, + "y": 65 + }, + "id": 36, + "options": { + "displayLabels": [ + "percent" + ], + "legend": { + "displayMode": "table", + "placement": "right", + "values": [ + "percent", + "value" + ] + }, + "pieType": "donut", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": true + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Get the work-type distribution in the last 5 tags\nwith refs_commits_diffs as(\n SELECT\n new_refs.id as new_ref_id, old_refs.id as old_ref_id, commits_diffs.commit_sha, new_commit_sha, old_commit_sha\n FROM\n commits_diffs\n LEFT JOIN refs new_refs on new_refs.commit_sha = commits_diffs.new_commit_sha\n LEFT JOIN refs old_refs on old_refs.commit_sha = commits_diffs.old_commit_sha\n),\n\n_last_5_tags as(\n SELECT \n -- distinct new_ref_id, old_ref_id\n distinct SUBSTRING_INDEX(new_ref_id,':', -1) as new_ref_id, SUBSTRING_INDEX(old_ref_id,':', -1) as old_ref_id\n FROM \n refs_commits_diffs\n WHERE\n\t\tSUBSTRING_INDEX(new_ref_id,':', 4) in ($repo_id)\n\tORDER BY 1 desc\n\tLIMIT 1,1\n),\n\n\n_combine_pr as (\n select pull_request_id as id, commit_sha, p.pull_request_key as pull_request_key from pull_request_commits left join pull_requests p on pull_request_commits.pull_request_id = p.id\n where base_repo_id in ($repo_id)\n union\n select id, merge_commit_sha, pull_request_key as commit_sha from pull_requests where base_repo_id in ($repo_id)\n),\n\n_commit_count_of_pr as(\n select\n SUBSTRING_INDEX(rcd.new_ref_id,'tags/', -1) as tag_name,\n pr.id as pull_request_id,\n count(c.sha) as pr_commit_count\n FROM \n refs_commits_diffs rcd\n\t\tleft join commits c on rcd.commit_sha = c.sha\n\t\t-- left join pull_request_commits prc on c.sha = prc.commit_sha\n\t\tleft join _combine_pr pr on c.sha = pr.commit_sha\n\twhere\n\t\tSUBSTRING_INDEX(rcd.new_ref_id,':', 4) in ($repo_id)\n\t\t-- and rcd.new_ref_id in (SELECT new_ref_id FROM _last_5_tags)\n\t\tand SUBSTRING_INDEX(rcd.new_ref_id,':', -1) in (SELECT new_ref_id FROM _last_5_tags)\n\tgroup by 1,2\n),\n\n_pr_issues as(\n select\n pri.pull_request_id,\n pri.issue_id,\n i.issue_key,\n i.type,\n row_number() over(partition by issue_id ORDER by pr.created_date asc) as pr_rank\n from\n pull_request_issues pri\n left join pull_requests pr on pri.pull_request_id = pr.id\n left join issues i on pri.issue_id = i.id\n where \n i.issue_key != 0\n),\n\n_final_results as(\n select\n distinct ccop.*, pi.type\n from \n _commit_count_of_pr ccop\n left join _pr_issues pi on ccop.pull_request_id = pi.pull_request_id\n where pi.pr_rank = 1\n order by 1\n)\n\nSELECT\n tag_name,\n case when type != '' then type else 'UNKNOWN' end as type,\n sum(pr_commit_count) as commit_count\nfrom _final_results\ngroup by 1,2", + "refId": "A", + "select": [ + [ + { + "params": [ + "script_version" + ], + "type": "column" + } + ] + ], + "table": "_devlake_migration_history", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "7.2 Work-Type Distribution [The Tag before Last]", + "type": "piechart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "v22.1.4.30-stable UNKNOWN" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "v22.1.4.30-stable BUG" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 7, + "w": 8, + "x": 16, + "y": 65 + }, + "id": 37, + "options": { + "displayLabels": [ + "percent" + ], + "legend": { + "displayMode": "table", + "placement": "right", + "values": [ + "percent", + "value" + ] + }, + "pieType": "donut", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": true + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Get the work-type distribution in the last 5 tags\nwith refs_commits_diffs as(\n SELECT\n new_refs.id as new_ref_id, old_refs.id as old_ref_id, commits_diffs.commit_sha, new_commit_sha, old_commit_sha\n FROM\n commits_diffs\n LEFT JOIN refs new_refs on new_refs.commit_sha = commits_diffs.new_commit_sha\n LEFT JOIN refs old_refs on old_refs.commit_sha = commits_diffs.old_commit_sha\n),\n\n_last_5_tags as(\n SELECT \n -- distinct new_ref_id, old_ref_id\n distinct SUBSTRING_INDEX(new_ref_id,':', -1) as new_ref_id, SUBSTRING_INDEX(old_ref_id,':', -1) as old_ref_id\n FROM \n refs_commits_diffs\n WHERE\n\t\tSUBSTRING_INDEX(new_ref_id,':', 4) in ($repo_id)\n\tORDER BY 1 desc\n\tLIMIT 2,1\n),\n\n\n_combine_pr as (\n select pull_request_id as id, commit_sha, p.pull_request_key as pull_request_key from pull_request_commits left join pull_requests p on pull_request_commits.pull_request_id = p.id\n where base_repo_id in ($repo_id)\n union\n select id, merge_commit_sha, pull_request_key as commit_sha from pull_requests where base_repo_id in ($repo_id)\n),\n\n_commit_count_of_pr as(\n select\n SUBSTRING_INDEX(rcd.new_ref_id,'tags/', -1) as tag_name,\n pr.id as pull_request_id,\n count(c.sha) as pr_commit_count\n FROM \n refs_commits_diffs rcd\n\t\tleft join commits c on rcd.commit_sha = c.sha\n\t\t-- left join pull_request_commits prc on c.sha = prc.commit_sha\n\t\tleft join _combine_pr pr on c.sha = pr.commit_sha\n\twhere\n\t\tSUBSTRING_INDEX(rcd.new_ref_id,':', 4) in ($repo_id)\n\t\t-- and rcd.new_ref_id in (SELECT new_ref_id FROM _last_5_tags)\n\t\tand SUBSTRING_INDEX(rcd.new_ref_id,':', -1) in (SELECT new_ref_id FROM _last_5_tags)\n\tgroup by 1,2\n),\n\n_pr_issues as(\n select\n pri.pull_request_id,\n pri.issue_id,\n i.issue_key,\n i.type,\n row_number() over(partition by issue_id ORDER by pr.created_date asc) as pr_rank\n from\n pull_request_issues pri\n left join pull_requests pr on pri.pull_request_id = pr.id\n left join issues i on pri.issue_id = i.id\n where \n i.issue_key != 0\n),\n\n_final_results as(\n select\n distinct ccop.*, pi.type\n from \n _commit_count_of_pr ccop\n left join _pr_issues pi on ccop.pull_request_id = pi.pull_request_id\n where pi.pr_rank = 1\n order by 1\n)\n\nSELECT\n tag_name,\n case when type != '' then type else 'UNKNOWN' end as type,\n sum(pr_commit_count) as commit_count\nfrom _final_results\ngroup by 1,2", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "7.3 Work-Type Distribution [The 2nd Tag before Last]", + "type": "piechart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "#EAB839", + "value": 0.25 + }, + { + "color": "green", + "value": 0.4 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 6, + "x": 0, + "y": 72 + }, + "id": 27, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "-- Get each contributor's work in bugfixing in the last 5 tags\nwith refs_commits_diffs as(\n SELECT\n new_refs.id as new_ref_id, old_refs.id as old_ref_id, commits_diffs.commit_sha, new_commit_sha, old_commit_sha\n FROM\n commits_diffs\n LEFT JOIN refs new_refs on new_refs.commit_sha = commits_diffs.new_commit_sha\n LEFT JOIN refs old_refs on old_refs.commit_sha = commits_diffs.old_commit_sha\n),\n\n_last_5_tags as(\n SELECT \n -- distinct new_ref_id, old_ref_id\n distinct SUBSTRING_INDEX(new_ref_id,':', -1) as new_ref_id, SUBSTRING_INDEX(old_ref_id,':', -1) as old_ref_id\n FROM \n refs_commits_diffs\n WHERE\n\t\tSUBSTRING_INDEX(new_ref_id,':', 4) in ($repo_id)\n\tORDER BY 1 desc\n\tLIMIT 5\n),\n\n_author_commits as(\n SELECT \n \tc.author_name,\n count(c.sha) as commit_count\n FROM \n refs_commits_diffs rcf\n left join commits c on rcf.commit_sha = c.sha\n WHERE\n \t-- rcf.new_ref_id in (SELECT new_ref_id FROM _last_5_tags)\n \tSUBSTRING_INDEX(rcf.new_ref_id,':', 4) in ($repo_id)\n \tand SUBSTRING_INDEX(rcf.new_ref_id,':', -1) in (SELECT new_ref_id FROM _last_5_tags)\n GROUP BY 1\n),\n\n_author_commits_running_total as(\n SELECT \n *, \n sum(commit_count) OVER (Order by commit_count desc) AS running_total\n FROM \n _author_commits\n),\n\n_percentile as(\n SELECT \n author_name,\n commit_count,\n running_total/sum(commit_count) OVER () AS cumulative_percentage\n FROM \n _author_commits_running_total\n)\n\n\nSELECT \n count(case when cumulative_percentage <= 0.8 then author_name else null end)/count(*) as \"contributors who contributed 80% of dev_eq\"\nFROM _percentile", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "8.1 Committers Contributing 80%+ Commits [Last 5 Tags]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Dev Equivalent", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 18, + "x": 6, + "y": 72 + }, + "id": 3, + "options": { + "barWidth": 0.3, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "hidden", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": {}, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with refs_commits_diffs as(\n SELECT\n new_refs.id as new_ref_id, old_refs.id as old_ref_id, commits_diffs.commit_sha, new_commit_sha, old_commit_sha\n FROM\n commits_diffs\n LEFT JOIN refs new_refs on new_refs.commit_sha = commits_diffs.new_commit_sha\n LEFT JOIN refs old_refs on old_refs.commit_sha = commits_diffs.old_commit_sha\n),\n\n_last_5_tags as(\n SELECT \n -- distinct new_ref_id, old_ref_id\n distinct SUBSTRING_INDEX(new_ref_id,':', -1) as new_ref_id, SUBSTRING_INDEX(old_ref_id,':', -1) as old_ref_id\n FROM \n refs_commits_diffs\n WHERE\n\t\tSUBSTRING_INDEX(new_ref_id,':', 4) in ($repo_id)\n\tORDER BY 1 desc\n\tLIMIT 5\n)\n\n\nSELECT \n\tc.author_name,\n count(c.sha) total_dev_eq\nFROM \n refs_commits_diffs rcf\n left join commits c on rcf.commit_sha = c.sha\nWHERE\n\t-- rcf.new_ref_id in (SELECT new_ref_id FROM _last_5_tags)\n\tSUBSTRING_INDEX(rcf.new_ref_id,':', 4) in ($repo_id)\n\tand SUBSTRING_INDEX(rcf.new_ref_id,':', -1) in (SELECT new_ref_id FROM _last_5_tags)\nGROUP BY 1\nORDER BY 2 desc\nlimit 10", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "8.2 Top Contributors [Last 5 Tags]", + "type": "barchart" + }, + { + "datasource": null, + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 79 + }, + "id": 59, + "options": { + "content": "
\n\nThis dashboard is created based on this [data schema](https://devlake.apache.org/docs/DataModels/DevLakeDomainLayerSchema). Want to add more metrics? Please follow the [guide](https://devlake.apache.org/docs/Configuration/Dashboards/GrafanaUserGuide).", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + } + ], + "refresh": "", + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": "mysql", + "definition": "select concat(name, '--', id) as text from repos", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Repo", + "multi": true, + "name": "repo_id", + "options": [], + "query": "select concat(name, '--', id) as text from repos", + "refresh": 1, + "regex": "/^(?.*)--(?.*)$/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-6M", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "GitHub_Release_Quality_and_Contribution_Analysis", + "uid": "2xuOaQUnk4", + "version": 3 +} \ No newline at end of file diff --git a/charts/devlake/dashboards/Gitlab.json b/charts/devlake/dashboards/Gitlab.json new file mode 100644 index 0000000..bbe74f6 --- /dev/null +++ b/charts/devlake/dashboards/Gitlab.json @@ -0,0 +1,1147 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 16, + "iteration": 1683687670575, + "links": [], + "panels": [ + { + "datasource": null, + "gridPos": { + "h": 3, + "w": 13, + "x": 0, + "y": 0 + }, + "id": 101, + "options": { + "content": "- Use Cases: This dashboard shows the basic Git and Code Review metrics from GitLab.\n- Data Source Required: GitLab", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "title": "Dashboard Introduction", + "type": "text" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 3 + }, + "id": 83, + "panels": [], + "title": "1. Contribution (PRs)", + "type": "row" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 4 + }, + "id": 68, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select\n\tcount(*) as pull_request_count\nfrom \n\tpull_requests pr\nwhere\n $__timeFilter(created_date)\n\tand base_repo_id in ($repo_id)\n\t\n\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "1.1 Number of New Pull Requests [Selected Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 18, + "x": 6, + "y": 4 + }, + "id": 77, + "options": { + "barWidth": 0.5, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _prs as(\n SELECT\n DATE_ADD(date(created_date), INTERVAL -DAY(date(created_date))+1 DAY) as time,\n count(*) as pr_count\n FROM pull_requests\n WHERE\n base_repo_id in ($repo_id)\n and $__timeFilter(created_date)\n and created_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\n group by 1\n)\n\nSELECT \n date_format(time,'%M %Y') as month,\n pr_count as \"Pull Request Count\"\nFROM _prs\nORDER BY time\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "1.2 Total Number of New Pull Requests [Each Month]", + "type": "barchart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Merged PR Count", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 54, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 59, + "options": { + "barWidth": 0.5, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "-- The PR/MR statuses are standardized to DevLake's statuses 'OPEN', 'MERGED' and 'CLOSED'. You can check out the original status from the field `original_status`\nselect\n author_name,\n\tcount(*) as merged_pull_request_count\nfrom \n\tpull_requests pr\nwhere\n $__timeFilter(created_date)\n\tand base_repo_id in ($repo_id)\n\tand pr.status = 'MERGED'\ngroup by 1\norder by 2 desc\nlimit 20\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "1.3 Top Contributors By Merged PRs", + "type": "barchart" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 85, + "panels": [], + "title": "2. How PRs are handled?", + "type": "row" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 17 + }, + "id": 66, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "-- The PR/MR statuses are standardized to DevLake's statuses 'OPEN', 'MERGED' and 'CLOSED'. You can check out the original status from the field `original_status`\nselect\n count(distinct case when status = 'CLOSED' then id else null end)/count(distinct case when status in ('CLOSED', 'MERGED') then id else null end) as ratio\nfrom \n\tpull_requests pr\nwhere\n $__timeFilter(created_date)\n\tand base_repo_id in ($repo_id)", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "2.1 Ratio of Non-merging Pull Requests of All Closed or Merged PRs", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Pull Request Count", + "axisPlacement": "auto", + "barAlignment": 1, + "drawStyle": "bars", + "fillOpacity": 50, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 18, + "x": 6, + "y": 17 + }, + "id": 79, + "options": { + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "-- The PR/MR statuses are standardized to DevLake's statuses 'OPEN', 'MERGED' and 'CLOSED'. You can check out the original status from the field `original_status`\nSELECT\n DATE_ADD(date(created_date), INTERVAL -DAYOFMONTH(date(created_date))+1 DAY) as time,\n count(distinct case when status = 'OPEN' then id else null end) as \"PR: Open\",\n count(distinct case when status = 'CLOSED' then id else null end) as \"PR: Closed without merging\",\n count(distinct case when status = 'MERGED' then id else null end) as \"PR: Merged\"\nFROM pull_requests\nWHERE\n $__timeFilter(created_date)\n and base_repo_id in ($repo_id)\ngroup by 1\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "2.2 Pull Request Status Distribution [Each Month]", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 23 + }, + "id": 80, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "-- The PR/MR statuses are standardized to DevLake's statuses 'OPEN', 'MERGED' and 'CLOSED'. You can check out the original status from the field `original_status`\nselect\n\tcount(*) as merged_pull_request_count\nfrom \n\tpull_requests pr\nwhere\n $__timeFilter(created_date)\n\tand base_repo_id in ($repo_id)\n\tand pr.status = 'CLOSED'", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "2.3 Number of Pull Requests Closed without Merging [Selected Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Ratio", + "axisPlacement": "auto", + "barAlignment": 1, + "drawStyle": "line", + "fillOpacity": 50, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineStyle": { + "fill": "solid" + }, + "lineWidth": 1, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 18, + "x": 6, + "y": 23 + }, + "id": 81, + "options": { + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "-- The PR/MR statuses are standardized to DevLake's statuses 'OPEN', 'MERGED' and 'CLOSED'. You can check out the original status from the field `original_status`\nSELECT\n DATE_ADD(date(created_date), INTERVAL -DAYOFMONTH(date(created_date))+1 DAY) as time,\n count(distinct case when status = 'CLOSED' then id else null end)/count(distinct case when status in ('CLOSED', 'MERGED') then id else null end) as ratio\nFROM pull_requests\nWHERE\n $__timeFilter(created_date)\n and base_repo_id in ($repo_id)\ngroup by 1\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "2.4 Ratio of Non-merging PRs of All Closed or Merged PRs [Each Month]", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 29 + }, + "id": 72, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select\n\tavg(TIMESTAMPDIFF(Minute,created_date,merged_date)/1440)\nfrom \n\tpull_requests\nwhere \n $__timeFilter(created_date)\n\tand base_repo_id in ($repo_id)\n\tand merged_date is not null\n\n\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "2.5 Mean Time to Merge of Pull Requests in Days [Selected Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 18, + "x": 6, + "y": 29 + }, + "id": 95, + "options": { + "barWidth": 0.5, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _prs as(\n SELECT\n DATE_ADD(date(created_date), INTERVAL -DAY(date(created_date))+1 DAY) as time,\n avg(TIMESTAMPDIFF(Minute,created_date,merged_date)/1440) as time_to_merge\n FROM pull_requests\n WHERE\n $__timeFilter(created_date)\n and base_repo_id in ($repo_id)\n and created_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\n group by 1\n)\n\nSELECT \n date_format(time,'%M %Y') as month,\n time_to_merge as \"Time to Merge\"\nFROM _prs\nORDER BY time\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "2.6 Mean Time to Merge of Pull Requests in Days [Each Month]", + "type": "barchart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 35 + }, + "id": 96, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "-- The PR/MR statuses are standardized to DevLake's statuses 'OPEN', 'MERGED' and 'CLOSED'. You can check out the original status from the field `original_status`\nselect\n\tavg(TIMESTAMPDIFF(Minute,created_date,closed_date)/1440) as time_to_close\nfrom \n\tpull_requests\nwhere \n $__timeFilter(created_date)\n\tand base_repo_id in ($repo_id)\n\tand status in ('CLOSED', 'MERGED')\n\n\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "2.7 Mean Time to Close of Pull Requests in Days [Selected Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 18, + "x": 6, + "y": 35 + }, + "id": 97, + "options": { + "barWidth": 0.5, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "-- The PR/MR statuses are standardized to DevLake's statuses 'OPEN', 'MERGED' and 'CLOSED'. You can check out the original status from the field `original_status`\nwith _prs as(\n SELECT\n DATE_ADD(date(created_date), INTERVAL -DAY(date(created_date))+1 DAY) as time,\n avg(TIMESTAMPDIFF(Minute,created_date,closed_date)/1440) as time_to_close\n FROM pull_requests\n WHERE\n $__timeFilter(created_date)\n and base_repo_id in ($repo_id)\n and status in ('CLOSED', 'MERGED')\n and created_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\n group by 1\n)\n\nSELECT \n date_format(time,'%M %Y') as month,\n time_to_close as \"Time to Close\"\nFROM _prs\nORDER BY time\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "2.8 Mean Time to Close of Pull Requests in Days [Each Month]", + "type": "barchart" + }, + { + "datasource": null, + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 41 + }, + "id": 99, + "options": { + "content": "
\n\nThis dashboard is created based on this [data schema](https://devlake.apache.org/docs/DataModels/DevLakeDomainLayerSchema). Want to add more metrics? Please follow the [guide](https://devlake.apache.org/docs/Configuration/Dashboards/GrafanaUserGuide).", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + } + ], + "refresh": "", + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": "", + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": "mysql", + "definition": "select concat(name, '--', id) as text from repos where id like 'gitlab%'", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Repo", + "multi": true, + "name": "repo_id", + "options": [], + "query": "select concat(name, '--', id) as text from repos where id like 'gitlab%'", + "refresh": 1, + "regex": "/^(?.*)--(?.*)$/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-6M", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "GitLab", + "uid": "msSjEq97z", + "version": 8 +} \ No newline at end of file diff --git a/charts/devlake/dashboards/Homepage.json b/charts/devlake/dashboards/Homepage.json new file mode 100644 index 0000000..8e261f2 --- /dev/null +++ b/charts/devlake/dashboards/Homepage.json @@ -0,0 +1,1039 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 23, + "links": [], + "panels": [ + { + "datasource": null, + "gridPos": { + "h": 7, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 32, + "options": { + "content": "# Welcome to Apache DevLake\n\n - DevLake provides following dashboards, grouped by use cases and data sources.\n - The data displayed in these dashboards are queried from DevLake's domain layer data, see [schema](https://devlake.apache.org/docs/DataModels/DevLakeDomainLayerSchema).\n - You can also make your own dashboard based on the [domain layer schema](https://devlake.apache.org/docs/DataModels/DevLakeDomainLayerSchema), the SQL exmaples of [engineering metrics](https://devlake.apache.org/docs/Metrics), and [Grafana manuals](https://devlake.apache.org/docs/Configuration/Dashboards/GrafanaUserGuide).\n - Feel free to [fire an issue](https://github.com/apache/incubator-devlake/issues/new/choose) if you have any question.", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + }, + { + "datasource": null, + "gridPos": { + "h": 7, + "w": 6, + "x": 12, + "y": 0 + }, + "id": 22, + "options": { + "folderId": 0, + "maxItems": 10, + "query": "", + "showHeadings": false, + "showRecentlyViewed": false, + "showSearch": false, + "showStarred": true, + "tags": [] + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "title": "Starred Dashboards", + "type": "dashlist" + }, + { + "datasource": null, + "gridPos": { + "h": 7, + "w": 6, + "x": 18, + "y": 0 + }, + "id": 2, + "options": { + "folderId": 0, + "maxItems": 50, + "query": "", + "showHeadings": false, + "showRecentlyViewed": false, + "showSearch": true, + "showStarred": false, + "tags": [] + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "title": "All Dashboards", + "type": "dashlist" + }, + { + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 7 + }, + "id": 10, + "title": "For Engineering Leads", + "type": "row" + }, + { + "cacheTimeout": null, + "datasource": null, + "gridPos": { + "h": 5, + "w": 6, + "x": 0, + "y": 8 + }, + "id": 6, + "interval": null, + "links": [], + "options": { + "content": "\n
\n

DORA

\n
\n
", + "mode": "html" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": false, + "rawSql": "SELECT\n create_time AS \"time\",\n progress\nFROM ca_analysis\nWHERE\n $__timeFilter(create_time)\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "type": "text" + }, + { + "cacheTimeout": null, + "datasource": null, + "gridPos": { + "h": 5, + "w": 6, + "x": 6, + "y": 8 + }, + "id": 20, + "interval": null, + "links": [], + "options": { + "content": "\n
\n

Engineering Overview

\n
\n
", + "mode": "html" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": false, + "rawSql": "SELECT\n create_time AS \"time\",\n progress\nFROM ca_analysis\nWHERE\n $__timeFilter(create_time)\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "type": "text" + }, + { + "cacheTimeout": null, + "datasource": null, + "gridPos": { + "h": 5, + "w": 6, + "x": 12, + "y": 8 + }, + "id": 18, + "interval": null, + "links": [], + "options": { + "content": "\n
\n

Engineering Throughput and Cycle Time

\n
\n
", + "mode": "html" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": false, + "rawSql": "SELECT\n create_time AS \"time\",\n progress\nFROM ca_analysis\nWHERE\n $__timeFilter(create_time)\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "type": "text" + }, + { + "cacheTimeout": null, + "datasource": null, + "gridPos": { + "h": 5, + "w": 6, + "x": 18, + "y": 8 + }, + "id": 19, + "interval": null, + "links": [], + "options": { + "content": "\n
\n

Engineering Throughput and Cycle Time - Team View

\n

(Team Configuration Required)

\n
\n
", + "mode": "html" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": false, + "rawSql": "SELECT\n create_time AS \"time\",\n progress\nFROM ca_analysis\nWHERE\n $__timeFilter(create_time)\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "type": "text" + }, + { + "cacheTimeout": null, + "datasource": null, + "gridPos": { + "h": 5, + "w": 6, + "x": 0, + "y": 13 + }, + "id": 17, + "interval": null, + "links": [], + "options": { + "content": "\n
\n

Component and File-level Metrics

\n
\n
", + "mode": "html" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": false, + "rawSql": "SELECT\n create_time AS \"time\",\n progress\nFROM ca_analysis\nWHERE\n $__timeFilter(create_time)\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "type": "text" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 18 + }, + "id": 12, + "panels": [], + "title": "For OSS Maintainers", + "type": "row" + }, + { + "cacheTimeout": null, + "datasource": null, + "gridPos": { + "h": 5, + "w": 6, + "x": 0, + "y": 19 + }, + "id": 8, + "interval": null, + "links": [], + "options": { + "content": "\n
\n

Weekly Community Retro

\n
\n
", + "mode": "html" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": false, + "rawSql": "SELECT\n create_time AS \"time\",\n progress\nFROM ca_analysis\nWHERE\n $__timeFilter(create_time)\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "type": "text" + }, + { + "cacheTimeout": null, + "datasource": null, + "gridPos": { + "h": 5, + "w": 6, + "x": 6, + "y": 19 + }, + "id": 21, + "interval": null, + "links": [], + "options": { + "content": "\n
\n

Contributor Experience

\n
\n
", + "mode": "html" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": false, + "rawSql": "SELECT\n create_time AS \"time\",\n progress\nFROM ca_analysis\nWHERE\n $__timeFilter(create_time)\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "type": "text" + }, + { + "cacheTimeout": null, + "datasource": null, + "gridPos": { + "h": 5, + "w": 6, + "x": 12, + "y": 19 + }, + "id": 23, + "interval": null, + "links": [], + "options": { + "content": "\n
\n

GitHub Release Quality and Contribution Analysis

\n
\n
", + "mode": "html" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": false, + "rawSql": "SELECT\n create_time AS \"time\",\n progress\nFROM ca_analysis\nWHERE\n $__timeFilter(create_time)\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "type": "text" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 24 + }, + "id": 16, + "panels": [], + "title": "For QA Engineers", + "type": "row" + }, + { + "cacheTimeout": null, + "datasource": null, + "gridPos": { + "h": 5, + "w": 6, + "x": 0, + "y": 25 + }, + "id": 24, + "interval": null, + "links": [], + "options": { + "content": "\n
\n

Weekly Bug Retro

\n
\n
", + "mode": "html" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": false, + "rawSql": "SELECT\n create_time AS \"time\",\n progress\nFROM ca_analysis\nWHERE\n $__timeFilter(create_time)\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "type": "text" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 30 + }, + "id": 14, + "panels": [], + "title": "By Data Sources", + "type": "row" + }, + { + "cacheTimeout": null, + "datasource": null, + "gridPos": { + "h": 5, + "w": 6, + "x": 0, + "y": 31 + }, + "id": 25, + "interval": null, + "links": [], + "options": { + "content": "\n
\n

Jira

\n
\n
", + "mode": "html" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": false, + "rawSql": "SELECT\n create_time AS \"time\",\n progress\nFROM ca_analysis\nWHERE\n $__timeFilter(create_time)\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "type": "text" + }, + { + "cacheTimeout": null, + "datasource": null, + "gridPos": { + "h": 5, + "w": 6, + "x": 6, + "y": 31 + }, + "id": 28, + "interval": null, + "links": [], + "options": { + "content": "\n
\n

GitHub

\n
\n
", + "mode": "html" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": false, + "rawSql": "SELECT\n create_time AS \"time\",\n progress\nFROM ca_analysis\nWHERE\n $__timeFilter(create_time)\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "type": "text" + }, + { + "cacheTimeout": null, + "datasource": null, + "gridPos": { + "h": 5, + "w": 6, + "x": 12, + "y": 31 + }, + "id": 29, + "interval": null, + "links": [], + "options": { + "content": "\n
\n

GitLab

\n
\n
", + "mode": "html" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": false, + "rawSql": "SELECT\n create_time AS \"time\",\n progress\nFROM ca_analysis\nWHERE\n $__timeFilter(create_time)\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "type": "text" + }, + { + "cacheTimeout": null, + "datasource": null, + "gridPos": { + "h": 5, + "w": 6, + "x": 18, + "y": 31 + }, + "id": 36, + "interval": null, + "links": [], + "options": { + "content": "\n
\n

BitBucket Cloud

\n
\n
", + "mode": "html" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": false, + "rawSql": "SELECT\n create_time AS \"time\",\n progress\nFROM ca_analysis\nWHERE\n $__timeFilter(create_time)\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "type": "text" + }, + { + "cacheTimeout": null, + "datasource": null, + "gridPos": { + "h": 5, + "w": 6, + "x": 0, + "y": 36 + }, + "id": 35, + "interval": null, + "links": [], + "options": { + "content": "\n
\n

SonarQube

\n
\n
", + "mode": "html" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": false, + "rawSql": "SELECT\n create_time AS \"time\",\n progress\nFROM ca_analysis\nWHERE\n $__timeFilter(create_time)\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "type": "text" + }, + { + "cacheTimeout": null, + "datasource": null, + "gridPos": { + "h": 5, + "w": 6, + "x": 6, + "y": 36 + }, + "id": 30, + "interval": null, + "links": [], + "options": { + "content": "\n
\n

Jenkins

\n
\n
", + "mode": "html" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": false, + "rawSql": "SELECT\n create_time AS \"time\",\n progress\nFROM ca_analysis\nWHERE\n $__timeFilter(create_time)\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "type": "text" + }, + { + "cacheTimeout": null, + "datasource": null, + "gridPos": { + "h": 5, + "w": 6, + "x": 12, + "y": 36 + }, + "id": 33, + "interval": null, + "links": [], + "options": { + "content": "\n
\n

TAPD

\n
\n
", + "mode": "html" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": false, + "rawSql": "SELECT\n create_time AS \"time\",\n progress\nFROM ca_analysis\nWHERE\n $__timeFilter(create_time)\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "type": "text" + }, + { + "cacheTimeout": null, + "datasource": null, + "gridPos": { + "h": 5, + "w": 6, + "x": 18, + "y": 36 + }, + "id": 34, + "interval": null, + "links": [], + "options": { + "content": "\n
\n

Zentao

\n
\n
", + "mode": "html" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": false, + "rawSql": "SELECT\n create_time AS \"time\",\n progress\nFROM ca_analysis\nWHERE\n $__timeFilter(create_time)\nORDER BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "type": "text" + } + ], + "refresh": "", + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Homepage", + "uid": "lCO8w-pVk", + "version": 8 +} \ No newline at end of file diff --git a/charts/devlake/dashboards/Jenkins.json b/charts/devlake/dashboards/Jenkins.json new file mode 100644 index 0000000..f2fc391 --- /dev/null +++ b/charts/devlake/dashboards/Jenkins.json @@ -0,0 +1,975 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 6, + "iteration": 1683624526469, + "links": [], + "panels": [ + { + "datasource": null, + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 58, + "options": { + "content": "- Use Cases: This dashboard shows the basic CI/CD metrics from Jenkins, such as [Build Count](https://devlake.apache.org/docs/Metrics/BuildCount), [Build Duration](https://devlake.apache.org/docs/Metrics/BuildDuration) and [Build Success Rate](https://devlake.apache.org/docs/Metrics/BuildSuccessRate).\n- Data Source Required: Jenkins", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "title": "Dashboard Introduction", + "type": "text" + }, + { + "datasource": "mysql", + "description": "Number of builds executed in the selected time range", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 3 + }, + "id": 4, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n count(*)\nFROM \n cicd_pipelines\nWHERE\n $__timeFilter(finished_date)\n and result = 'SUCCESS'\n and id like \"%jenkins%\"\n and cicd_scope_id in ($job_id)\n -- the following condition will remove the month with incomplete data\n and finished_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)", + "refId": "A", + "select": [ + [ + { + "params": [ + "project_id" + ], + "type": "column" + } + ] + ], + "table": "gitlab_commits", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "1. Total Number of Successful Builds [Selected Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "Number of successful builds / Number of total builds", + "fieldConfig": { + "defaults": { + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 6, + "y": 3 + }, + "id": 6, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n 1.0 * count(case when result = 'SUCCESS' then 1 else null end)/count(*)\nFROM cicd_pipelines\nWHERE\n $__timeFilter(finished_date)\n and id like \"%jenkins%\"\n and cicd_scope_id in ($job_id)\n -- the following condition will remove the month with incomplete data\n and finished_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)", + "refId": "A", + "select": [ + [ + { + "params": [ + "project_id" + ], + "type": "column" + } + ] + ], + "table": "gitlab_commits", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "2. Mean Build Success Rate", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "decimals": 0, + "mappings": [], + "unit": "none" + }, + "overrides": [ + { + "__systemRef": "hideSeriesFrom", + "matcher": { + "id": "byNames", + "options": { + "mode": "exclude", + "names": [ + "build_count", + "ABORT" + ], + "prefix": "All except:", + "readOnly": true + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": false, + "tooltip": false, + "viz": true + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "SUCCESS" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "FAILURE" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "ABORT" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "rgba(205, 204, 206, 1)", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 12, + "y": 3 + }, + "id": 37, + "interval": null, + "links": [], + "options": { + "displayLabels": [ + "value", + "percent" + ], + "legend": { + "calcs": [], + "displayMode": "table", + "placement": "right", + "values": [ + "percent", + "value" + ] + }, + "pieType": "donut", + "reduceOptions": { + "calcs": [ + "sum" + ], + "fields": "", + "values": true + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n result,\n count(*) as build_count\nFROM cicd_pipelines\nWHERE\n $__timeFilter(finished_date)\n and id like \"%jenkins%\"\n and cicd_scope_id in ($job_id)\n -- the following condition will remove the month with incomplete data\n and finished_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\nGROUP BY 1\nORDER BY 2 desc", + "refId": "A", + "select": [ + [ + { + "params": [ + "project_id" + ], + "type": "column" + } + ] + ], + "table": "gitlab_commits", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "3. Total Build Result Distribution", + "type": "piechart" + }, + { + "datasource": "mysql", + "description": "Number of successful builds / Number of total builds", + "fieldConfig": { + "defaults": { + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "light-orange", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 18, + "y": 3 + }, + "id": 55, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n avg(duration_sec/60) as duration_in_minutes\nFROM cicd_pipelines\nWHERE\n $__timeFilter(finished_date)\n and id like \"%jenkins%\"\n and cicd_scope_id in ($job_id)\n -- the following condition will remove the month with incomplete data\n and finished_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)", + "refId": "A", + "select": [ + [ + { + "params": [ + "project_id" + ], + "type": "column" + } + ] + ], + "table": "gitlab_commits", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "4. Mean Build Duration in Minutes", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Build Count", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 9 + }, + "id": 52, + "options": { + "barWidth": 0.5, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH _builds as(\n SELECT\n DATE_ADD(date(finished_date), INTERVAL -DAYOFMONTH(date(finished_date))+1 DAY) as time,\n count(*) as build_count\n FROM cicd_pipelines\n WHERE\n $__timeFilter(finished_date)\n and result = 'SUCCESS'\n and id like \"%jenkins%\"\n and cicd_scope_id in ($job_id)\n -- the following condition will remove the month with incomplete data\n and finished_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\n GROUP BY 1\n)\n\nSELECT \n date_format(time,'%M %Y') as month,\n build_count as \"Build Count\"\nFROM _builds\nORDER BY time\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "1.1 Total Number of Successful Builds [Each Month]", + "type": "barchart" + }, + { + "datasource": "mysql", + "description": "1. Mean Build success rate over time.\n2. The builds being calculated are filtered by \"build starting time\" (time filter at the upper-right corner) and \"Jira board\" (\"Choose Board\" filter at the upper-left corner)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Build Success Rate(%)", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Build Success Rate" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "blue", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 9 + }, + "id": 50, + "interval": "", + "options": { + "barWidth": 0.5, + "groupWidth": 0.7, + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH _build_success_rate as(\r\n SELECT\r\n DATE_ADD(date(finished_date), INTERVAL -DAYOFMONTH(date(finished_date))+1 DAY) as time,\r\n result\r\n FROM\r\n cicd_pipelines\r\n WHERE\r\n $__timeFilter(finished_date)\r\n and id like \"%jenkins%\"\r\n and cicd_scope_id in ($job_id)\r\n -- the following condition will remove the month with incomplete data\r\n and finished_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\r\n)\r\n\r\nSELECT \r\n date_format(time,'%M %Y') as month,\r\n 1.0 * sum(case when result = 'SUCCESS' then 1 else 0 end)/ count(*) as \"Build Success Rate\"\r\nFROM _build_success_rate\r\nGROUP BY time\r\nORDER BY time", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "2.1 Build Success Rate [Each Month]", + "type": "barchart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "fixed" + }, + "custom": { + "axisLabel": "Build Count", + "axisPlacement": "auto", + "barAlignment": 1, + "drawStyle": "bars", + "fillOpacity": 50, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "successful_build_count" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "green", + "mode": "fixed" + } + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "failed_build_count" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 15 + }, + "id": 54, + "options": { + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "SELECT\n DATE_ADD(date(finished_date), INTERVAL -DAYOFMONTH(date(finished_date))+1 DAY) as time,\n count(distinct case when result = 'SUCCESS' then id else null end) as successful_build_count,\n count(distinct case when result != 'SUCCESS' then id else null end) as failed_build_count\nFROM cicd_pipelines\nWHERE\n $__timeFilter(finished_date)\n and id like \"%jenkins%\"\n and cicd_scope_id in ($job_id)\n -- the following condition will remove the month with incomplete data\n and finished_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\nGROUP BY 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "3.1 Number of Successful and Failed Builds [Each Month]", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Build Duration(minutes)", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "purple", + "value": null + }, + { + "color": "red", + "value": 60 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "mean_duration_minutes" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "light-orange", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 21 + }, + "id": 56, + "options": { + "barWidth": 0.5, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "WITH _builds as(\n SELECT\n DATE_ADD(date(finished_date), INTERVAL -DAYOFMONTH(date(finished_date))+1 DAY) as time,\n avg(duration_sec) as mean_duration_sec\n FROM \n cicd_pipelines\n WHERE\n $__timeFilter(finished_date)\n and id like \"%jenkins%\"\n and cicd_scope_id in ($job_id)\n -- the following condition will remove the month with incomplete data\n and finished_date >= DATE_ADD(DATE_ADD($__timeFrom(), INTERVAL -DAY($__timeFrom())+1 DAY), INTERVAL +1 MONTH)\n GROUP BY 1\n)\n\nSELECT \n date_format(time,'%M %Y') as month,\n mean_duration_sec/60 as mean_duration_minutes\nFROM _builds\nORDER BY time\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "4.1 Mean Build Duration in Minutes [Each Month]", + "type": "barchart" + }, + { + "datasource": null, + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 60, + "options": { + "content": "
\n\nThis dashboard is created based on this [data schema](https://devlake.apache.org/docs/DataModels/DevLakeDomainLayerSchema). Want to add more metrics? Please follow the [guide](https://devlake.apache.org/docs/Configuration/Dashboards/GrafanaUserGuide).", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + } + ], + "refresh": "", + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": "mysql", + "definition": "select distinct cicd_scope_id as text from cicd_pipelines where id like \"%jenkins%\" ", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Job Name", + "multi": true, + "name": "job_id", + "options": [], + "query": "select distinct cicd_scope_id as text from cicd_pipelines where id like \"%jenkins%\" ", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-6M", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Jenkins", + "uid": "W8AiDFQnk", + "version": 2 +} \ No newline at end of file diff --git a/charts/devlake/dashboards/Jira.json b/charts/devlake/dashboards/Jira.json new file mode 100644 index 0000000..ed53692a --- /dev/null +++ b/charts/devlake/dashboards/Jira.json @@ -0,0 +1,1031 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 14, + "iteration": 1682063040196, + "links": [ + { + "asDropdown": false, + "icon": "bolt", + "includeVars": false, + "keepTime": true, + "tags": [], + "targetBlank": false, + "title": "Homepage", + "tooltip": "", + "type": "link", + "url": "/grafana/d/Lv1XbLHnk/data-specific-dashboards-homepage" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": true, + "tags": [ + "Data Source Specific Dashboard" + ], + "targetBlank": false, + "title": "Metric dashboards", + "tooltip": "", + "type": "dashboards", + "url": "" + } + ], + "panels": [ + { + "datasource": null, + "gridPos": { + "h": 3, + "w": 13, + "x": 0, + "y": 0 + }, + "id": 128, + "options": { + "content": "- Use Cases: This dashboard shows the basic project management metrics from Jira.\n- Data Source Required: Jira", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "title": "Dashboard Introduction", + "type": "text" + }, + { + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 3 + }, + "id": 126, + "title": "1. Issue Throughput", + "type": "row" + }, + { + "datasource": "mysql", + "description": "1. Total number of issues created.\n2. The requirements being calculated are filtered by \"requirement creation time\" (time filter at the upper-right corner) and \"Jira board\" (\"Choose Board\" filter at the upper-left corner)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 0, + "y": 4 + }, + "id": 114, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select \r\n count(*) as value\r\nfrom issues i\r\n join board_issues bi on i.id = bi.issue_id\r\nwhere \r\n i.type in ($type)\r\n and $__timeFilter(i.created_date)\r\n and bi.board_id in ($board_id)", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Number of Issues [Issues Created in Selected Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 4, + "y": 4 + }, + "id": 116, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select \r\n count(*) as value\r\nfrom issues i\r\n join board_issues bi on i.id = bi.issue_id\r\nwhere \r\n i.type in ($type)\r\n and i.status = 'DONE'\r\n and $__timeFilter(i.created_date)\r\n and bi.board_id in ($board_id)", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Number of Delivered Issue [Issues Created in Selected Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 1, + "drawStyle": "bars", + "fillOpacity": 12, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 16, + "x": 8, + "y": 4 + }, + "id": 120, + "interval": null, + "options": { + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "SELECT\r\n DATE_ADD(date(i.created_date), INTERVAL -DAYOFMONTH(date(i.created_date))+1 DAY) as time,\r\n count(distinct case when status != 'DONE' then i.id else null end) as \"Number of Open Issues\",\r\n count(distinct case when status = 'DONE' then i.id else null end) as \"Number of Delivered Issues\"\r\nFROM issues i\r\n\tjoin board_issues bi on i.id = bi.issue_id\r\n\tjoin boards b on bi.board_id = b.id\r\nwhere \r\n i.type in ($type)\r\n and $__timeFilter(i.created_date)\r\n and bi.board_id in ($board_id)\r\ngroup by 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Issue Status Distribution over Month [Issues Created in Selected Time Range]", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "Issue Delivery Rate = count(Delivered Issues)/count(Issues)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 50 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 10 + }, + "id": 117, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with _requirements as(\r\n select\r\n count(distinct i.id) as total_count,\r\n count(distinct case when i.status = 'DONE' then i.id else null end) as delivered_count\r\n from issues i\r\n join board_issues bi on i.id = bi.issue_id\r\n where \r\n i.type in ($type)\r\n and $__timeFilter(i.created_date)\r\n and bi.board_id in ($board_id)\r\n)\r\n\r\nselect \r\n now() as time,\r\n 1.0 * delivered_count/total_count as requirement_delivery_rate\r\nfrom _requirements", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Issue Delivery Rate [Issues Created in Selected Time Range]", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "mysql", + "description": "Issue Delivery Rate = count(Delivered Issues)/count(Issues)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Delivery Rate(%)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 16, + "x": 8, + "y": 10 + }, + "id": 121, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with _requirements as(\r\n select\r\n DATE_ADD(date(i.created_date), INTERVAL -DAYOFMONTH(date(i.created_date))+1 DAY) as time,\r\n 1.0 * count(distinct case when i.status = 'DONE' then i.id else null end)/count(distinct i.id) as delivered_rate\r\n from issues i\r\n join board_issues bi on i.id = bi.issue_id\r\n where \r\n i.type in ($type)\r\n and $__timeFilter(i.created_date)\r\n and bi.board_id in ($board_id)\r\n group by 1\r\n)\r\n\r\nselect\r\n time,\r\n delivered_rate\r\nfrom _requirements\r\norder by time", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Issue Delivery Rate over Time [Issues Created in Selected Time Range]", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 110, + "panels": [], + "title": "2. Issue Lead Time", + "type": "row" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 14 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 0, + "y": 17 + }, + "id": 12, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "/^value$/", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select \r\n avg(lead_time_minutes/1440) as value\r\nfrom issues i\r\n join board_issues bi on i.id = bi.issue_id\r\nwhere \r\n i.type in ($type)\r\n and i.status = 'DONE'\r\n and $__timeFilter(i.resolution_date)\r\n and bi.board_id in ($board_id)", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Mean Issue Lead Time in Days [Issues Resolved in Select Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 21 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 4, + "y": 17 + }, + "id": 13, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _ranks as(\r\n select \r\n i.lead_time_minutes,\r\n percent_rank() over (order by lead_time_minutes asc) as ranks\r\n from issues i\r\n join board_issues bi on i.id = bi.issue_id\r\n where \r\n i.type in ($type)\r\n and i.status = 'DONE'\r\n and $__timeFilter(i.resolution_date)\r\n and bi.board_id in ($board_id)\r\n)\r\n\r\nselect\r\n max(lead_time_minutes/1440) as value\r\nfrom _ranks\r\nwhere \r\n ranks <= 0.8", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "80% Issues' Lead Time are less than # days [Issues Resolved in Select Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Lead Time(days)", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 16, + "x": 8, + "y": 17 + }, + "id": 17, + "interval": "", + "options": { + "barWidth": 0.5, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _requirements as(\r\n select \r\n DATE_ADD(date(i.resolution_date), INTERVAL -DAYOFMONTH(date(i.resolution_date))+1 DAY) as time,\r\n avg(lead_time_minutes/1440) as mean_lead_time\r\n from issues i\r\n join board_issues bi on i.id = bi.issue_id\r\n where \r\n i.type in ($type)\r\n and i.status = 'DONE'\r\n and $__timeFilter(i.resolution_date)\r\n and bi.board_id in ($board_id)\r\n group by 1\r\n)\r\n\r\nselect \r\n date_format(time,'%M %Y') as month,\r\n mean_lead_time\r\nfrom _requirements\r\norder by time asc", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Mean Issue Lead Time [Issues Resolved in Select Time Range]", + "type": "barchart" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "mysql", + "description": "1. The cumulative distribution of requirement lead time. \n2. Each point refers to the percent rank of a lead time.", + "fill": 0, + "fillGradient": 4, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 23 + }, + "hiddenSeries": false, + "id": 15, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 8, + "nullPointMode": "null", + "options": { + "alertThreshold": false + }, + "percentage": false, + "pluginVersion": "8.0.6", + "pointradius": 0.5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _ranks as(\r\n select \r\n round(i.lead_time_minutes/1440) as lead_time_day\r\n from issues i\r\n join board_issues bi on i.id = bi.issue_id\r\n where \r\n i.type in ($type)\r\n and i.status = 'DONE'\r\n and $__timeFilter(i.resolution_date)\r\n and bi.board_id in ($board_id)\r\n order by lead_time_day asc\r\n)\r\n\r\nselect \r\n now() as time,\r\n lpad(concat(lead_time_day,'d'), 4, ' ') as metric,\r\n percent_rank() over (order by lead_time_day asc) as value\r\nfrom _ranks\r\norder by lead_time_day asc", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "thresholds": [ + { + "$$hashKey": "object:469", + "colorMode": "ok", + "fill": true, + "line": true, + "op": "lt", + "value": 0.8, + "yaxis": "right" + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Cumulative Distribution of Requirement Lead Time [Issues Resolved in Select Time Range]", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "transformations": [], + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "series", + "name": null, + "show": true, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "$$hashKey": "object:76", + "format": "percentunit", + "label": "Percent Rank (%)", + "logBase": 1, + "max": "1.2", + "min": null, + "show": true + }, + { + "$$hashKey": "object:77", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "datasource": null, + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 29 + }, + "id": 130, + "options": { + "content": "
\n\nThis dashboard is created based on this [data schema](https://devlake.apache.org/docs/DataModels/DevLakeDomainLayerSchema). Want to add more metrics? Please follow the [guide](https://devlake.apache.org/docs/Configuration/Dashboards/GrafanaUserGuide).", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + } + ], + "refresh": "", + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": "mysql", + "definition": "select concat(name, '--', id) from boards where id like 'jira%'", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Choose Board", + "multi": true, + "name": "board_id", + "options": [], + "query": "select concat(name, '--', id) from boards where id like 'jira%'", + "refresh": 1, + "regex": "/^(?.*)--(?.*)$/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "allValue": null, + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "mysql", + "definition": "select distinct type from issues", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Issue Type", + "multi": false, + "name": "type", + "options": [], + "query": "select distinct type from issues", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-6M", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Jira", + "uid": "F5vqBQl7z", + "version": 3 +} \ No newline at end of file diff --git a/charts/devlake/dashboards/Sonarqube.json b/charts/devlake/dashboards/Sonarqube.json new file mode 100644 index 0000000..f411f64 --- /dev/null +++ b/charts/devlake/dashboards/Sonarqube.json @@ -0,0 +1,1058 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 29, + "iteration": 1682063057579, + "links": [], + "panels": [ + { + "datasource": null, + "gridPos": { + "h": 3, + "w": 13, + "x": 0, + "y": 0 + }, + "id": 19, + "options": { + "content": "- Use Cases: This dashboard shows the code quality metrics from SonarQube.\n- Data Source Required: SonarQube v8.2+", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "title": "Dashboard Introduction", + "type": "text" + }, + { + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 3 + }, + "id": 16, + "title": "Reliability & Security", + "type": "row" + }, + { + "datasource": "-- Mixed --", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "bugs" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 4 + }, + "id": 2, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "center", + "orientation": "vertical", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/.*/", + "values": false + }, + "text": {}, + "textMode": "value" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "datasource": "mysql", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "SELECT\n count(*) as 'Bugs'\nFROM cq_issues\nWHERE\n $__timeFilter(created_date)\n and project_key in ($project_id)\n and `type` = 'BUG'\nORDER BY created_date", + "refId": "A", + "select": [ + [ + { + "params": [ + "blueprint_id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprint_labels", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Reliability", + "type": "stat" + }, + { + "datasource": "-- Mixed --", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "vulnerabilities" + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 6, + "y": 4 + }, + "id": 3, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "value" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "datasource": "mysql", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "SELECT\n count(*) as 'Vulnerabilities'\nFROM cq_issues\nWHERE\n $__timeFilter(created_date)\n and project_key in ($project_id)\n and `type` = 'VULNERABILITY'\nORDER BY created_date", + "refId": "A", + "select": [ + [ + { + "params": [ + "blueprint_id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprint_labels", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Security", + "type": "stat" + }, + { + "datasource": "-- Mixed --", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 4 + }, + "id": 4, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/.*/", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "datasource": "mysql", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "SELECT\n COUNT(IF(status = 'TO_REVIEW', 1, NULL)) AS 'Security Hotspots'\nFROM cq_issues\nWHERE\n $__timeFilter(created_date)\n and project_key in ($project_id)\n and `type` = 'HOTSPOTS'\nORDER BY created_date", + "refId": "A", + "select": [ + [ + { + "params": [ + "blueprint_id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprint_labels", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Security Hotspots", + "type": "stat" + }, + { + "datasource": "-- Mixed --", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 4 + }, + "id": 13, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/.*/", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "datasource": "mysql", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "SELECT\n CONCAT(ROUND(COUNT(IF(status != 'TO_REVIEW', 1, NULL)) / COUNT(*) * 100, 2), '%') AS 'Reviewed'\nFROM cq_issues\nWHERE\n $__timeFilter(created_date)\n and project_key in ($project_id)\n and `type` = 'HOTSPOTS'\nORDER BY created_date", + "refId": "A", + "select": [ + [ + { + "params": [ + "blueprint_id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprint_labels", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Security Reviewed", + "type": "stat" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 8 + }, + "id": 12, + "panels": [], + "title": "Test & Maintainability", + "type": "row" + }, + { + "datasource": "-- Mixed --", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 0, + "y": 9 + }, + "id": 8, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/.*/", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "datasource": "mysql", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "SELECT\n CONCAT(ROUND((sum(lines_to_cover) - sum(uncovered_lines)) / sum(lines_to_cover) * 100, 1), '% ', 'Coverage on ', ROUND(sum(lines_to_cover) / 1000, 0),'k Lines to cover')\nFROM cq_file_metrics\nWHERE\n project_key in ($project_id)\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "blueprint_id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprint_labels", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Test", + "type": "stat" + }, + { + "datasource": "-- Mixed --", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 6, + "y": 9 + }, + "id": 7, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/.*/", + "values": false + }, + "text": {}, + "textMode": "value" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "datasource": "mysql", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "SELECT\n CONCAT(ROUND(SUM(debt) / (8 * 60), 0), ' days') AS 'Debt'\nFROM cq_issues\nWHERE\n $__timeFilter(created_date)\n and project_key in ($project_id)", + "refId": "A", + "select": [ + [ + { + "params": [ + "blueprint_id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprint_labels", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Maintainability - Debt", + "type": "stat" + }, + { + "datasource": "-- Mixed --", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 12, + "y": 9 + }, + "id": 14, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/.*/", + "values": false + }, + "text": {}, + "textMode": "value" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "datasource": "mysql", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "SELECT\n\tCOUNT(if(type = 'CODE_SMELL', 1, null)) as 'Code Smells'\nFROM cq_issues\nWHERE\n $__timeFilter(created_date)\n and project_key in ($project_id)", + "refId": "A", + "select": [ + [ + { + "params": [ + "blueprint_id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprint_labels", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Maintainability - Code Smells", + "type": "stat" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 6, + "panels": [], + "title": "Duplication & Code", + "type": "row" + }, + { + "datasource": "-- Mixed --", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 0, + "y": 15 + }, + "id": 10, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/.*/", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "datasource": "mysql", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "SELECT\n sum(duplicated_blocks)\nFROM cq_file_metrics\nWHERE\n project_key in ($project_id)\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "blueprint_id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprint_labels", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Duplicated Blocks", + "type": "stat" + }, + { + "datasource": "-- Mixed --", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 5, + "w": 6, + "x": 6, + "y": 15 + }, + "id": 9, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "/.*/", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "datasource": "mysql", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "SELECT\n CONCAT(ROUND(sum(duplicated_lines) / sum(num_of_lines) * 100, 1), '% ', 'Duplications on ', ROUND(sum(ncloc) / 1000, 0),'k Lines')\nFROM cq_file_metrics\nWHERE\n project_key in ($project_id)\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "blueprint_id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprint_labels", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Duplicated Lines", + "type": "stat" + }, + { + "datasource": "-- Mixed --", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "color-text", + "filterable": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 20 + }, + "id": 17, + "options": { + "showHeader": true + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "datasource": "mysql", + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "SELECT\n\tfile_name, num_of_lines as 'Lines of Code', bugs as 'Bugs', vulnerabilities as 'Vulnerabilities', code_smells as 'Code Smells', \n\tsecurity_hotspots as 'Security Hotspots', CONCAT(ROUND(coverage, 2), '%') as 'Coverage', CONCAT(ROUND(duplicated_lines_density, 2), '%') as 'Duplications'\nFROM cq_file_metrics\nWHERE\n project_key in ($project_id)\n order by bugs\nlimit $rows", + "refId": "A", + "select": [ + [ + { + "params": [ + "blueprint_id" + ], + "type": "column" + } + ] + ], + "table": "_devlake_blueprint_labels", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Code Quality Metrics by Files", + "type": "table" + } + ], + "refresh": "", + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": "mysql", + "definition": "select concat(name, '--', id) as text from cq_projects", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Choose Project", + "multi": true, + "name": "project_id", + "options": [], + "query": "select concat(name, '--', id) as text from cq_projects", + "refresh": 1, + "regex": "/^(?.*)--(?.*)$/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "allValue": null, + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": "mysql", + "definition": "select distinct(type) from cq_issues", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Issue Type", + "multi": true, + "name": "issue_type", + "options": [], + "query": "select distinct(type) from cq_issues", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "allValue": null, + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": "mysql", + "definition": "select distinct(severity) from cq_issues", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Severity", + "multi": true, + "name": "severity", + "options": [], + "query": "select distinct(severity) from cq_issues", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "allValue": null, + "current": { + "selected": false, + "text": "20", + "value": "20" + }, + "description": null, + "error": null, + "hide": 0, + "includeAll": false, + "label": "rows", + "multi": false, + "name": "rows", + "options": [ + { + "selected": true, + "text": "20", + "value": "20" + }, + { + "selected": false, + "text": "50", + "value": "50" + }, + { + "selected": false, + "text": "100", + "value": "100" + } + ], + "query": "20,50,100", + "queryValue": "", + "skipUrlSync": false, + "type": "custom" + } + ] + }, + "time": { + "from": "now-10y", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "SonarQube", + "uid": "WA0qbuJ4k", + "version": 1 +} \ No newline at end of file diff --git a/charts/devlake/dashboards/TAPD.json b/charts/devlake/dashboards/TAPD.json new file mode 100644 index 0000000..cef23eb --- /dev/null +++ b/charts/devlake/dashboards/TAPD.json @@ -0,0 +1,1031 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 16, + "iteration": 1682063068647, + "links": [ + { + "asDropdown": false, + "icon": "bolt", + "includeVars": false, + "keepTime": true, + "tags": [], + "targetBlank": false, + "title": "Homepage", + "tooltip": "", + "type": "link", + "url": "/grafana/d/Lv1XbLHnk/data-specific-dashboards-homepage" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": true, + "tags": [ + "Data Source Specific Dashboard" + ], + "targetBlank": false, + "title": "Metric dashboards", + "tooltip": "", + "type": "dashboards", + "url": "" + } + ], + "panels": [ + { + "datasource": null, + "gridPos": { + "h": 3, + "w": 13, + "x": 0, + "y": 0 + }, + "id": 128, + "options": { + "content": "- Use Cases: This dashboard shows the basic project management metrics from TAPD.\n- Data Source Required: TAPD", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "title": "Dashboard Introduction", + "type": "text" + }, + { + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 3 + }, + "id": 126, + "title": "1. Issue Throughput", + "type": "row" + }, + { + "datasource": "mysql", + "description": "1. Total number of issues created.\n2. The requirements being calculated are filtered by \"requirement creation time\" (time filter at the upper-right corner) and \"Jira board\" (\"Choose Board\" filter at the upper-left corner)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 0, + "y": 4 + }, + "id": 114, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select \r\n count(*) as value\r\nfrom issues i\r\n join board_issues bi on i.id = bi.issue_id\r\nwhere \r\n i.type in ($type)\r\n and $__timeFilter(i.created_date)\r\n and bi.board_id in ($board_id)", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Number of Issues [Issues Created in Selected Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 4, + "y": 4 + }, + "id": 116, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select \r\n count(*) as value\r\nfrom issues i\r\n join board_issues bi on i.id = bi.issue_id\r\nwhere \r\n i.type in ($type)\r\n and i.status = 'DONE'\r\n and $__timeFilter(i.created_date)\r\n and bi.board_id in ($board_id)", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Number of Delivered Issue [Issues Created in Selected Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 1, + "drawStyle": "bars", + "fillOpacity": 12, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 16, + "x": 8, + "y": 4 + }, + "id": 120, + "interval": null, + "options": { + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "SELECT\r\n DATE_ADD(date(i.created_date), INTERVAL -DAYOFMONTH(date(i.created_date))+1 DAY) as time,\r\n count(distinct case when status != 'DONE' then i.id else null end) as \"Number of Open Issues\",\r\n count(distinct case when status = 'DONE' then i.id else null end) as \"Number of Delivered Issues\"\r\nFROM issues i\r\n\tjoin board_issues bi on i.id = bi.issue_id\r\n\tjoin boards b on bi.board_id = b.id\r\nwhere \r\n i.type in ($type)\r\n and $__timeFilter(i.created_date)\r\n and bi.board_id in ($board_id)\r\ngroup by 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Issue Status Distribution over Month [Issues Created in Selected Time Range]", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "Issue Delivery Rate = count(Delivered Issues)/count(Issues)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 50 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 10 + }, + "id": 117, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with _requirements as(\r\n select\r\n count(distinct i.id) as total_count,\r\n count(distinct case when i.status = 'DONE' then i.id else null end) as delivered_count\r\n from issues i\r\n join board_issues bi on i.id = bi.issue_id\r\n where \r\n i.type in ($type)\r\n and $__timeFilter(i.created_date)\r\n and bi.board_id in ($board_id)\r\n)\r\n\r\nselect \r\n now() as time,\r\n 1.0 * delivered_count/total_count as requirement_delivery_rate\r\nfrom _requirements", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Issue Delivery Rate [Issues Created in Selected Time Range]", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "mysql", + "description": "Issue Delivery Rate = count(Delivered Issues)/count(Issues)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Delivery Rate(%)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 16, + "x": 8, + "y": 10 + }, + "id": 121, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with _requirements as(\r\n select\r\n DATE_ADD(date(i.created_date), INTERVAL -DAYOFMONTH(date(i.created_date))+1 DAY) as time,\r\n 1.0 * count(distinct case when i.status = 'DONE' then i.id else null end)/count(distinct i.id) as delivered_rate\r\n from issues i\r\n join board_issues bi on i.id = bi.issue_id\r\n where \r\n i.type in ($type)\r\n and $__timeFilter(i.created_date)\r\n and bi.board_id in ($board_id)\r\n group by 1\r\n)\r\n\r\nselect\r\n time,\r\n delivered_rate\r\nfrom _requirements\r\norder by time", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Issue Delivery Rate over Time [Issues Created in Selected Time Range]", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 110, + "panels": [], + "title": "2. Issue Lead Time", + "type": "row" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 14 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 0, + "y": 17 + }, + "id": 12, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "/^value$/", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select \r\n avg(lead_time_minutes/1440) as value\r\nfrom issues i\r\n join board_issues bi on i.id = bi.issue_id\r\nwhere \r\n i.type in ($type)\r\n and i.status = 'DONE'\r\n and $__timeFilter(i.resolution_date)\r\n and bi.board_id in ($board_id)", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Mean Issue Lead Time in Days [Issues Resolved in Select Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 21 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 4, + "y": 17 + }, + "id": 13, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _ranks as(\r\n select \r\n i.lead_time_minutes,\r\n percent_rank() over (order by lead_time_minutes asc) as ranks\r\n from issues i\r\n join board_issues bi on i.id = bi.issue_id\r\n where \r\n i.type in ($type)\r\n and i.status = 'DONE'\r\n and $__timeFilter(i.resolution_date)\r\n and bi.board_id in ($board_id)\r\n)\r\n\r\nselect\r\n max(lead_time_minutes/1440) as value\r\nfrom _ranks\r\nwhere \r\n ranks <= 0.8", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "80% Issues' Lead Time are less than # days [Issues Resolved in Select Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Lead Time(days)", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 16, + "x": 8, + "y": 17 + }, + "id": 17, + "interval": "", + "options": { + "barWidth": 0.5, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _requirements as(\r\n select \r\n DATE_ADD(date(i.resolution_date), INTERVAL -DAYOFMONTH(date(i.resolution_date))+1 DAY) as time,\r\n avg(lead_time_minutes/1440) as mean_lead_time\r\n from issues i\r\n join board_issues bi on i.id = bi.issue_id\r\n where \r\n i.type in ($type)\r\n and i.status = 'DONE'\r\n and $__timeFilter(i.resolution_date)\r\n and bi.board_id in ($board_id)\r\n group by 1\r\n)\r\n\r\nselect \r\n date_format(time,'%M %Y') as month,\r\n mean_lead_time\r\nfrom _requirements\r\norder by time asc", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Mean Issue Lead Time [Issues Resolved in Select Time Range]", + "type": "barchart" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "mysql", + "description": "1. The cumulative distribution of requirement lead time. \n2. Each point refers to the percent rank of a lead time.", + "fill": 0, + "fillGradient": 4, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 23 + }, + "hiddenSeries": false, + "id": 15, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 8, + "nullPointMode": "null", + "options": { + "alertThreshold": false + }, + "percentage": false, + "pluginVersion": "8.0.6", + "pointradius": 0.5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _ranks as(\r\n select \r\n round(i.lead_time_minutes/1440) as lead_time_day\r\n from issues i\r\n join board_issues bi on i.id = bi.issue_id\r\n where \r\n i.type in ($type)\r\n and i.status = 'DONE'\r\n and $__timeFilter(i.resolution_date)\r\n and bi.board_id in ($board_id)\r\n order by lead_time_day asc\r\n)\r\n\r\nselect \r\n now() as time,\r\n lpad(concat(lead_time_day,'d'), 4, ' ') as metric,\r\n percent_rank() over (order by lead_time_day asc) as value\r\nfrom _ranks\r\norder by lead_time_day asc", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "thresholds": [ + { + "$$hashKey": "object:469", + "colorMode": "ok", + "fill": true, + "line": true, + "op": "lt", + "value": 0.8, + "yaxis": "right" + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Cumulative Distribution of Requirement Lead Time [Issues Resolved in Select Time Range]", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "transformations": [], + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "series", + "name": null, + "show": true, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "$$hashKey": "object:76", + "format": "percentunit", + "label": "Percent Rank (%)", + "logBase": 1, + "max": "1.2", + "min": null, + "show": true + }, + { + "$$hashKey": "object:77", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "datasource": null, + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 29 + }, + "id": 130, + "options": { + "content": "
\n\nThis dashboard is created based on this [data schema](https://devlake.apache.org/docs/DataModels/DevLakeDomainLayerSchema). Want to add more metrics? Please follow the [guide](https://devlake.apache.org/docs/Configuration/Dashboards/GrafanaUserGuide).", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + } + ], + "refresh": "", + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": "mysql", + "definition": "select concat(name, '--', id) from boards where id like 'tapd%'", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Choose Board", + "multi": true, + "name": "board_id", + "options": [], + "query": "select concat(name, '--', id) from boards where id like 'tapd%'", + "refresh": 1, + "regex": "/^(?.*)--(?.*)$/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "allValue": null, + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "mysql", + "definition": "select distinct type from issues", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Issue Type", + "multi": false, + "name": "type", + "options": [], + "query": "select distinct type from issues", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-6M", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "TAPD", + "uid": "hi-907hVk", + "version": 3 +} \ No newline at end of file diff --git a/charts/devlake/dashboards/Teambition.json b/charts/devlake/dashboards/Teambition.json new file mode 100644 index 0000000..44133f9 --- /dev/null +++ b/charts/devlake/dashboards/Teambition.json @@ -0,0 +1,1031 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 22, + "iteration": 1672982963558, + "links": [ + { + "asDropdown": false, + "icon": "bolt", + "includeVars": false, + "keepTime": true, + "tags": [], + "targetBlank": false, + "title": "Homepage", + "tooltip": "", + "type": "link", + "url": "/grafana/d/Lv1XbLHnk/data-specific-dashboards-homepage" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": true, + "tags": [ + "Data Source Specific Dashboard" + ], + "targetBlank": false, + "title": "Metric dashboards", + "tooltip": "", + "type": "dashboards", + "url": "" + } + ], + "panels": [ + { + "datasource": null, + "gridPos": { + "h": 3, + "w": 13, + "x": 0, + "y": 0 + }, + "id": 128, + "options": { + "content": "- Use Cases: This dashboard shows the basic project management metrics from Teambition.\n- Data Source Required: Teambition", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "title": "Dashboard Introduction", + "type": "text" + }, + { + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 3 + }, + "id": 126, + "title": "1. Issue Throughput", + "type": "row" + }, + { + "datasource": "mysql", + "description": "1. Total number of issues created.\n2. The requirements being calculated are filtered by \"requirement creation time\" (time filter at the upper-right corner) and \"Jira board\" (\"Choose Board\" filter at the upper-left corner)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 0, + "y": 4 + }, + "id": 114, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select \r\n count(*) as value\r\nfrom issues i\r\n join board_issues bi on i.id = bi.issue_id\r\nwhere \r\n i.type in ($type)\r\n and $__timeFilter(i.created_date)\r\n and bi.board_id in ($board_id)", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Number of Issues [Issues Created in Selected Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 4, + "y": 4 + }, + "id": 116, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select \r\n count(*) as value\r\nfrom issues i\r\n join board_issues bi on i.id = bi.issue_id\r\nwhere \r\n i.type in ($type)\r\n and i.status = 'DONE'\r\n and $__timeFilter(i.created_date)\r\n and bi.board_id in ($board_id)", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Number of Delivered Issue [Issues Created in Selected Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 1, + "drawStyle": "bars", + "fillOpacity": 12, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 16, + "x": 8, + "y": 4 + }, + "id": 120, + "interval": null, + "options": { + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "SELECT\r\n DATE_ADD(date(i.created_date), INTERVAL -DAYOFMONTH(date(i.created_date))+1 DAY) as time,\r\n count(distinct case when status != 'DONE' then i.id else null end) as \"Number of Open Issues\",\r\n count(distinct case when status = 'DONE' then i.id else null end) as \"Number of Delivered Issues\"\r\nFROM issues i\r\n\tjoin board_issues bi on i.id = bi.issue_id\r\n\tjoin boards b on bi.board_id = b.id\r\nwhere \r\n i.type in ($type)\r\n and $__timeFilter(i.created_date)\r\n and bi.board_id in ($board_id)\r\ngroup by 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Issue Status Distribution over Month [Issues Created in Selected Time Range]", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "Issue Delivery Rate = count(Delivered Issues)/count(Issues)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 50 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 10 + }, + "id": 117, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with _requirements as(\r\n select\r\n count(distinct i.id) as total_count,\r\n count(distinct case when i.status = 'DONE' then i.id else null end) as delivered_count\r\n from issues i\r\n join board_issues bi on i.id = bi.issue_id\r\n where \r\n i.type in ($type)\r\n and $__timeFilter(i.created_date)\r\n and bi.board_id in ($board_id)\r\n)\r\n\r\nselect \r\n now() as time,\r\n 1.0 * delivered_count/total_count as requirement_delivery_rate\r\nfrom _requirements", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Issue Delivery Rate [Issues Created in Selected Time Range]", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "mysql", + "description": "Issue Delivery Rate = count(Delivered Issues)/count(Issues)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Delivery Rate(%)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 16, + "x": 8, + "y": 10 + }, + "id": 121, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with _requirements as(\r\n select\r\n DATE_ADD(date(i.created_date), INTERVAL -DAYOFMONTH(date(i.created_date))+1 DAY) as time,\r\n 1.0 * count(distinct case when i.status = 'DONE' then i.id else null end)/count(distinct i.id) as delivered_rate\r\n from issues i\r\n join board_issues bi on i.id = bi.issue_id\r\n where \r\n i.type in ($type)\r\n and $__timeFilter(i.created_date)\r\n and bi.board_id in ($board_id)\r\n group by 1\r\n)\r\n\r\nselect\r\n time,\r\n delivered_rate\r\nfrom _requirements\r\norder by time", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Issue Delivery Rate over Time [Issues Created in Selected Time Range]", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 110, + "panels": [], + "title": "2. Issue Lead Time", + "type": "row" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 14 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 0, + "y": 17 + }, + "id": 12, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "/^value$/", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select \r\n avg(lead_time_minutes/1440) as value\r\nfrom issues i\r\n join board_issues bi on i.id = bi.issue_id\r\nwhere \r\n i.type in ($type)\r\n and i.status = 'DONE'\r\n and $__timeFilter(i.resolution_date)\r\n and bi.board_id in ($board_id)", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Mean Issue Lead Time in Days [Issues Resolved in Select Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 21 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 4, + "y": 17 + }, + "id": 13, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _ranks as(\r\n select \r\n i.lead_time_minutes,\r\n percent_rank() over (order by lead_time_minutes asc) as ranks\r\n from issues i\r\n join board_issues bi on i.id = bi.issue_id\r\n where \r\n i.type in ($type)\r\n and i.status = 'DONE'\r\n and $__timeFilter(i.resolution_date)\r\n and bi.board_id in ($board_id)\r\n)\r\n\r\nselect\r\n max(lead_time_minutes/1440) as value\r\nfrom _ranks\r\nwhere \r\n ranks <= 0.8", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "80% Issues' Lead Time are less than # days [Issues Resolved in Select Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Lead Time(days)", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 16, + "x": 8, + "y": 17 + }, + "id": 17, + "interval": "", + "options": { + "barWidth": 0.5, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _requirements as(\r\n select \r\n DATE_ADD(date(i.resolution_date), INTERVAL -DAYOFMONTH(date(i.resolution_date))+1 DAY) as time,\r\n avg(lead_time_minutes/1440) as mean_lead_time\r\n from issues i\r\n join board_issues bi on i.id = bi.issue_id\r\n where \r\n i.type in ($type)\r\n and i.status = 'DONE'\r\n and $__timeFilter(i.resolution_date)\r\n and bi.board_id in ($board_id)\r\n group by 1\r\n)\r\n\r\nselect \r\n date_format(time,'%M %Y') as month,\r\n mean_lead_time\r\nfrom _requirements\r\norder by time asc", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Mean Issue Lead Time [Issues Resolved in Select Time Range]", + "type": "barchart" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "mysql", + "description": "1. The cumulative distribution of requirement lead time. \n2. Each point refers to the percent rank of a lead time.", + "fill": 0, + "fillGradient": 4, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 23 + }, + "hiddenSeries": false, + "id": 15, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 8, + "nullPointMode": "null", + "options": { + "alertThreshold": false + }, + "percentage": false, + "pluginVersion": "8.0.6", + "pointradius": 0.5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _ranks as(\r\n select \r\n round(i.lead_time_minutes/1440) as lead_time_day\r\n from issues i\r\n join board_issues bi on i.id = bi.issue_id\r\n where \r\n i.type in ($type)\r\n and i.status = 'DONE'\r\n and $__timeFilter(i.resolution_date)\r\n and bi.board_id in ($board_id)\r\n order by lead_time_day asc\r\n)\r\n\r\nselect \r\n now() as time,\r\n lpad(concat(lead_time_day,'d'), 4, ' ') as metric,\r\n percent_rank() over (order by lead_time_day asc) as value\r\nfrom _ranks\r\norder by lead_time_day asc", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "thresholds": [ + { + "$$hashKey": "object:469", + "colorMode": "ok", + "fill": true, + "line": true, + "op": "lt", + "value": 0.8, + "yaxis": "right" + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Cumulative Distribution of Requirement Lead Time [Issues Resolved in Select Time Range]", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "transformations": [], + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "series", + "name": null, + "show": true, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "$$hashKey": "object:76", + "format": "percentunit", + "label": "Percent Rank (%)", + "logBase": 1, + "max": "1.2", + "min": null, + "show": true + }, + { + "$$hashKey": "object:77", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "datasource": null, + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 29 + }, + "id": 130, + "options": { + "content": "
\n\nThis dashboard is created based on this [data schema](https://devlake.apache.org/docs/DataModels/DevLakeDomainLayerSchema). Want to add more metrics? Please follow the [guide](https://devlake.apache.org/docs/Configuration/Dashboards/GrafanaUserGuide).", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + } + ], + "refresh": "", + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": "mysql", + "definition": "select concat(name, '--', id) from boards where id like 'teambition%'", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Choose Board", + "multi": true, + "name": "board_id", + "options": [], + "query": "select concat(name, '--', id) from boards where id like 'teambition%'", + "refresh": 1, + "regex": "/^(?.*)--(?.*)$/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "allValue": null, + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "mysql", + "definition": "select distinct type from issues", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Issue Type", + "multi": false, + "name": "type", + "options": [], + "query": "select distinct type from issues", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-6M", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Teambition", + "uid": "hi-908hVk", + "version": 3 +} \ No newline at end of file diff --git a/charts/devlake/dashboards/WeeklyBugRetro.json b/charts/devlake/dashboards/WeeklyBugRetro.json new file mode 100644 index 0000000..7e33ce8 --- /dev/null +++ b/charts/devlake/dashboards/WeeklyBugRetro.json @@ -0,0 +1,1681 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 13, + "iteration": 1681785827220, + "links": [], + "panels": [ + { + "datasource": null, + "gridPos": { + "h": 3, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 28, + "options": { + "content": "- Use Cases: This dashboard can be used to track bugs with metrics such as [Bug Age](https://devlake.apache.org/docs/Metrics/BugAge).\n- Data Source Required: GitHub ([transformation](https://devlake.apache.org/docs/UserManuals/ConfigUI/GitHub#step-3---adding-transformation-rules-optional) required) or Jira ([transformation](https://devlake.apache.org/docs/UserManuals/ConfigUI/Jira#step-3---adding-transformation-rules-optional) required). Transformation is the configuration for you to tell DevLake what is a bug.", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "title": "Dashboard Introduction", + "type": "text" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 3 + }, + "id": 6, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select\n count(*)\nfrom\n lake.issues as i\n join lake.board_issues bi on i.id = bi.issue_id\n join boards b on bi.board_id = b.id\nwhere\n i.type in ($issue_type)\n and date(i.created_date) BETWEEN curdate() - INTERVAL WEEKDAY(curdate())+7 DAY AND curdate() - INTERVAL WEEKDAY(curdate())+1 DAY\n and b.id in ($board_id)", + "refId": "A", + "select": [ + [ + { + "params": [ + "script_version" + ], + "type": "column" + } + ] + ], + "table": "_devlake_migration_history", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Previous Week New Bug Count", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + } + }, + "mappings": [] + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 3 + }, + "id": 26, + "options": { + "displayLabels": [ + "name", + "value" + ], + "legend": { + "displayMode": "list", + "placement": "bottom", + "values": [ + "percent", + "value" + ] + }, + "pieType": "donut", + "reduceOptions": { + "calcs": [], + "fields": "", + "values": true + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select\n priority,\n count(*) as 'Issue Number'\nfrom\n lake.issues as i\n join lake.board_issues bi on i.id = bi.issue_id\n join boards b on bi.board_id = b.id\nwhere\n i.type in ($issue_type)\n and date(i.created_date) BETWEEN curdate() - INTERVAL WEEKDAY(curdate())+7 DAY AND curdate() - INTERVAL WEEKDAY(curdate())+1 DAY\n and b.id in ($board_id)\ngroup by 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "script_version" + ], + "type": "column" + } + ] + ], + "table": "_devlake_migration_history", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Previous Week New Bug Count by Priority", + "type": "piechart" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "url" + }, + "properties": [ + { + "id": "links" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "number" + }, + "properties": [ + { + "id": "custom.width", + "value": 343 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "title" + }, + "properties": [ + { + "id": "custom.width", + "value": 753 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "url" + }, + "properties": [ + { + "id": "links", + "value": [ + { + "targetBlank": true, + "title": "URL", + "url": "${__value.raw}" + } + ] + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Issue Number" + }, + "properties": [ + { + "id": "custom.width", + "value": 124 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Title" + }, + "properties": [ + { + "id": "custom.width", + "value": 640 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 3 + }, + "id": 4, + "options": { + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select\n i.issue_key as 'Issue Number',\n i.title as 'Title',\n i.url as 'Url'\nfrom\n lake.issues as i\n\tjoin lake.board_issues bi on i.id = bi.issue_id\n\tjoin lake.boards b on bi.board_id = b.id\nwhere\n i.type in ($issue_type)\n and date(i.created_date) BETWEEN curdate() - INTERVAL WEEKDAY(curdate())+7 DAY AND curdate() - INTERVAL WEEKDAY(curdate())+1 DAY\n and b.id in ($board_id)", + "refId": "A", + "select": [ + [ + { + "params": [ + "script_version" + ], + "type": "column" + } + ] + ], + "table": "_devlake_migration_history", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Last Week's New Bugs", + "type": "table" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 0, + "y": 11 + }, + "id": 8, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select\n count(*)\nfrom\n lake.issues as i\n join board_issues bi on i.id = bi.issue_id\n\tjoin boards b on bi.board_id = b.id\nwhere\n i.type in ($issue_type)\n and status = 'DONE'\n and date(i.resolution_date) BETWEEN curdate() - INTERVAL WEEKDAY(curdate())+7 DAY AND curdate() - INTERVAL WEEKDAY(curdate())+1 DAY\n and b.id in ($board_id)", + "refId": "A", + "select": [ + [ + { + "params": [ + "script_version" + ], + "type": "column" + } + ] + ], + "table": "_devlake_migration_history", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Last Week's Fixed Bugs Count", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 14 + }, + { + "color": "red", + "value": 21 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 6, + "y": 11 + }, + "id": 24, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select\n avg(lead_time_minutes / 1440)\nfrom\n lake.issues as i\n\tjoin board_issues bi on i.id = bi.issue_id\n\tjoin boards b on bi.board_id = b.id\nwhere\n i.type in ($issue_type)\n and status = 'DONE'\n and date(i.resolution_date) BETWEEN curdate() - INTERVAL WEEKDAY(curdate())+7 DAY AND curdate() - INTERVAL WEEKDAY(curdate())+1 DAY\n and b.id in ($board_id)", + "refId": "A", + "select": [ + [ + { + "params": [ + "script_version" + ], + "type": "column" + } + ] + ], + "table": "_devlake_migration_history", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Average Lead Time of Last Week's Resolved Bugs in Days", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 21 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Issue Number" + }, + "properties": [ + { + "id": "custom.width", + "value": 125 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Title" + }, + "properties": [ + { + "id": "custom.width", + "value": 541 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Url" + }, + "properties": [ + { + "id": "custom.width", + "value": 414 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Lead Time in Days" + }, + "properties": [ + { + "id": "custom.displayMode", + "value": "color-text" + } + ] + } + ] + }, + "gridPos": { + "h": 16, + "w": 12, + "x": 12, + "y": 11 + }, + "id": 10, + "options": { + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select\n i.issue_key as 'Issue Number',\n i.title as 'Title',\n lead_time_minutes/1440 as 'Lead Time in Days',\n i.url as 'Url'\nfrom\n lake.issues as i\n\tjoin board_issues bi on i.id = bi.issue_id\n\tjoin boards b on bi.board_id = b.id\nwhere\n i.type in ($issue_type)\n and status = 'DONE'\n and date(i.resolution_date) BETWEEN curdate() - INTERVAL WEEKDAY(curdate())+7 DAY AND curdate() - INTERVAL WEEKDAY(curdate())+1 DAY\n and b.id in ($board_id)", + "refId": "A", + "select": [ + [ + { + "params": [ + "script_version" + ], + "type": "column" + } + ] + ], + "table": "_devlake_migration_history", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Last Week's Fixed Bugs", + "type": "table" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 19 + }, + "id": 23, + "options": { + "barWidth": 0.3, + "groupWidth": 0.7, + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "horizontal", + "showValue": "auto", + "text": {}, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select\n concat('#',i.issue_key, ' ', i.title) as issue_key,\n lead_time_minutes/1440 as lead_time\nfrom\n lake.issues as i\n\tjoin board_issues bi on i.id = bi.issue_id\n\tjoin boards b on bi.board_id = b.id\nwhere\n i.type in ($issue_type)\n and status = 'DONE'\n and date(i.resolution_date) BETWEEN curdate() - INTERVAL WEEKDAY(curdate())+7 DAY AND curdate() - INTERVAL WEEKDAY(curdate())+1 DAY\n and b.id in ($board_id)\norder by lead_time desc", + "refId": "A", + "select": [ + [ + { + "params": [ + "script_version" + ], + "type": "column" + } + ] + ], + "table": "_devlake_migration_history", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Lead Time Distribution [Last Week's Resolved Bugs in Days]", + "type": "barchart" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 6, + "x": 0, + "y": 27 + }, + "id": 16, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select\n count(*)\nfrom \n lake.issues i\n\tjoin board_issues bi on i.id = bi.issue_id\n\tjoin boards b on bi.board_id = b.id\nwhere\n i.type in ($issue_type)\n and i.status != 'DONE'\n and b.id in ($board_id)", + "refId": "A", + "select": [ + [ + { + "params": [ + "script_version" + ], + "type": "column" + } + ] + ], + "table": "_devlake_migration_history", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Total Number of Outstanding Bugs", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 30 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 6, + "x": 6, + "y": 27 + }, + "id": 25, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select \n avg((TIMESTAMPDIFF(MINUTE, i.created_date,NOW()))/1440)\nfrom \n lake.issues i\n\tjoin board_issues bi on i.id = bi.issue_id\n\tjoin boards b on bi.board_id = b.id\nwhere\n i.type in ($issue_type)\n and i.status != 'DONE'\n and b.id in ($board_id)", + "refId": "A", + "select": [ + [ + { + "params": [ + "script_version" + ], + "type": "column" + } + ] + ], + "table": "_devlake_migration_history", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Average Age of Outstanding Bugs in Days", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 30 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Queue Time" + }, + "properties": [ + { + "id": "custom.width", + "value": 150 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Issue Number" + }, + "properties": [ + { + "id": "custom.width", + "value": 121 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Queue Time in Days" + }, + "properties": [ + { + "id": "custom.width", + "value": 152 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Title" + }, + "properties": [ + { + "id": "custom.width", + "value": 547 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Queue Time in Days" + }, + "properties": [ + { + "id": "custom.displayMode", + "value": "color-text" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Url" + }, + "properties": [ + { + "id": "custom.width", + "value": null + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 27 + }, + "id": 14, + "options": { + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select \n i.issue_key as 'Issue Number',\n i.title as 'Title',\n (TIMESTAMPDIFF(MINUTE, i.created_date,NOW()))/1440 as 'Queue Time in Days',\n i.url as 'Url',\n priority\nfrom \n lake.issues i\n\tjoin board_issues bi on i.id = bi.issue_id\n\tjoin boards b on bi.board_id = b.id\nwhere\n i.type in ($issue_type)\n and i.status != 'DONE'\n and b.id in ($board_id)\n and priority in ($priority)\norder by 'Queue Time' desc", + "refId": "A", + "select": [ + [ + { + "params": [ + "script_version" + ], + "type": "column" + } + ] + ], + "table": "_devlake_migration_history", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Outstanding Bugs Sort by Queue Time [All History]", + "type": "table" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Queue Time in Days", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 21 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 36 + }, + "id": 18, + "options": { + "barWidth": 0.3, + "groupWidth": 0.7, + "legend": { + "calcs": [ + "mean", + "max" + ], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "always", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select \n concat('#', i.issue_key) as issue_key,\n (TIMESTAMPDIFF(MINUTE, i.created_date,NOW()))/1440 as 'Queue Time in Days'\nfrom \n lake.issues i\n\tjoin board_issues bi on i.id = bi.issue_id\n\tjoin boards b on bi.board_id = b.id\nwhere\n i.type in ($issue_type)\n and i.status != 'DONE'\n and b.id in ($board_id)\norder by 2 desc", + "refId": "A", + "select": [ + [ + { + "params": [ + "script_version" + ], + "type": "column" + } + ] + ], + "table": "_devlake_migration_history", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Distribution of Bug Queue Time in Days [Outstanding Bugs]", + "type": "barchart" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 7 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Issue Number" + }, + "properties": [ + { + "id": "custom.width", + "value": 121 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Queue Time in Days" + }, + "properties": [ + { + "id": "custom.width", + "value": 152 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Title" + }, + "properties": [ + { + "id": "custom.width", + "value": 547 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Queue Time in Days" + }, + "properties": [ + { + "id": "custom.displayMode", + "value": "color-text" + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 36 + }, + "id": 31, + "options": { + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select \n i.issue_key as 'Issue Number',\n i.title as 'Title',\n (TIMESTAMPDIFF(MINUTE, i.created_date,NOW()))/1440 as 'Queue Time in Days',\n i.url as 'Url'\nfrom \n lake.issues i\n\tjoin board_issues bi on i.id = bi.issue_id\n\tjoin boards b on bi.board_id = b.id\nwhere\n i.type in ($issue_type)\n and i.status != 'DONE'\n and i.assignee_name = ''\n and b.id in ($board_id)\norder by 'Queue Time' desc", + "refId": "A", + "select": [ + [ + { + "params": [ + "script_version" + ], + "type": "column" + } + ] + ], + "table": "_devlake_migration_history", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Bugs to be Triaged Sort by Queue Time [All History]", + "type": "table" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 46, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 24, + "x": 0, + "y": 45 + }, + "id": 2, + "options": { + "barWidth": 0.71, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with bugs as ( \n select \n DATE_ADD(date(i.created_date), INTERVAL -WEEKDAY(date(i.created_date)) DAY) as time,\n count(*) as bug_count\n from\n lake.issues as i\n\t join lake.board_issues bi on i.id = bi.issue_id\n\t join lake.boards b on bi.board_id = b.id\n where \n i.type in ($issue_type)\n and $__timeFilter(i.created_date)\n and b.id in ($board_id)\n group by time\n order by time desc\n),\n\ncalendar_date as(\n\tSELECT CAST((SYSDATE()-INTERVAL (H+T+U) DAY) AS date) d\n\tFROM ( SELECT 0 H\n\t\t\tUNION ALL SELECT 100 UNION ALL SELECT 200 UNION ALL SELECT 300\n\t\t) H CROSS JOIN ( SELECT 0 T\n\t\t\tUNION ALL SELECT 10 UNION ALL SELECT 20 UNION ALL SELECT 30\n\t\t\tUNION ALL SELECT 40 UNION ALL SELECT 50 UNION ALL SELECT 60\n\t\t\tUNION ALL SELECT 70 UNION ALL SELECT 80 UNION ALL SELECT 90\n\t\t) T CROSS JOIN ( SELECT 0 U\n\t\t\tUNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3\n\t\t\tUNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6\n\t\t\tUNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9\n\t\t) U\n\tWHERE\n\t\t(SYSDATE()-INTERVAL (H+T+U) DAY) >= (SYSDATE()-INTERVAL 6 MONTH)\n),\n\ncalendar_weeks as(\n select \n \tdistinct date(DATE_ADD(date(d), INTERVAL -WEEKDAY(date(d)) DAY)) as start_of_week\n FROM calendar_date\n ORDER BY 1 asc\n)\n\n\nselect \n concat(date_format(cw.start_of_week,'%m/%d'), ' - ', date_format(DATE_ADD(cw.start_of_week, INTERVAL +6 DAY),'%m/%d')) as week,\n case when bug_count is not null then bug_count else 0 end as 'Weekly New Bugs'\nfrom calendar_weeks cw left join bugs b on cw.start_of_week = b.time\norder by cw.start_of_week asc\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "script_version" + ], + "type": "column" + } + ] + ], + "table": "_devlake_migration_history", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Weekly New Bugs [Selected Time Range]", + "type": "barchart" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 46, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 54 + }, + "id": 20, + "options": { + "barWidth": 0.71, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with bugs as (\n select \n DATE_ADD(date(i.resolution_date), INTERVAL -WEEKDAY(date(i.resolution_date)) DAY) as time,\n count(*) as bug_count\n from\n lake.issues as i\n\t join lake.board_issues bi on i.id = bi.issue_id\n\t join lake.boards b on bi.board_id = b.id\n where \n i.type in ($issue_type)\n and status = 'DONE'\n and $__timeFilter(i.resolution_date)\n and b.id in ($board_id)\n group by time\n order by time desc\n),\n\ncalendar_date as(\n\tSELECT CAST((SYSDATE()-INTERVAL (H+T+U) DAY) AS date) d\n\tFROM ( SELECT 0 H\n\t\t\tUNION ALL SELECT 100 UNION ALL SELECT 200 UNION ALL SELECT 300\n\t\t) H CROSS JOIN ( SELECT 0 T\n\t\t\tUNION ALL SELECT 10 UNION ALL SELECT 20 UNION ALL SELECT 30\n\t\t\tUNION ALL SELECT 40 UNION ALL SELECT 50 UNION ALL SELECT 60\n\t\t\tUNION ALL SELECT 70 UNION ALL SELECT 80 UNION ALL SELECT 90\n\t\t) T CROSS JOIN ( SELECT 0 U\n\t\t\tUNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3\n\t\t\tUNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6\n\t\t\tUNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9\n\t\t) U\n\tWHERE\n\t\t(SYSDATE()-INTERVAL (H+T+U) DAY) >= (SYSDATE()-INTERVAL 6 MONTH)\n),\n\ncalendar_weeks as(\n select \n \tdistinct date(DATE_ADD(date(d), INTERVAL -WEEKDAY(date(d)) DAY)) as start_of_week\n FROM calendar_date\n ORDER BY 1 asc\n)\n\nselect \n concat(date_format(cw.start_of_week,'%m/%d'), ' - ', date_format(DATE_ADD(cw.start_of_week, INTERVAL +6 DAY),'%m/%d')) as week,\n case when bug_count is not null then bug_count else 0 end as 'Weekly Closed Bugs'\nfrom calendar_weeks cw left join bugs b on cw.start_of_week = b.time\norder by cw.start_of_week asc", + "refId": "A", + "select": [ + [ + { + "params": [ + "script_version" + ], + "type": "column" + } + ] + ], + "table": "_devlake_migration_history", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Weekly Closed Bugs [Selected Time Range]", + "type": "barchart" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 46, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 64 + }, + "id": 21, + "options": { + "barWidth": 0.71, + "groupWidth": 0.7, + "legend": { + "calcs": [ + "mean" + ], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with calendar_date as(\n\tSELECT CAST((SYSDATE()-INTERVAL (H+T+U) DAY) AS date) d\n\tFROM ( SELECT 0 H\n\t\t\tUNION ALL SELECT 100 UNION ALL SELECT 200 UNION ALL SELECT 300\n\t\t) H CROSS JOIN ( SELECT 0 T\n\t\t\tUNION ALL SELECT 10 UNION ALL SELECT 20 UNION ALL SELECT 30\n\t\t\tUNION ALL SELECT 40 UNION ALL SELECT 50 UNION ALL SELECT 60\n\t\t\tUNION ALL SELECT 70 UNION ALL SELECT 80 UNION ALL SELECT 90\n\t\t) T CROSS JOIN ( SELECT 0 U\n\t\t\tUNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3\n\t\t\tUNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6\n\t\t\tUNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9\n\t\t) U\n\tWHERE\n\t\t(SYSDATE()-INTERVAL (H+T+U) DAY) >= (SYSDATE()-INTERVAL 6 MONTH)\n),\n\ncalendar_weeks as(\n select \n \tdistinct date(DATE_ADD(date(d), INTERVAL -WEEKDAY(date(d)) DAY)) as start_of_week\n FROM calendar_date\n ORDER BY 1 asc\n),\n\ncreated_bugs as ( \n select \n DATE_ADD(date(i.created_date), INTERVAL -WEEKDAY(date(i.created_date)) DAY) as time,\n count(*) as bug_count\n from\n lake.issues as i\n\t join lake.board_issues bi on i.id = bi.issue_id\n\t join lake.boards b on bi.board_id = b.id\n where \n i.type in ($issue_type)\n and $__timeFilter(i.created_date)\n and b.id in ($board_id)\n group by time\n order by time desc\n),\n\nresolved_bugs as (\n select \n DATE_ADD(date(i.resolution_date), INTERVAL -WEEKDAY(date(i.resolution_date)) DAY) as time,\n count(*) as bug_count\n from\n lake.issues as i\n\t join lake.board_issues bi on i.id = bi.issue_id\n\t join lake.boards b on bi.board_id = b.id\n where \n i.type in ($issue_type)\n and status = 'DONE'\n and $__timeFilter(i.resolution_date)\n and b.id in ($board_id)\n group by time\n order by time desc\n),\n\nweekly_new_bug as(\n select\n cw.start_of_week as week,\n case when bug_count is not null then bug_count else 0 end as weekly_new_bug\n from calendar_weeks cw left join created_bugs cb on cw.start_of_week = cb.time\n),\n\nweekly_closed_bug as(\n select\n cw.start_of_week as week,\n case when bug_count is not null then bug_count else 0 end as weekly_closed_bug\n from calendar_weeks cw left join resolved_bugs cb on cw.start_of_week = cb.time\n),\n\nweekly_updates as(\n SELECT t1.week, weekly_new_bug, weekly_closed_bug FROM weekly_new_bug t1\n LEFT JOIN weekly_closed_bug t2 ON t1.week = t2.week\n UNION\n SELECT t1.week, weekly_new_bug, weekly_closed_bug FROM weekly_new_bug t1\n RIGHT JOIN weekly_closed_bug t2 ON t1.week = t2.week\n),\n\n\noriginal_open_bugs as (\n SELECT \n count(distinct i.id) as original_open_bug_count\n FROM\n lake.issues as i\n\t join lake.board_issues bi on i.id = bi.issue_id\n\t join lake.boards b on bi.board_id = b.id\n where \n i.type in ($issue_type)\n and i.created_date < $__timeFrom()\n and (i.status != 'DONE' or $__timeFilter(i.resolution_date))\n and b.id in ($board_id)\n),\n\nweekly_updated_without_null as(\n SELECT \n week, \n COALESCE(weekly_new_bug,0) as weekly_new_bug, \n COALESCE(weekly_closed_bug,0) as weekly_closed_bug,\n original_open_bug_count\n from weekly_updates, original_open_bugs\n where week is not null\n),\n\nweekly_delta as(\n SELECT \n *,\n (weekly_new_bug - weekly_closed_bug) as weekly_delta\n from weekly_updated_without_null\n order by week asc\n),\n\nfinal_data as(\n SELECT \n *,\n concat(date_format(week,'%m/%d'), ' - ', date_format(DATE_ADD(week, INTERVAL +6 DAY),'%m/%d')) as _week,\n sum(weekly_delta) over(order by week asc) as weekly_accumulated\n from weekly_delta\n)\n\nSELECT \n _week,\n (original_open_bug_count + weekly_accumulated) as \"Total No. of Outstanding Bugs By the End of Week\" from final_data", + "refId": "A", + "select": [ + [ + { + "params": [ + "script_version" + ], + "type": "column" + } + ] + ], + "table": "_devlake_migration_history", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Total Outstanding Bug Count by Week [Selected Time Range]", + "type": "barchart" + }, + { + "datasource": null, + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 74 + }, + "id": 30, + "options": { + "content": "
\n\nThis dashboard is created based on this [data schema](https://devlake.apache.org/docs/DataModels/DevLakeDomainLayerSchema). Want to add more metrics? Please follow the [guide](https://devlake.apache.org/docs/UserManuals/Dashboards/GrafanaUserGuide).", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + } + ], + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "mysql", + "definition": "select concat(name, '-', id) as text from boards", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Board", + "multi": false, + "name": "board_id", + "options": [], + "query": "select concat(name, '-', id) as text from boards", + "refresh": 1, + "regex": "/^(?.*)-(?.*)$/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "allValue": null, + "current": { + "selected": false, + "text": "BUG", + "value": "BUG" + }, + "datasource": "mysql", + "definition": "select distinct type from issues", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Issue Type", + "multi": false, + "name": "issue_type", + "options": [], + "query": "select distinct type from issues", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "allValue": null, + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": "mysql", + "definition": "select distinct priority from issues", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Priority", + "multi": true, + "name": "priority", + "options": [], + "query": "select distinct priority from issues", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-6M", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Weekly Bug Retro", + "uid": "-5EKA5w7k", + "version": 23 +} \ No newline at end of file diff --git a/charts/devlake/dashboards/WeeklyCommunityRetro.json b/charts/devlake/dashboards/WeeklyCommunityRetro.json new file mode 100644 index 0000000..d219c91 --- /dev/null +++ b/charts/devlake/dashboards/WeeklyCommunityRetro.json @@ -0,0 +1,1794 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 27, + "iteration": 1682063086384, + "links": [], + "panels": [ + { + "datasource": null, + "gridPos": { + "h": 3, + "w": 23, + "x": 0, + "y": 0 + }, + "id": 48, + "options": { + "content": "- Use Cases: This dashboard can be used to track community growth by OSS maintainers.\n- Data Source Required: GitHub users' organizations are used to filter issues/PRs created by certain users. [Publicize users' org](https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-your-membership-in-organizations/publicizing-or-hiding-organization-membership) so that Apache DevLake can collect users' org.", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "title": "Dashboard Introduction", + "type": "text" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 3 + }, + "id": 42, + "panels": [], + "title": "Community Issues", + "type": "row" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 4 + }, + "id": 6, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select\n count(*)\nfrom\n lake.issues as i\n join lake.board_issues bi on i.id = bi.issue_id\n join boards b on bi.board_id = b.id\nwhere\n i.type in ($issue_type)\n and date(i.created_date) BETWEEN curdate() - INTERVAL WEEKDAY(curdate())+7 DAY AND curdate() - INTERVAL WEEKDAY(curdate())+1 DAY\n and b.id in ($repo_id)", + "refId": "A", + "select": [ + [ + { + "params": [ + "script_version" + ], + "type": "column" + } + ] + ], + "table": "_devlake_migration_history", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "New Issue Count [Previous Week]", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 8, + "y": 4 + }, + "id": 22, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select\n count(*)\nfrom\n lake.issues as i\n join lake.board_issues bi on i.id = bi.issue_id\n join boards b on bi.board_id = b.id\nwhere\n i.type in ($issue_type)\n and date(i.created_date) BETWEEN curdate() - INTERVAL WEEKDAY(curdate())+7 DAY AND curdate() - INTERVAL WEEKDAY(curdate())+1 DAY\n and b.id in ($repo_id)\n and i.creator_id not in (select distinct id from accounts where organization in ($org))", + "refId": "A", + "select": [ + [ + { + "params": [ + "script_version" + ], + "type": "column" + } + ] + ], + "table": "_devlake_migration_history", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "New Issue Created by Community [Previous Week]", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 14, + "y": 4 + }, + "id": 23, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select\n sum(case when i.creator_id not in (select distinct id from accounts where organization in ($org)\n ) then 1 else 0 end)/count(*) as community_issue_ratio\nfrom\n lake.issues as i\n join lake.board_issues bi on i.id = bi.issue_id\n join boards b on bi.board_id = b.id\nwhere\n i.type in ($issue_type)\n and date(i.created_date) BETWEEN curdate() - INTERVAL WEEKDAY(curdate())+7 DAY AND curdate() - INTERVAL WEEKDAY(curdate())+1 DAY\n and b.id in ($repo_id)", + "refId": "A", + "select": [ + [ + { + "params": [ + "script_version" + ], + "type": "column" + } + ] + ], + "table": "_devlake_migration_history", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Ratio of New Issue Created by the Community [Previous Week]", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 4, + "x": 20, + "y": 4 + }, + "id": 45, + "options": { + "showHeader": true + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select\n distinct i.creator_name\nfrom\n lake.issues as i\n join lake.board_issues bi on i.id = bi.issue_id\n join boards b on bi.board_id = b.id\nwhere\n i.type in ($issue_type)\n and date(i.created_date) BETWEEN curdate() - INTERVAL WEEKDAY(curdate())+7 DAY AND curdate() - INTERVAL WEEKDAY(curdate())+1 DAY\n and b.id in ($repo_id)\n and i.creator_name not in (select distinct creator_name from issues where created_date < curdate() - INTERVAL WEEKDAY(curdate())+7 DAY and creator_name is not null)", + "refId": "A", + "select": [ + [ + { + "params": [ + "script_version" + ], + "type": "column" + } + ] + ], + "table": "_devlake_migration_history", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "1st Time Issue Reporter [Previous Week]", + "type": "table" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "yellow", + "value": 0.5 + }, + { + "color": "green", + "value": 0.8 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 12 + }, + "id": 24, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with issue_comment_list as(\n select\n i.id as issue_id,\n i.url,\n i.title,\n ic.id as comment_id,\n ic.created_date as comment_date,\n ic.body,\n case when ic.id is not null then rank() over (partition by i.id order by ic.created_date asc) else null end as comment_rank\n from\n issues i\n join board_issues bi on i.id = bi.issue_id\n join boards b on bi.board_id = b.id\n left join issue_comments ic on i.id = ic.issue_id\n where\n i.type in ($issue_type)\n and date(i.created_date) BETWEEN curdate() - INTERVAL WEEKDAY(curdate())+7 DAY AND curdate() - INTERVAL WEEKDAY(curdate())+1 DAY\n and b.id in ($repo_id)\n and i.creator_id not in (select distinct id from accounts where organization in ($org))\n)\n\nselect\n 1 - count(distinct case when comment_id is null then issue_id else null end)/count(distinct issue_id) as response_rate\nfrom issue_comment_list", + "refId": "A", + "select": [ + [ + { + "params": [ + "script_version" + ], + "type": "column" + } + ] + ], + "table": "_devlake_migration_history", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Community Issues' Response Rate [Previous Week]", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "title" + }, + "properties": [ + { + "id": "custom.width", + "value": 449 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "url" + }, + "properties": [ + { + "id": "custom.width", + "value": 415 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "issue_id" + }, + "properties": [ + { + "id": "custom.width", + "value": 117 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "status" + }, + "properties": [ + { + "id": "custom.width", + "value": 100 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "issue_number" + }, + "properties": [ + { + "id": "custom.width", + "value": 125 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 16, + "x": 8, + "y": 12 + }, + "id": 25, + "options": { + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with issue_comment_list as(\n select\n i.id as issue_id,\n i.url,\n i.title,\n i.creator_name,\n i.created_date as issue_created_date,\n i.status,\n ic.id as comment_id,\n ic.created_date as comment_date,\n ic.body,\n case when ic.id is not null then rank() over (partition by i.id order by ic.created_date asc) else null end as comment_rank\n from\n issues i\n join board_issues bi on i.id = bi.issue_id\n join boards b on bi.board_id = b.id\n left join issue_comments ic on i.id = ic.issue_id\n where\n i.type in ($issue_type)\n and date(i.created_date) BETWEEN curdate() - INTERVAL WEEKDAY(curdate())+7 DAY AND curdate() - INTERVAL WEEKDAY(curdate())+1 DAY\n and b.id in ($repo_id)\n and i.creator_id not in (select distinct id from accounts where organization in ($org))\n)\n\nselect \n SUBSTRING_INDEX(url, '/', -1) as issue_number,\n title,\n creator_name,\n issue_created_date,\n status,\n (TIMESTAMPDIFF(MINUTE,issue_created_date,NOW()))/1440 as 'queue_time_in_days',\n url\nfrom issue_comment_list\nwhere comment_id is null", + "refId": "A", + "select": [ + [ + { + "params": [ + "script_version" + ], + "type": "column" + } + ] + ], + "table": "_devlake_migration_history", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "List of New Community Issues with no Comments [Previous Week]", + "type": "table" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 1 + }, + { + "color": "red", + "value": 2 + } + ] + }, + "unit": "d" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 20 + }, + "id": 26, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with issue_comment_list as(\n select\n i.id as issue_id,\n i.url,\n i.title,\n i.created_date as issue_created_date,\n ic.id as comment_id,\n ic.created_date as comment_date,\n ic.body,\n case when ic.id is not null then rank() over (partition by i.id order by ic.created_date asc) else null end as comment_rank\n from\n issues i\n join board_issues bi on i.id = bi.issue_id\n join boards b on bi.board_id = b.id\n left join issue_comments ic on i.id = ic.issue_id\n where\n i.type in ($issue_type)\n and date(i.created_date) BETWEEN curdate() - INTERVAL WEEKDAY(curdate())+7 DAY AND curdate() - INTERVAL WEEKDAY(curdate())+1 DAY\n and b.id in ($repo_id)\n and i.creator_id not in (select distinct id from accounts where organization in ($org))\n)\n\nselect\n avg((TIMESTAMPDIFF(MINUTE, issue_created_date,comment_date))/1440)\nfrom issue_comment_list\nwhere comment_rank = 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "script_version" + ], + "type": "column" + } + ] + ], + "table": "_devlake_migration_history", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "New Community Issues' Average Response Time in Days [Previous Week]", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 0.2 + }, + { + "color": "red", + "value": 0.5 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "body" + }, + "properties": [ + { + "id": "custom.width", + "value": 364 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "url" + }, + "properties": [ + { + "id": "custom.width", + "value": null + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "issue_id" + }, + "properties": [ + { + "id": "custom.width", + "value": 73 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "comment_id" + }, + "properties": [ + { + "id": "custom.width", + "value": 106 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "comment_rank" + }, + "properties": [ + { + "id": "custom.width", + "value": 28 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "response_time_in_days" + }, + "properties": [ + { + "id": "custom.width", + "value": 184 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "issue_nunber" + }, + "properties": [ + { + "id": "custom.width", + "value": 127 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "issue_number" + }, + "properties": [ + { + "id": "custom.width", + "value": 122 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "title" + }, + "properties": [ + { + "id": "custom.width", + "value": 451 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "creator_name" + }, + "properties": [ + { + "id": "custom.width", + "value": 146 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "issue_created_date" + }, + "properties": [ + { + "id": "custom.width", + "value": 162 + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "comment_date" + }, + "properties": [ + { + "id": "custom.width", + "value": 160 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 16, + "x": 8, + "y": 20 + }, + "id": 28, + "options": { + "showHeader": true, + "sortBy": [] + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with issue_comment_list as(\n select\n SUBSTRING_INDEX(i.url, '/', -1) as issue_number,\n i.url,\n i.title,\n i.creator_name,\n i.created_date as issue_created_date,\n ic.id as comment_id,\n ic.created_date as comment_date,\n ic.body,\n case when ic.id is not null then rank() over (partition by i.id order by ic.created_date asc) else null end as comment_rank\n from\n issues i\n join board_issues bi on i.id = bi.issue_id\n join boards b on bi.board_id = b.id\n left join issue_comments ic on i.id = ic.issue_id\n where\n i.type in ($issue_type)\n and date(i.created_date) BETWEEN curdate() - INTERVAL WEEKDAY(curdate())+7 DAY AND curdate() - INTERVAL WEEKDAY(curdate())+1 DAY\n and b.id in ($repo_id)\n and i.creator_id not in (select distinct id from accounts where organization in ($org))\n)\n\nselect\n issue_number,\n title,\n -- body,\n creator_name,\n issue_created_date,\n comment_date,\n (TIMESTAMPDIFF(MINUTE, issue_created_date,comment_date))/60 as response_time_in_hours,\n url\nfrom issue_comment_list\nwhere comment_rank = 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "script_version" + ], + "type": "column" + } + ] + ], + "table": "_devlake_migration_history", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "List of New Community Issues' 1st Comment [Previous Week]", + "type": "table" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 28 + }, + "id": 44, + "panels": [], + "title": "Community PRs", + "type": "row" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 29 + }, + "id": 31, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select\n\tcount(*) as pull_request_count\nfrom \n\tpull_requests pr\nwhere\n date(created_date) BETWEEN curdate() - INTERVAL WEEKDAY(curdate())+7 DAY AND curdate() - INTERVAL WEEKDAY(curdate())+1 DAY\n\tand base_repo_id in ($repo_id)\n\t\n\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Number of New Pull Requests [Previous Week]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 8, + "y": 29 + }, + "id": 34, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select\n\tcount(*) as pull_request_count\nfrom \n\tpull_requests pr\nwhere\n date(created_date) BETWEEN curdate() - INTERVAL WEEKDAY(curdate())+7 DAY AND curdate() - INTERVAL WEEKDAY(curdate())+1 DAY\n\tand base_repo_id in ($repo_id)\n\tand author_id not in (select distinct id from accounts where organization in ($org))", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Number of New Pull Requests Created by the Community [Previous Week]", + "type": "stat" + }, + { + "datasource": "mysql", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 6, + "x": 14, + "y": 29 + }, + "id": 35, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select\n sum(case when author_id not in (select distinct id from accounts where organization in ($org))\n then 1 else 0 end)/count(*) as community_pr_ratio\nfrom\n pull_requests pr\nwhere\n date(created_date) BETWEEN curdate() - INTERVAL WEEKDAY(curdate())+7 DAY AND curdate() - INTERVAL WEEKDAY(curdate())+1 DAY\n\tand base_repo_id in ($repo_id)", + "refId": "A", + "select": [ + [ + { + "params": [ + "script_version" + ], + "type": "column" + } + ] + ], + "table": "_devlake_migration_history", + "timeColumn": "created_at", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Ratio of New PR Created by the Community [Previous Week]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 4, + "x": 20, + "y": 29 + }, + "id": 46, + "options": { + "showHeader": true + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select\n distinct author_name\nfrom \n\tpull_requests pr\nwhere\n date(created_date) BETWEEN curdate() - INTERVAL WEEKDAY(curdate())+7 DAY AND curdate() - INTERVAL WEEKDAY(curdate())+1 DAY\n\tand base_repo_id in ($repo_id)\n\tand author_name not in (select distinct author_name from pull_requests where created_date < curdate() - INTERVAL WEEKDAY(curdate())+7 DAY and author_name is not null)", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "First time Contributor [Previous Week]", + "type": "table" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 37 + }, + "id": 36, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select\n\tcount(*) as merged_pull_request_count\nfrom \n\tpull_requests pr\nwhere\n date(created_date) BETWEEN curdate() - INTERVAL WEEKDAY(curdate())+7 DAY AND curdate() - INTERVAL WEEKDAY(curdate())+1 DAY\n\tand base_repo_id in ($repo_id)\n\tand merged_date is not null\n\tand author_id not in (select distinct id from accounts where organization in ($org))", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Number of Merged Pull Requests Created by the Community [Previous Week]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "#EAB839", + "value": 0.5 + }, + { + "color": "green", + "value": 0.8 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 37 + }, + "id": 37, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select\n\tsum(case when merged_date is not null then 1 else 0 end)/ count(*) as merged_pull_request_ratio\nfrom \n\tpull_requests pr\nwhere\n date(created_date) BETWEEN curdate() - INTERVAL WEEKDAY(curdate())+7 DAY AND curdate() - INTERVAL WEEKDAY(curdate())+1 DAY\n\tand base_repo_id in ($repo_id)\n\tand author_id not in (select distinct id from accounts where organization in ($org))", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Ratio of Merged Pull Requests Created by the Community [Previous Week]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 3 + } + ] + }, + "unit": "d" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 37 + }, + "id": 39, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select\n\tavg(TIMESTAMPDIFF(Minute,created_date,merged_date)/1440)\nfrom \n\tpull_requests\nwhere \n date(created_date) BETWEEN curdate() - INTERVAL WEEKDAY(curdate())+7 DAY AND curdate() - INTERVAL WEEKDAY(curdate())+1 DAY\n\tand base_repo_id in ($repo_id)\n\tand merged_date is not null\n\tand author_id not in (select distinct id from accounts where organization in ($org))", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Average Time to Merge of Community Pull Requests in Days [Previous Week]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Merged PR Count", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 54, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 45 + }, + "id": 33, + "options": { + "barWidth": 0.5, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select\n author_name,\n\tcount(*) as pull_request_count\nfrom \n\tpull_requests pr\nwhere\n date(created_date) BETWEEN curdate() - INTERVAL WEEKDAY(curdate())+7 DAY AND curdate() - INTERVAL WEEKDAY(curdate())+1 DAY\n\tand base_repo_id in ($repo_id)\n\tand author_id not in (select distinct id from accounts where organization in ($org))\ngroup by 1\norder by 2 desc\nlimit 20\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Top Community Contributors By Number of PRs Created [Previous Week]", + "type": "barchart" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 45 + }, + "id": 40, + "options": { + "displayMode": "gradient", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "first" + ], + "fields": "", + "values": true + }, + "showUnfilled": true, + "text": { + "valueSize": 1 + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "hide": false, + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select\n author_name,\n\tcount(*) as merged_pull_request_count\nfrom \n\tpull_requests pr\nwhere\n $__timeFilter(created_date)\n\tand base_repo_id in ($repo_id)\n\tand author_id not in (select distinct id from accounts where organization in ($org))\ngroup by 1\norder by 2 desc\nlimit 20\n", + "refId": "A", + "select": [ + [ + { + "params": [ + "id" + ], + "type": "column" + } + ] + ], + "table": "ae_projects", + "timeColumn": "ae_create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Top Community Contributors By PRs Created [All History]", + "type": "bargauge" + }, + { + "datasource": null, + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 54 + }, + "id": 50, + "options": { + "content": "
\n\nThis dashboard is created based on this [data schema](https://devlake.apache.org/docs/DataModels/DevLakeDomainLayerSchema). Want to add more metrics? Please follow the [guide](https://devlake.apache.org/docs/Configuration/Dashboards/GrafanaUserGuide).", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + } + ], + "refresh": "", + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": "mysql", + "definition": "select concat(name, '-', id) as text from repos", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Repo", + "multi": true, + "name": "repo_id", + "options": [], + "query": "select concat(name, '-', id) as text from repos", + "refresh": 1, + "regex": "/^(?.*)-(?.*)$/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "allValue": null, + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "mysql", + "definition": "select distinct type from issues", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Issue Type", + "multi": false, + "name": "issue_type", + "options": [], + "query": "select distinct type from issues", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "allValue": null, + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": "mysql", + "definition": "select distinct organization from accounts where organization != ''", + "description": "", + "error": null, + "hide": 0, + "includeAll": true, + "label": "Community Definition - Issues and PRs NOT from Organization(s)", + "multi": true, + "name": "org", + "options": [], + "query": "select distinct organization from accounts where organization != ''", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-6M", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Weekly Community Retro", + "uid": "VTr6Y_q7z", + "version": 3 +} \ No newline at end of file diff --git a/charts/devlake/dashboards/Zentao.json b/charts/devlake/dashboards/Zentao.json new file mode 100644 index 0000000..14b6d8c --- /dev/null +++ b/charts/devlake/dashboards/Zentao.json @@ -0,0 +1,1031 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 23, + "iteration": 1673170738316, + "links": [ + { + "asDropdown": false, + "icon": "bolt", + "includeVars": false, + "keepTime": true, + "tags": [], + "targetBlank": false, + "title": "Homepage", + "tooltip": "", + "type": "link", + "url": "/grafana/d/Lv1XbLHnk/data-specific-dashboards-homepage" + }, + { + "asDropdown": false, + "icon": "external link", + "includeVars": false, + "keepTime": true, + "tags": [ + "Data Source Specific Dashboard" + ], + "targetBlank": false, + "title": "Metric dashboards", + "tooltip": "", + "type": "dashboards", + "url": "" + } + ], + "panels": [ + { + "datasource": null, + "gridPos": { + "h": 3, + "w": 13, + "x": 0, + "y": 0 + }, + "id": 128, + "options": { + "content": "- Use Cases: This dashboard shows the basic project management metrics from Zentao.\n- Data Source Required: Zentao", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "title": "Dashboard Introduction", + "type": "text" + }, + { + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 3 + }, + "id": 126, + "title": "1. Issue Throughput", + "type": "row" + }, + { + "datasource": "mysql", + "description": "1. Total number of issues created.\n2. The requirements being calculated are filtered by \"requirement creation time\" (time filter at the upper-right corner) and \"Jira board\" (\"Choose Board\" filter at the upper-left corner)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 0, + "y": 4 + }, + "id": 114, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select \r\n count(*) as value\r\nfrom issues i\r\n join board_issues bi on i.id = bi.issue_id\r\nwhere \r\n i.type in ($type)\r\n and $__timeFilter(i.created_date)\r\n and bi.board_id in ($board_id)", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Number of Issues [Issues Created in Selected Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 4, + "y": 4 + }, + "id": 116, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "select \r\n count(*) as value\r\nfrom issues i\r\n join board_issues bi on i.id = bi.issue_id\r\nwhere \r\n i.type in ($type)\r\n and i.status = 'DONE'\r\n and $__timeFilter(i.created_date)\r\n and bi.board_id in ($board_id)", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Number of Delivered Issue [Issues Created in Selected Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 1, + "drawStyle": "bars", + "fillOpacity": 12, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 16, + "x": 8, + "y": 4 + }, + "id": 120, + "interval": null, + "options": { + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "SELECT\r\n DATE_ADD(date(i.created_date), INTERVAL -DAYOFMONTH(date(i.created_date))+1 DAY) as time,\r\n count(distinct case when status != 'DONE' then i.id else null end) as \"Number of Open Issues\",\r\n count(distinct case when status = 'DONE' then i.id else null end) as \"Number of Delivered Issues\"\r\nFROM issues i\r\n\tjoin board_issues bi on i.id = bi.issue_id\r\n\tjoin boards b on bi.board_id = b.id\r\nwhere \r\n i.type in ($type)\r\n and $__timeFilter(i.created_date)\r\n and bi.board_id in ($board_id)\r\ngroup by 1", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Issue Status Distribution over Month [Issues Created in Selected Time Range]", + "type": "timeseries" + }, + { + "datasource": "mysql", + "description": "Issue Delivery Rate = count(Delivered Issues)/count(Issues)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "percentage", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 50 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 8, + "x": 0, + "y": 10 + }, + "id": 117, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with _requirements as(\r\n select\r\n count(distinct i.id) as total_count,\r\n count(distinct case when i.status = 'DONE' then i.id else null end) as delivered_count\r\n from issues i\r\n join board_issues bi on i.id = bi.issue_id\r\n where \r\n i.type in ($type)\r\n and $__timeFilter(i.created_date)\r\n and bi.board_id in ($board_id)\r\n)\r\n\r\nselect \r\n now() as time,\r\n 1.0 * delivered_count/total_count as requirement_delivery_rate\r\nfrom _requirements", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "title": "Issue Delivery Rate [Issues Created in Selected Time Range]", + "type": "stat" + }, + { + "cacheTimeout": null, + "datasource": "mysql", + "description": "Issue Delivery Rate = count(Delivered Issues)/count(Issues)", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Delivery Rate(%)", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 12, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 16, + "x": 8, + "y": 10 + }, + "id": 121, + "links": [], + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "queryType": "randomWalk", + "rawQuery": true, + "rawSql": "with _requirements as(\r\n select\r\n DATE_ADD(date(i.created_date), INTERVAL -DAYOFMONTH(date(i.created_date))+1 DAY) as time,\r\n 1.0 * count(distinct case when i.status = 'DONE' then i.id else null end)/count(distinct i.id) as delivered_rate\r\n from issues i\r\n join board_issues bi on i.id = bi.issue_id\r\n where \r\n i.type in ($type)\r\n and $__timeFilter(i.created_date)\r\n and bi.board_id in ($board_id)\r\n group by 1\r\n)\r\n\r\nselect\r\n time,\r\n delivered_rate\r\nfrom _requirements\r\norder by time", + "refId": "A", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "column" + } + ] + ], + "timeColumn": "time", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Issue Delivery Rate over Time [Issues Created in Selected Time Range]", + "type": "timeseries" + }, + { + "collapsed": false, + "datasource": null, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 16 + }, + "id": 110, + "panels": [], + "title": "2. Issue Lead Time", + "type": "row" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "decimals": 1, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 14 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 0, + "y": 17 + }, + "id": 12, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "/^value$/", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "select \r\n avg(lead_time_minutes/1440) as value\r\nfrom issues i\r\n join board_issues bi on i.id = bi.issue_id\r\nwhere \r\n i.type in ($type)\r\n and i.status = 'DONE'\r\n and $__timeFilter(i.resolution_date)\r\n and bi.board_id in ($board_id)", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Mean Issue Lead Time in Days [Issues Resolved in Select Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 21 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 4, + "x": 4, + "y": 17 + }, + "id": 13, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _ranks as(\r\n select \r\n i.lead_time_minutes,\r\n percent_rank() over (order by lead_time_minutes asc) as ranks\r\n from issues i\r\n join board_issues bi on i.id = bi.issue_id\r\n where \r\n i.type in ($type)\r\n and i.status = 'DONE'\r\n and $__timeFilter(i.resolution_date)\r\n and bi.board_id in ($board_id)\r\n)\r\n\r\nselect\r\n max(lead_time_minutes/1440) as value\r\nfrom _ranks\r\nwhere \r\n ranks <= 0.8", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "80% Issues' Lead Time are less than # days [Issues Resolved in Select Time Range]", + "type": "stat" + }, + { + "datasource": "mysql", + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "Lead Time(days)", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 16, + "x": 8, + "y": 17 + }, + "id": 17, + "interval": "", + "options": { + "barWidth": 0.5, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "orientation": "auto", + "showValue": "auto", + "text": { + "valueSize": 12 + }, + "tooltip": { + "mode": "single" + } + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "format": "table", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _requirements as(\r\n select \r\n DATE_ADD(date(i.resolution_date), INTERVAL -DAYOFMONTH(date(i.resolution_date))+1 DAY) as time,\r\n avg(lead_time_minutes/1440) as mean_lead_time\r\n from issues i\r\n join board_issues bi on i.id = bi.issue_id\r\n where \r\n i.type in ($type)\r\n and i.status = 'DONE'\r\n and $__timeFilter(i.resolution_date)\r\n and bi.board_id in ($board_id)\r\n group by 1\r\n)\r\n\r\nselect \r\n date_format(time,'%M %Y') as month,\r\n mean_lead_time\r\nfrom _requirements\r\norder by time asc", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Mean Issue Lead Time [Issues Resolved in Select Time Range]", + "type": "barchart" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "mysql", + "description": "1. The cumulative distribution of requirement lead time. \n2. Each point refers to the percent rank of a lead time.", + "fill": 0, + "fillGradient": 4, + "gridPos": { + "h": 6, + "w": 24, + "x": 0, + "y": 23 + }, + "hiddenSeries": false, + "id": 15, + "legend": { + "alignAsTable": false, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": false, + "show": false, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 8, + "nullPointMode": "null", + "options": { + "alertThreshold": false + }, + "percentage": false, + "pluginVersion": "8.0.6", + "pointradius": 0.5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "format": "time_series", + "group": [], + "metricColumn": "none", + "rawQuery": true, + "rawSql": "with _ranks as(\r\n select \r\n round(i.lead_time_minutes/1440) as lead_time_day\r\n from issues i\r\n join board_issues bi on i.id = bi.issue_id\r\n where \r\n i.type in ($type)\r\n and i.status = 'DONE'\r\n and $__timeFilter(i.resolution_date)\r\n and bi.board_id in ($board_id)\r\n order by lead_time_day asc\r\n)\r\n\r\nselect \r\n now() as time,\r\n lpad(concat(lead_time_day,'d'), 4, ' ') as metric,\r\n percent_rank() over (order by lead_time_day asc) as value\r\nfrom _ranks\r\norder by lead_time_day asc", + "refId": "A", + "select": [ + [ + { + "params": [ + "progress" + ], + "type": "column" + } + ] + ], + "table": "ca_analysis", + "timeColumn": "create_time", + "timeColumnType": "timestamp", + "where": [ + { + "name": "$__timeFilter", + "params": [], + "type": "macro" + } + ] + } + ], + "thresholds": [ + { + "$$hashKey": "object:469", + "colorMode": "ok", + "fill": true, + "line": true, + "op": "lt", + "value": 0.8, + "yaxis": "right" + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Cumulative Distribution of Requirement Lead Time [Issues Resolved in Select Time Range]", + "tooltip": { + "shared": false, + "sort": 0, + "value_type": "individual" + }, + "transformations": [], + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "series", + "name": null, + "show": true, + "values": [ + "current" + ] + }, + "yaxes": [ + { + "$$hashKey": "object:76", + "format": "percentunit", + "label": "Percent Rank (%)", + "logBase": 1, + "max": "1.2", + "min": null, + "show": true + }, + { + "$$hashKey": "object:77", + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": false + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "datasource": null, + "gridPos": { + "h": 2, + "w": 24, + "x": 0, + "y": 29 + }, + "id": 130, + "options": { + "content": "
\n\nThis dashboard is created based on this [data schema](https://devlake.apache.org/docs/DataModels/DevLakeDomainLayerSchema). Want to add more metrics? Please follow the [guide](https://devlake.apache.org/docs/Configuration/Dashboards/GrafanaUserGuide).", + "mode": "markdown" + }, + "pluginVersion": "8.0.6", + "targets": [ + { + "queryType": "randomWalk", + "refId": "A" + } + ], + "type": "text" + } + ], + "refresh": "", + "schemaVersion": 30, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": "mysql", + "definition": "select concat(name, '--', id) from boards where id like 'zentao%'", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Choose Board", + "multi": true, + "name": "board_id", + "options": [], + "query": "select concat(name, '--', id) from boards where id like 'zentao%'", + "refresh": 1, + "regex": "/^(?.*)--(?.*)$/", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "allValue": null, + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "datasource": "mysql", + "definition": "select distinct type from issues", + "description": null, + "error": null, + "hide": 0, + "includeAll": true, + "label": "Issue Type", + "multi": false, + "name": "type", + "options": [], + "query": "select distinct type from issues", + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + } + ] + }, + "time": { + "from": "now-6M", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Zentao", + "uid": "yMb4MKh4k", + "version": 3 +} \ No newline at end of file diff --git a/charts/devlake/templates/configmaps.yaml b/charts/devlake/templates/configmaps.yaml index c5d263b..b975b8f 100644 --- a/charts/devlake/templates/configmaps.yaml +++ b/charts/devlake/templates/configmaps.yaml @@ -33,47 +33,3 @@ data: ADMIN_USER: "{{ .Values.ui.basicAuth.user }}" ADMIN_PASS: "{{ .Values.ui.basicAuth.password }}" {{- end }} ---- -{{- if not .Values.grafana.useExternal }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "devlake.fullname" . }}-grafana-datasource -data: -{{- if eq .Values.option.database "mysql" }} - grafana-datasource.yml: | - apiVersion: 1 - datasources: - - name: mysql - type: mysql - url: $MYSQL_URL - database: $MYSQL_DATABASE - user: $MYSQL_USER - secureJsonData: - password: $MYSQL_PASSWORD - editable: false -{{- end }} -{{- end }} ---- -{{- if .Values.grafana.oauthEnabled }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "devlake.fullname" . }}-grafana-oauth-config -data: - {{- with .Values.grafana.oauthConfig }} - {{- toYaml . | nindent 2 }} - {{- end }} -{{- end }} ---- -{{- if .Values.awsCognitoAuth.enabled }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "devlake.fullname" . }}-cognito-config -data: - AWS_ENABLE_COGNITO: "true" - AWS_AUTH_REGION: "{{ .Values.awsCognitoAuth.awsAuthRegion }}" - AWS_AUTH_USER_POOL_ID: "{{ .Values.awsCognitoAuth.awsAuthUserPoolID }}" - AWS_AUTH_USER_POOL_WEB_CLIENT_ID: "{{ .Values.awsCognitoAuth.awsAuthUserPoolWebClientID }}" -{{- end }} diff --git a/charts/devlake/templates/deployments.yaml b/charts/devlake/templates/deployments.yaml index 1d673e5..dd7a1a4 100644 --- a/charts/devlake/templates/deployments.yaml +++ b/charts/devlake/templates/deployments.yaml @@ -15,109 +15,6 @@ # limitations under the License. # --- -{{- if not .Values.grafana.useExternal }} -# grafana -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "devlake.fullname" . }}-grafana - labels: - {{- include "devlake.labels" . | nindent 4 }} -spec: - replicas: 1 - selector: - matchLabels: - {{- include "devlake.selectorLabels" . | nindent 6 }} - template: - metadata: - labels: - {{- include "devlake.selectorLabels" . | nindent 8 }} - devlakeComponent: grafana - {{- with .Values.grafana.extraLabels }} - {{- toYaml . | nindent 8 }} - {{- end }} - spec: - {{- with .Values.grafana.securityContext }} - securityContext: - {{- toYaml . | nindent 8 }} - {{- end }} - initContainers: - {{- include "common.initContainerWaitDatabase" . | nindent 8 }} - {{- with .Values.grafana.containerSecurityContext }} - securityContext: - {{- toYaml . | nindent 12 }} - {{- end }} - containers: - - name: grafana - image: "{{ .Values.grafana.image.repository }}:{{ .Values.imageTag }}" - imagePullPolicy: {{ .Values.grafana.image.pullPolicy }} - ports: - - containerPort: 3000 - livenessProbe: - httpGet: - path: /api/health - port: 3000 - initialDelaySeconds: 30 - timeoutSeconds: 30 - volumeMounts: - {{- if ne .Values.option.localtime "" }} - - name: {{ include "devlake.fullname" . }}-grafana-localtime - mountPath: /etc/localtime - readOnly: true - {{- end }} - - name: {{ include "devlake.fullname" . }}-grafana-datasource-config - mountPath: /etc/grafana/provisioning/datasources/datasource.yml - subPath: grafana-datasource.yml - envFrom: - - configMapRef: - name: {{ include "devlake.fullname" . }}-config - {{- if .Values.grafana.oauthEnabled }} - - configMapRef: - name: {{ include "devlake.fullname" . }}-grafana-oauth-config - {{- end }} - {{- if .Values.option.useConnectionDetailsSecret }} - - secretRef: - name: {{ .Values.option.connectionSecretName }} - {{- end }} - env: - {{ if not .Values.grafana.oauthEnabled }} - - name: GF_SERVER_ROOT_URL - value: "%(protocol)s://%(domain)s:%(http_port)s/grafana/" - {{ end }} - - name: MYSQL_URL - value: {{ include "mysql.server" . }}:{{ include "mysql.port" . }} - {{- with .Values.grafana.resources }} - resources: - {{- toYaml . | nindent 12 }} - {{- end }} - {{- with .Values.grafana.containerSecurityContext }} - securityContext: - {{- toYaml . | nindent 12 }} - {{- end }} - {{- with .Values.grafana.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.grafana.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.grafana.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} - volumes: - {{- if ne .Values.option.localtime "" }} - - name: {{ include "devlake.fullname" . }}-grafana-localtime - hostPath: - path: {{ .Values.option.localtime }} - type: File - {{- end }} - - name: {{ include "devlake.fullname" . }}-grafana-datasource-config - configMap: - name: {{ include "devlake.fullname" . }}-grafana-datasource -{{ end }} ---- # devlake-ui apiVersion: apps/v1 kind: Deployment @@ -162,17 +59,17 @@ spec: {{- end }} env: - name: DEVLAKE_ENDPOINT - # TODO: remove hardcoded `cluster.local` value: {{ include "devlake.fullname" . }}-lake.{{ .Release.Namespace }}.svc.cluster.local:8080 -{{- if .Values.grafana.useExternal }} +{{- if .Values.externalGrafana.useExternal }} - name: GRAFANA_ENDPOINT - value: {{ .Values.grafana.externalUrl }} + value: {{ .Values.externalGrafana.grafanaUrl }} - name: USE_EXTERNAL_GRAFANA value: "true" {{- else }} - name: GRAFANA_ENDPOINT - value: {{ include "devlake.fullname" . }}-grafana.{{ .Release.Namespace }}.svc.cluster.local:3000 + value: {{ .Release.Name }}-grafana.{{ .Release.Namespace }}.svc.cluster.local:80 {{- end }} + volumeMounts: {{- if ne .Values.option.localtime "" }} - name: {{ include "devlake.fullname" . }}-ui-localtime diff --git a/charts/devlake/templates/grafana-dashboard-configmap.yaml b/charts/devlake/templates/grafana-dashboard-configmap.yaml new file mode 100644 index 0000000..01bb445 --- /dev/null +++ b/charts/devlake/templates/grafana-dashboard-configmap.yaml @@ -0,0 +1,64 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: grafana-dashboards + labels: + grafana_dashboard: "1" +data: + bitbucket.json: | +{{ .Files.Get "dashboards/BitBucket.json" | indent 4 }} + componentandfilelevelmetrics.json: | +{{ .Files.Get "dashboards/ComponentAndFileLevelMetrics.json" | indent 4 }} + contributorexperience.json: | +{{ .Files.Get "dashboards/ContributorExperience.json" | indent 4 }} + dora.json: | +{{ .Files.Get "dashboards/DORA.json" | indent 4 }} + dorabyteam.json: | +{{ .Files.Get "dashboards/DORAByTeam.json" | indent 4 }} + doradebug.json: | +{{ .Files.Get "dashboards/DORADebug.json" | indent 4 }} + demoaveragerequirementleadtimebyassignee.json: | +{{ .Files.Get "dashboards/DemoAverageRequirementLeadTimeByAssignee.json" | indent 4 }} + democommitcountbyauthor.json: | +{{ .Files.Get "dashboards/DemoCommitCountByAuthor.json" | indent 4 }} + demodetailedbuginfo.json: | +{{ .Files.Get "dashboards/DemoDetailedBugInfo.json" | indent 4 }} + demohomepage.json: | +{{ .Files.Get "dashboards/DemoHomepage.json" | indent 4 }} + demohowfastdowerespondtocustomerrequirements.json: | +{{ .Files.Get "dashboards/DemoHowFastDoWeRespondToCustomerRequirements.json" | indent 4 }} + demoisthismonthmoreproductivethanlast.json: | +{{ .Files.Get "dashboards/DemoIsThisMonthMoreProductiveThanLast.json" | indent 4 }} + demowasourqualityimprovedornot.json: | +{{ .Files.Get "dashboards/DemoWasOurQualityImprovedOrNot.json" | indent 4 }} + engineeringoverview.json: | +{{ .Files.Get "dashboards/EngineeringOverview.json" | indent 4 }} + engineeringthroughputandcycletime.json: | +{{ .Files.Get "dashboards/EngineeringThroughputAndCycleTime.json" | indent 4 }} + engineeringthroughputandcycletimeteamview.json: | +{{ .Files.Get "dashboards/EngineeringThroughputAndCycleTimeTeamView.json" | indent 4 }} + github.json: | +{{ .Files.Get "dashboards/GitHub.json" | indent 4 }} + githubreleasequalityandcontributionanalysis.json: | +{{ .Files.Get "dashboards/GithubReleaseQualityAndContributionAnalysis.json" | indent 4 }} + gitlab.json: | +{{ .Files.Get "dashboards/Gitlab.json" | indent 4 }} + homepage.json: | +{{ .Files.Get "dashboards/Homepage.json" | indent 4 }} + jenkins.json: | +{{ .Files.Get "dashboards/Jenkins.json" | indent 4 }} + jira.json: | +{{ .Files.Get "dashboards/Jira.json" | indent 4 }} + sonarqube.json: | +{{ .Files.Get "dashboards/Sonarqube.json" | indent 4 }} + tapd.json: | +{{ .Files.Get "dashboards/TAPD.json" | indent 4 }} + teambition.json: | +{{ .Files.Get "dashboards/Teambition.json" | indent 4 }} + weeklybugretro.json: | +{{ .Files.Get "dashboards/WeeklyBugRetro.json" | indent 4 }} + weeklycommunityretro.json: | +{{ .Files.Get "dashboards/WeeklyCommunityRetro.json" | indent 4 }} + zentao.json: | +{{ .Files.Get "dashboards/Zentao.json" | indent 4 }} diff --git a/charts/devlake/templates/ingresses.yaml b/charts/devlake/templates/ingresses.yaml index ef206ac..5426419 100644 --- a/charts/devlake/templates/ingresses.yaml +++ b/charts/devlake/templates/ingresses.yaml @@ -21,7 +21,6 @@ {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} {{- end }} {{- end }} - --- {{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} apiVersion: networking.k8s.io/v1 @@ -56,8 +55,7 @@ spec: - host: {{ .Values.ingress.hostname | quote }} http: paths: - {{- if not .Values.grafana.oauthEnabled }} - {{- if not .Values.grafana.useExternal }} + {{- if not .Values.externalGrafana.useExternal }} {{- if .Values.ingress.useDefaultNginx }} - path: /{{ include "devlake.grafanaEndpointPrefix" . }}(/|$)(.*) {{- else }} @@ -77,7 +75,6 @@ spec: servicePort: 3000 {{- end }} {{- end }} - {{- end }} {{- if .Values.ingress.useDefaultNginx }} - path: /{{ include "devlake.uiEndpointPrefix" . }}(/?|$)(.*) {{- else }} @@ -97,7 +94,7 @@ spec: servicePort: 4000 {{- end }} -{{- if and .Values.ingress.useDefaultNginx .Values.grafana.useExternal }} +{{- if and .Values.ingress.useDefaultNginx .Values.externalGrafana.useExternal }} --- {{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} apiVersion: networking.k8s.io/v1 @@ -113,7 +110,7 @@ metadata: {{- include "devlake.labels" . | nindent 4 }} annotations: nginx.ingress.kubernetes.io/rewrite-target: /$2 - nginx.ingress.kubernetes.io/permanent-redirect: {{ .Values.grafana.externalUrl }} + nginx.ingress.kubernetes.io/permanent-redirect: {{ .Values.externalGrafana.grafanaUrl }} {{- with .Values.ingress.annotations }} {{- toYaml . | nindent 4 }} {{- end }} diff --git a/charts/devlake/templates/services.yaml b/charts/devlake/templates/services.yaml index 586e84e..d8972c5 100644 --- a/charts/devlake/templates/services.yaml +++ b/charts/devlake/templates/services.yaml @@ -35,50 +35,7 @@ spec: port: 3306 targetPort: 3306 {{- end }} -#{{- else if eq .Values.option.database "pgsql" }} -#{{- if not .Values.pgsql.useExternal }} -#apiVersion: v1 -#kind: Service -#metadata: -# name: {{ include "devlake.fullname" . }}-pgsql -# labels: -# {{- include "devlake.labels" . | nindent 4 }} -#spec: -# selector: -# {{- include "devlake.selectorLabels" . | nindent 4 }} -# devlakeComponent: pgsql -# ports: -# - protocol: TCP -# name: pgsql -# port: 5432 -# targetPort: 5432 -#{{- end }} {{- end }} - -{{- if not .Values.grafana.useExternal }} -# grafana services ---- -apiVersion: v1 -kind: Service -metadata: - name: {{ include "devlake.fullname" . }}-grafana - labels: - {{- include "devlake.labels" . | nindent 4 }} -spec: - type: {{ .Values.service.type}} - selector: - {{- include "devlake.selectorLabels" . | nindent 4 }} - devlakeComponent: grafana - ports: - - protocol: TCP - name: grafana - port: 3000 - targetPort: 3000 - {{- if eq .Values.service.type "NodePort" }} - nodePort: {{ .Values.service.grafanaPort }} - {{- end }} -{{ end }} - # devlake services --- apiVersion: v1 @@ -96,7 +53,6 @@ spec: name: devlake port: 8080 targetPort: 8080 - --- # ui apiVersion: v1 diff --git a/charts/devlake/templates/statefulsets.yaml b/charts/devlake/templates/statefulsets.yaml index 25fb011..62e21d7 100644 --- a/charts/devlake/templates/statefulsets.yaml +++ b/charts/devlake/templates/statefulsets.yaml @@ -216,10 +216,6 @@ spec: - secretRef: name: {{ .Values.option.connectionSecretName }} {{- end }} - {{- if .Values.awsCognitoAuth.enabled }} - - configMapRef: - name: {{ include "devlake.fullname" . }}-cognito-config - {{- end }} env: - name: ENV_PATH value: /app/config/.env diff --git a/charts/devlake/values.yaml b/charts/devlake/values.yaml index 49a130d..58bcccb 100644 --- a/charts/devlake/values.yaml +++ b/charts/devlake/values.yaml @@ -121,68 +121,43 @@ mysql: # containerSecurityContext: {} -grafana: - # image for grafana - image: - repository: apache/devlake-dashboard - pullPolicy: Always - - # If true, the default Nginx configuration will support a permanent redirect - # in the tool's menu. Should you use a different ingress controller, you'll need - # to add the ingress with the permanent redirect. +externalGrafana: useExternal: false + grafanaUrl: "" - externalUrl: "" - - resources: {} - - nodeSelector: {} - - tolerations: [] - - affinity: {} - - extraLabels: {} - - securityContext: {} - - containerSecurityContext: {} - - # Enable oauth, defaults to false - oauthEnabled: false - # grafana oauth related env vars, see the example below for aws cognito oauth - oauthConfig: - {} - # GF_SERVER_ROOT_URL: "https://demo.devlake.pro/grafana/" - # GF_AUTH_JWT_ENABLED: "true" - # GF_AUTH_JWT_HEADER_NAME: X-Forwarded-Access-Token - # GF_AUTH_JWT_USERNAME_CLAIM: username - # GF_AUTH_JWT_SKIP_ORG_ROLE_SYNC: "true" - # GF_AUTH_JWT_ROLE_ATTRIBUTE_PATH: contains("cognito:groups"[*], 'Admin') && 'Admin' - # GF_AUTH_JWT_CACHE_TTL: "60m" - # GF_AUTH_EXPECTED_CLAIMS: '{"iss": "https://cognito-idp.us-east-2.amazonaws.com/us-east-2_xxx"}' - # GF_AUTH_JWT_JWK_SET_URL: https://cognito-idp.us-east-2.amazonaws.com/us-east-2_xxx/.well-known/jwks.json - # GF_AUTH_GENERIC_OAUTH_ENABLED: "true" - # GF_AUTH_GENERIC_OAUTH_AUTO_LOGIN: "true" - # GF_AUTH_GENERIC_OAUTH_NAME: Amazon - # GF_AUTH_GENERIC_OAUTH_SCOPES: "email profile aws.cognito.signin.user.admin openid" - # GF_AUTH_GENERIC_OAUTH_CLIENT_ID: xxx - # GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET: "" - # GF_AUTH_GENERIC_OAUTH_AUTH_URL: https://xxx.auth.us-east-2.amazoncognito.com/oauth2/authorize - # GF_AUTH_GENERIC_OAUTH_TOKEN_URL: https://xxx.auth.us-east-2.amazoncognito.com/oauth2/token - # GF_AUTH_GENERIC_OAUTH_API_URL: https://xxx.auth.us-east-2.amazoncognito.com/oauth2/userInfo - # GF_AUTH_GENERIC_OAUTH_ALLOW_SIGN_UP: "true" - # GF_AUTH_GENERIC_OAUTH_SIGNOUT_REDIRECT_URL: https://xxx.auth.us-east-2.amazoncognito.com/logout?client_id=$GF_AUTH_GENERIC_OAUTH_CLIENT_ID&logout_uri=https://demo.devlake.pro/grafana/login - # GF_AUTH_GENERIC_OAUTH_ROLE_ATTRIBUTE_PATH: contains("cognito:groups"[*], 'Admin') && 'Admin' - # GF_SECURITY_DISABLE_INITIAL_ADMIN_CREATION: "true" - -awsCognitoAuth: - # by default, AWS Cognito auth is disabled - # if enabled, please set the following 3 awsXXX variables - enabled: false - awsAuthRegion: "" - awsAuthUserPoolID: "" - awsAuthUserPoolWebClientID: "" +# dependency chart values +grafana: + grafana.ini: + server: + root_url: "%(protocol)s://%(domain)s/grafana" + dashboardProviders: + dashboard.yaml: + apiVersion: 1 + providers: + - name: default + org_id: 1 + folder: "" + type: "file" + disableDeletion: false + editable: true + updateIntervalSeconds: 5 + allowUiUpdates: true + options: + path: /var/lib/grafana/dashboards/default + dashboardsConfigMaps: + default: "grafana-dashboards" + datasources: + datasource.yaml: + apiVersion: 1 + datasources: + - name: mysql + type: mysql + url: devlake-mysql:3306 + database: lake + user: merico + secureJsonData: + password: merico + editable: false lake: image: @@ -278,7 +253,6 @@ service: type: NodePort # node port for devlake-ui if NodePort is enabled uiPort: 32001 - grafanaPort: 32002 ingress: enabled: false