From 72e7706f29b92216b1442668ab393e7d4c275543 Mon Sep 17 00:00:00 2001 From: Kyongsik Yun Date: Tue, 15 Apr 2025 21:31:35 -0700 Subject: [PATCH 1/7] add simple metrics gathering --- .../software-lifecycle/metrics/README.md | 70 ++++++++++++++++--- 1 file changed, 61 insertions(+), 9 deletions(-) diff --git a/docs/guides/software-lifecycle/metrics/README.md b/docs/guides/software-lifecycle/metrics/README.md index 743f11ef3..8b436014f 100644 --- a/docs/guides/software-lifecycle/metrics/README.md +++ b/docs/guides/software-lifecycle/metrics/README.md @@ -7,29 +7,51 @@ ## Introduction -Metrics collection is important for project management and software quality assurance. We recommend [Apache DevLake](https://devlake.apache.org/) for easy tracking and analysis. This guide simplifies its installation and configuration, especially for developers new to metrics collection. +Metrics collection is important for project management and software quality assurance. This guide provides two tool recommendations for collecting and visualizing metrics, depending on the complexity of your project: +- For complex, multi-repository metrics gathering: We recommend [Apache DevLake](https://devlake.apache.org/) for detailed metrics tracking and analysis. +- For simpler, single-repository projects: We recommend using GitHub Actions-based tools for easy integration and basic metrics collection. Specifically, the [DeveloperMetrics GitHub Action](https://github.com/DeveloperMetrics), which enables you to quickly gather and display DORA metrics with minimal configuration. **Use Cases**: - Collecting and analyzing [DORA metrics](https://devlake.apache.org/docs/DORA/) along with many others for your project. - Creating a visual dashboard to view metrics from multiple sources (e.g., GitHub, JIRA) in one place. -- Streamlining the setup and configuration of Apache DevLake through a *single-command* setup step. -- Gain insight into organizational and project performance for software development and the overall software lifecycle. +- Streamlining the setup and configuration of metrics collection through a single-command setup step or plug-and-play GitHub Action. +- Simplifying metrics collection for smaller projects to encourage broader adoption. -**Why We Chose Apache DevLake:** -Our decision to select Apache DevLake was informed by thorough trade study documentation, available [here](https://github.com/NASA-AMMOS/slim/issues/117#issuecomment-1802302091). +## Tool Options ---- +### 1. **Apache DevLake** for Complex Multi-Repository Projects -## Prerequisites +DevLake is a powerful and flexible tool for gathering and visualizing software lifecycle metrics across multiple repositories. It requires Docker and some configuration but is ideal for teams managing several repositories or those needing in-depth metrics analysis. +**Prerequisites**: - Familiarity with [Docker](https://docs.docker.com/engine/install/) as well as a running instance of it - A familiarity with validated software metrics is not required for this tool but it is recommended +**Why We Chose Apache DevLake**: + +- Our decision to select Apache DevLake was informed by thorough trade study documentation, available [here](https://github.com/NASA-AMMOS/slim/issues/117#issuecomment-1802302091). +- Offers detailed metrics analysis for complex projects. +- Supports various data sources (GitHub, Jira, etc.) and can create powerful visual dashboards. +- Well-suited for projects requiring a deeper understanding of organizational and project performance. + + +### 2. **DeveloperMetrics GitHub Action** for Simple Single-Repository Projects + +For smaller, simpler projects, where full DevLake setup might be too cumbersome, we recommend the [DeveloperMetrics GitHub Action](https://github.com/DeveloperMetrics). This tool allows you to quickly collect basic DORA metrics (e.g., deployment frequency, lead time for changes) and display results as badges in your project README. + +**Why We Recommend DeveloperMetrics**: + +- Lightweight, quick to integrate into any GitHub repository via GitHub Actions. +- No server setup or Docker required—ideal for developers who want an easy solution. +- Automatically collects basic DORA metrics, with results visible as badges on your repository. +- SLIM can automatically submit PRs to infuse this action into repositories, making it easier to adopt. + + --- -## Quick Start +## Quick Start: Apache DevLake To quickly deploy DevLake on one of your servers or locally for testing, we've developed a convenient 1-step command. Please ensure Docker is running on your system before executing this command. @@ -68,9 +90,38 @@ cd /path/to/your/chosen/deployment/directory The `-d` flag runs containers in detached mode, allowing them to run in the background. +--- +## Quick Start: DeveloperMetrics GitHub Action + +To add simple metrics collection for a single repository: + +1. Add the following GitHub Action to your repository's `.github/workflows/metrics.yml` file: + + ```yaml + name: Collect DORA Metrics + on: + push: + branches: + - main + jobs: + collect-metrics: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Run DORA Metrics Collection + uses: DeveloperMetrics/collect@v1 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ``` + +2. After a push to your repository, metrics such as deployment frequency and lead time for changes will be collected and displayed as badges on your project README. + +For more information, check out the [DeveloperMetrics repository](https://github.com/DeveloperMetrics). + --- -## Step-by-Step Configuration Guide +## Step-by-Step Configuration Guide for DevLake +_For **DeveloperMetrics**, no additional configuration is needed beyond adding the GitHub Action to your repository._ 1. Run the **[Quick Start](#quick-start)** steps above. 2. Once you have a working DevLake instance, we recommend going through DevLake's [official start guide](https://devlake.apache.org/docs/Overview/Introduction/#2-configuring-data-source) step-by-step, beginning with the data sources section. @@ -109,6 +160,7 @@ See [this list](https://devlake.apache.org/docs/Metrics) of metrics on the DevLa - Dillon Dalton [ddalton-jpl](https://github.com/ddalton-jpl) - Rishi Verma [riverma](https://github.com/riverma) +- Kyongsik Yun [yunks128](https://github.com/yunks128) --- From 0327e38487fda360e246c2edc76c78ce869104a5 Mon Sep 17 00:00:00 2001 From: Kyongsik Yun Date: Wed, 30 Apr 2025 10:29:24 -0700 Subject: [PATCH 2/7] add metrics.yml --- docs/guides/software-lifecycle/metrics/README.md | 2 +- .../assets/software-lifecycle/metrics/metrics.yml | 14 ++++++++++++++ static/data/slim-registry.json | 8 ++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 static/assets/software-lifecycle/metrics/metrics.yml diff --git a/docs/guides/software-lifecycle/metrics/README.md b/docs/guides/software-lifecycle/metrics/README.md index 8b436014f..8cf845718 100644 --- a/docs/guides/software-lifecycle/metrics/README.md +++ b/docs/guides/software-lifecycle/metrics/README.md @@ -95,7 +95,7 @@ cd /path/to/your/chosen/deployment/directory To add simple metrics collection for a single repository: -1. Add the following GitHub Action to your repository's `.github/workflows/metrics.yml` file: +1. Add the following GitHub Action to your repository's [`.github/workflows/metrics.yml` file](https://raw.githubusercontent.com/NASA-AMMOS/slim/main/static/assets/software-lifecycle/metrics/metrics.yml): ```yaml name: Collect DORA Metrics diff --git a/static/assets/software-lifecycle/metrics/metrics.yml b/static/assets/software-lifecycle/metrics/metrics.yml new file mode 100644 index 000000000..ff756a49c --- /dev/null +++ b/static/assets/software-lifecycle/metrics/metrics.yml @@ -0,0 +1,14 @@ +name: Collect DORA Metrics + on: + push: + branches: + - main + jobs: + collect-metrics: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Run DORA Metrics Collection + uses: DeveloperMetrics/collect@v1 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/static/data/slim-registry.json b/static/data/slim-registry.json index cf9bd1242..133e18734 100644 --- a/static/data/slim-registry.json +++ b/static/data/slim-registry.json @@ -274,7 +274,15 @@ "software-lifecycle", "metrics", "tools" + ], + "assets": [ + { + "name": "Simple Metrics Collection", + "type": "text/yaml", + "uri": "https://raw.githubusercontent.com/NASA-AMMOS/slim/main/static/assets/software-lifecycle/metrics/metrics.yml" + } ] + }, { "title": "Container Vulnerability Scanning", From d30aa211ab2006943fc3f86039256ca935a72830 Mon Sep 17 00:00:00 2001 From: Kyongsik Yun Date: Thu, 1 May 2025 14:33:30 -0700 Subject: [PATCH 3/7] dora metrics --- .github/workflows/metrics.yml | 421 +++++++++++++++++ README.md | 1 + .../software-lifecycle/metrics/README.md | 19 +- .../software-lifecycle/metrics/metrics.yml | 435 +++++++++++++++++- 4 files changed, 844 insertions(+), 32 deletions(-) create mode 100644 .github/workflows/metrics.yml diff --git a/.github/workflows/metrics.yml b/.github/workflows/metrics.yml new file mode 100644 index 000000000..bcec2528f --- /dev/null +++ b/.github/workflows/metrics.yml @@ -0,0 +1,421 @@ +name: DORA Metrics +on: + # Schedule to run weekly + schedule: + - cron: '0 0 * * 0' # Run at midnight every Sunday + # Allow manual triggering + workflow_dispatch: + +jobs: + collect-metrics: + runs-on: ubuntu-latest + permissions: + actions: read + contents: write # Required to commit badge files + issues: read # Required to analyze bug/incident issues + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up directory for badge files + run: mkdir -p .github/badges + + - name: Calculate DORA Metrics + run: | + # Get date 30 days ago in ISO format + THIRTY_DAYS_AGO=$(date -d "30 days ago" -u +"%Y-%m-%dT%H:%M:%SZ") + + echo "=== Calculating DORA Metrics for Last 30 Days ===" + + #========================================================= + # 1. Deployment Frequency + #========================================================= + echo "Calculating Deployment Frequency..." + + # Get pushes to main branch in last 30 days as a proxy for deployments + # Or use your actual deployment workflow runs if available + DEPLOY_COUNT=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + "https://api.github.com/repos/${{ github.repository }}/commits?since=$THIRTY_DAYS_AGO&sha=main" | \ + jq '. | length') + + echo "Total deployments in last 30 days: $DEPLOY_COUNT" + + if [ -z "$DEPLOY_COUNT" ] || [ "$DEPLOY_COUNT" == "null" ]; then + DEPLOY_COUNT=0 + fi + + # Calculate per day/week/month metrics + if [ "$DEPLOY_COUNT" -gt 0 ]; then + DEPLOY_PER_DAY=$(echo "scale=2; $DEPLOY_COUNT / 30" | bc) + DEPLOY_PER_WEEK=$(echo "scale=2; $DEPLOY_COUNT / 4.3" | bc) + DEPLOY_PER_MONTH="$DEPLOY_COUNT" + + echo "Deployments per day: $DEPLOY_PER_DAY" + echo "Deployments per week: $DEPLOY_PER_WEEK" + + # Determine DORA level based on deployment frequency + if (( $(echo "$DEPLOY_PER_DAY >= 1" | bc -l) )); then + DF_VALUE="$DEPLOY_PER_DAY per day" + DF_LEVEL="Elite" + DF_COLOR="brightgreen" + elif (( $(echo "$DEPLOY_PER_WEEK >= 1" | bc -l) )); then + DF_VALUE="$DEPLOY_PER_WEEK per week" + DF_LEVEL="High" + DF_COLOR="green" + elif (( $(echo "$DEPLOY_PER_MONTH >= 1" | bc -l) )); then + DF_VALUE="$DEPLOY_PER_MONTH per month" + DF_LEVEL="Medium" + DF_COLOR="yellow" + else + DF_VALUE="$DEPLOY_PER_MONTH per month" + DF_LEVEL="Low" + DF_COLOR="red" + fi + else + DF_VALUE="0 per month" + DF_LEVEL="Low" + DF_COLOR="red" + fi + + echo "Deployment Frequency: $DF_VALUE ($DF_LEVEL)" + + #========================================================= + # 2. Lead Time for Changes + #========================================================= + echo "Calculating Lead Time for Changes..." + + # Get merged PRs in the last 30 days + MERGED_PRS=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + "https://api.github.com/repos/${{ github.repository }}/pulls?state=closed&sort=updated&direction=desc&per_page=100" | \ + jq '[.[] | select(.merged_at != null and .merged_at > "'$THIRTY_DAYS_AGO'")]') + + PR_COUNT=$(echo "$MERGED_PRS" | jq 'length') + echo "Merged PRs in last 30 days: $PR_COUNT" + + if [ "$PR_COUNT" -gt 0 ]; then + TOTAL_HOURS=0 + + for i in $(seq 0 $(($PR_COUNT-1))); do + CREATED=$(echo "$MERGED_PRS" | jq -r ".[$i].created_at") + MERGED=$(echo "$MERGED_PRS" | jq -r ".[$i].merged_at") + + CREATED_TS=$(date -d "$CREATED" +%s) + MERGED_TS=$(date -d "$MERGED" +%s) + + DIFF_SECS=$(($MERGED_TS - $CREATED_TS)) + PR_HOURS=$(echo "scale=2; $DIFF_SECS / 3600" | bc) + + TOTAL_HOURS=$(echo "scale=2; $TOTAL_HOURS + $PR_HOURS" | bc) + done + + AVG_HOURS=$(echo "scale=2; $TOTAL_HOURS / $PR_COUNT" | bc) + echo "Average lead time: $AVG_HOURS hours" + + # Determine DORA level based on lead time + if (( $(echo "$AVG_HOURS < 24" | bc -l) )); then + LT_VALUE="$AVG_HOURS hours" + LT_LEVEL="Elite" + LT_COLOR="brightgreen" + elif (( $(echo "$AVG_HOURS < 168" | bc -l) )); then + AVG_DAYS=$(echo "scale=2; $AVG_HOURS / 24" | bc) + LT_VALUE="$AVG_DAYS days" + LT_LEVEL="High" + LT_COLOR="green" + elif (( $(echo "$AVG_HOURS < 730" | bc -l) )); then + AVG_DAYS=$(echo "scale=2; $AVG_HOURS / 24" | bc) + LT_VALUE="$AVG_DAYS days" + LT_LEVEL="Medium" + LT_COLOR="yellow" + else + AVG_DAYS=$(echo "scale=2; $AVG_HOURS / 24" | bc) + LT_VALUE="$AVG_DAYS days" + LT_LEVEL="Low" + LT_COLOR="red" + fi + else + LT_VALUE="No PRs" + LT_LEVEL="N/A" + LT_COLOR="gray" + fi + + echo "Lead Time: $LT_VALUE ($LT_LEVEL)" + + #========================================================= + # 3. Change Failure Rate + #========================================================= + echo "Calculating Change Failure Rate..." + + # Get bugs/incidents reported in the last 30 days + # (Using issues with "bug" or "incident" labels) + BUG_COUNT=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + "https://api.github.com/repos/${{ github.repository }}/issues?state=all&labels=bug&since=$THIRTY_DAYS_AGO&per_page=100" | \ + jq '. | length') + + INCIDENT_COUNT=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + "https://api.github.com/repos/${{ github.repository }}/issues?state=all&labels=incident&since=$THIRTY_DAYS_AGO&per_page=100" | \ + jq '. | length') + + if [ -z "$BUG_COUNT" ] || [ "$BUG_COUNT" == "null" ]; then + BUG_COUNT=0 + fi + + if [ -z "$INCIDENT_COUNT" ] || [ "$INCIDENT_COUNT" == "null" ]; then + INCIDENT_COUNT=0 + fi + + TOTAL_FAILURES=$(($BUG_COUNT + $INCIDENT_COUNT)) + echo "Bugs/incidents in last 30 days: $TOTAL_FAILURES" + + if [ "$DEPLOY_COUNT" -gt 0 ]; then + FAILURE_RATE=$(echo "scale=2; $TOTAL_FAILURES / $DEPLOY_COUNT * 100" | bc) + echo "Change failure rate: $FAILURE_RATE%" + + # Determine DORA level based on failure rate + if (( $(echo "$FAILURE_RATE <= 15" | bc -l) )); then + CFR_VALUE="$FAILURE_RATE%" + CFR_LEVEL="Elite" + CFR_COLOR="brightgreen" + elif (( $(echo "$FAILURE_RATE <= 30" | bc -l) )); then + CFR_VALUE="$FAILURE_RATE%" + CFR_LEVEL="High" + CFR_COLOR="green" + elif (( $(echo "$FAILURE_RATE <= 45" | bc -l) )); then + CFR_VALUE="$FAILURE_RATE%" + CFR_LEVEL="Medium" + CFR_COLOR="yellow" + else + CFR_VALUE="$FAILURE_RATE%" + CFR_LEVEL="Low" + CFR_COLOR="red" + fi + else + CFR_VALUE="N/A (No deployments)" + CFR_LEVEL="N/A" + CFR_COLOR="gray" + fi + + echo "Change Failure Rate: $CFR_VALUE ($CFR_LEVEL)" + + #========================================================= + # 4. Mean Time to Recovery (MTTR) + #========================================================= + echo "Calculating Mean Time to Recovery..." + + # Get closed incidents in the last 30 days + CLOSED_INCIDENTS=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + "https://api.github.com/repos/${{ github.repository }}/issues?state=closed&labels=incident&per_page=100" | \ + jq '[.[] | select(.closed_at > "'$THIRTY_DAYS_AGO'")]') + + INCIDENT_COUNT=$(echo "$CLOSED_INCIDENTS" | jq 'length') + echo "Closed incidents in last 30 days: $INCIDENT_COUNT" + + if [ "$INCIDENT_COUNT" -gt 0 ]; then + TOTAL_MINUTES=0 + + for i in $(seq 0 $(($INCIDENT_COUNT-1))); do + CREATED=$(echo "$CLOSED_INCIDENTS" | jq -r ".[$i].created_at") + CLOSED=$(echo "$CLOSED_INCIDENTS" | jq -r ".[$i].closed_at") + + CREATED_TS=$(date -d "$CREATED" +%s) + CLOSED_TS=$(date -d "$CLOSED" +%s) + + DIFF_MINS=$(echo "scale=2; ($CLOSED_TS - $CREATED_TS) / 60" | bc) + TOTAL_MINUTES=$(echo "scale=2; $TOTAL_MINUTES + $DIFF_MINS" | bc) + done + + AVG_MINUTES=$(echo "scale=2; $TOTAL_MINUTES / $INCIDENT_COUNT" | bc) + AVG_HOURS=$(echo "scale=2; $AVG_MINUTES / 60" | bc) + echo "Average recovery time: $AVG_HOURS hours" + + # Determine DORA level based on recovery time + if (( $(echo "$AVG_HOURS < 1" | bc -l) )); then + MTTR_VALUE="$AVG_MINUTES minutes" + MTTR_LEVEL="Elite" + MTTR_COLOR="brightgreen" + elif (( $(echo "$AVG_HOURS < 24" | bc -l) )); then + MTTR_VALUE="$AVG_HOURS hours" + MTTR_LEVEL="High" + MTTR_COLOR="green" + elif (( $(echo "$AVG_HOURS < 168" | bc -l) )); then + MTTR_VALUE="$AVG_HOURS hours" + MTTR_LEVEL="Medium" + MTTR_COLOR="yellow" + else + AVG_DAYS=$(echo "scale=2; $AVG_HOURS / 24" | bc) + MTTR_VALUE="$AVG_DAYS days" + MTTR_LEVEL="Low" + MTTR_COLOR="red" + fi + else + MTTR_VALUE="N/A (No incidents)" + MTTR_LEVEL="N/A" + MTTR_COLOR="gray" + fi + + echo "Mean Time to Recovery: $MTTR_VALUE ($MTTR_LEVEL)" + + #========================================================= + # Generate Badge Files + #========================================================= + echo "Generating badge files..." + + # Deployment Frequency Badge + cat > .github/badges/deployment-frequency.json << EOF + { + "schemaVersion": 1, + "label": "Deployment Frequency", + "message": "$DF_VALUE ($DF_LEVEL)", + "color": "$DF_COLOR" + } + EOF + + # Lead Time Badge + cat > .github/badges/lead-time.json << EOF + { + "schemaVersion": 1, + "label": "Lead Time", + "message": "$LT_VALUE ($LT_LEVEL)", + "color": "$LT_COLOR" + } + EOF + + # Change Failure Rate Badge + cat > .github/badges/change-failure-rate.json << EOF + { + "schemaVersion": 1, + "label": "Change Failure Rate", + "message": "$CFR_VALUE ($CFR_LEVEL)", + "color": "$CFR_COLOR" + } + EOF + + # MTTR Badge + cat > .github/badges/mttr.json << EOF + { + "schemaVersion": 1, + "label": "MTTR", + "message": "$MTTR_VALUE ($MTTR_LEVEL)", + "color": "$MTTR_COLOR" + } + EOF + + # Combined DORA Metrics Badge + cat > .github/badges/dora-metrics.json << EOF + { + "schemaVersion": 1, + "label": "DORA Metrics", + "message": "Deployment Frequency: $DF_LEVEL | Lead Time: $LT_LEVEL | Change Failure Rate: $CFR_LEVEL | Mean Time to Recovery: $MTTR_LEVEL", + "color": "blue" + } + EOF + + echo "Badge files generated successfully!" + + #========================================================= + # Generate Metrics Report + #========================================================= + echo "Generating metrics report..." + + cat > dora-metrics-report.md << EOF + # DORA Metrics Report + + *Generated on $(date)* + + ## Summary + + | Metric | Value | Performance Level | + |--------|-------|------------------| + | Deployment Frequency | $DF_VALUE | $DF_LEVEL | + | Lead Time for Changes | $LT_VALUE | $LT_LEVEL | + | Change Failure Rate | $CFR_VALUE | $CFR_LEVEL | + | Mean Time to Recovery | $MTTR_VALUE | $MTTR_LEVEL | + + ## How to Add Badges to Your README + + Add the following to your README.md: + + \`\`\`markdown + ![Deployment Frequency](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/${{ github.repository }}/main/.github/badges/deployment-frequency.json) + ![Lead Time](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/${{ github.repository }}/main/.github/badges/lead-time.json) + ![Change Failure Rate](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/${{ github.repository }}/main/.github/badges/change-failure-rate.json) + ![MTTR](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/${{ github.repository }}/main/.github/badges/mttr.json) + ![DORA Metrics](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/${{ github.repository }}/main/.github/badges/dora-metrics.json) + \`\`\` + + ## Details + + ### Deployment Frequency + + - Total deployments in last 30 days: $DEPLOY_COUNT + - Deployments per day: $DEPLOY_PER_DAY + - Performance level: $DF_LEVEL + + ### Lead Time for Changes + + - Merged PRs in last 30 days: $PR_COUNT + - Average lead time: $LT_VALUE + - Performance level: $LT_LEVEL + + ### Change Failure Rate + + - Total failures in last 30 days: $TOTAL_FAILURES + - Change failure rate: $CFR_VALUE + - Performance level: $CFR_LEVEL + + ### Mean Time to Recovery + + - Closed incidents in last 30 days: $INCIDENT_COUNT + - Average recovery time: $MTTR_VALUE + - Performance level: $MTTR_LEVEL + EOF + + echo "Metrics report generated successfully!" + + - name: Create GitHub Issue with Report + run: | + REPORT=$(cat dora-metrics-report.md) + TODAY=$(date +"%Y-%m-%d") + + # Create or update issue with metrics report + ISSUE_DATA=$(cat << EOF + { + "title": "DORA Metrics Report - $TODAY", + "body": $REPORT, + "labels": ["metrics", "dora"] + } + EOF + ) + + # Try to find existing open issue with the same label + EXISTING_ISSUES=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + "https://api.github.com/repos/${{ github.repository }}/issues?state=open&labels=dora") + + ISSUE_COUNT=$(echo "$EXISTING_ISSUES" | jq 'length') + + if [ "$ISSUE_COUNT" -gt 0 ]; then + # Update existing issue + ISSUE_NUMBER=$(echo "$EXISTING_ISSUES" | jq -r '.[0].number') + echo "Updating existing issue #$ISSUE_NUMBER" + + curl -s -X PATCH -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + -H "Accept: application/vnd.github.v3+json" \ + -d "$ISSUE_DATA" \ + "https://api.github.com/repos/${{ github.repository }}/issues/$ISSUE_NUMBER" + else + # Create new issue + echo "Creating new DORA metrics issue" + + curl -s -X POST -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + -H "Accept: application/vnd.github.v3+json" \ + -d "$ISSUE_DATA" \ + "https://api.github.com/repos/${{ github.repository }}/issues" + fi + + - name: Commit badge files + run: | + git config --local user.email "github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions[bot]" + git add .github/badges/ + git commit -m "Update DORA metrics badges [skip ci]" || echo "No changes to commit" + git push \ No newline at end of file diff --git a/README.md b/README.md index 564a85d2c..2e81a556e 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ [![SLIM](https://img.shields.io/badge/Best%20Practices%20from-SLIM-blue)](https://nasa-ammos.github.io/slim/) +![DORA Metrics](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/NASA-AMMOS/slim/tree/issue-160/.github/badges/dora-metrics.json) ![screen-slim](https://github.com/NASA-AMMOS/slim/assets/3129134/d4da5150-aae6-4986-b18e-5c463f8ff38a) diff --git a/docs/guides/software-lifecycle/metrics/README.md b/docs/guides/software-lifecycle/metrics/README.md index 8cf845718..b0c3bdaf5 100644 --- a/docs/guides/software-lifecycle/metrics/README.md +++ b/docs/guides/software-lifecycle/metrics/README.md @@ -95,24 +95,7 @@ cd /path/to/your/chosen/deployment/directory To add simple metrics collection for a single repository: -1. Add the following GitHub Action to your repository's [`.github/workflows/metrics.yml` file](https://raw.githubusercontent.com/NASA-AMMOS/slim/main/static/assets/software-lifecycle/metrics/metrics.yml): - - ```yaml - name: Collect DORA Metrics - on: - push: - branches: - - main - jobs: - collect-metrics: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Run DORA Metrics Collection - uses: DeveloperMetrics/collect@v1 - with: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - ``` +1. Add the following GitHub Action to your repository's [`.github/workflows/metrics.yml` file](/static/assets/software-lifecycle/metrics/metrics.yml): 2. After a push to your repository, metrics such as deployment frequency and lead time for changes will be collected and displayed as badges on your project README. diff --git a/static/assets/software-lifecycle/metrics/metrics.yml b/static/assets/software-lifecycle/metrics/metrics.yml index ff756a49c..bcec2528f 100644 --- a/static/assets/software-lifecycle/metrics/metrics.yml +++ b/static/assets/software-lifecycle/metrics/metrics.yml @@ -1,14 +1,421 @@ -name: Collect DORA Metrics - on: - push: - branches: - - main - jobs: - collect-metrics: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Run DORA Metrics Collection - uses: DeveloperMetrics/collect@v1 - with: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file +name: DORA Metrics +on: + # Schedule to run weekly + schedule: + - cron: '0 0 * * 0' # Run at midnight every Sunday + # Allow manual triggering + workflow_dispatch: + +jobs: + collect-metrics: + runs-on: ubuntu-latest + permissions: + actions: read + contents: write # Required to commit badge files + issues: read # Required to analyze bug/incident issues + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up directory for badge files + run: mkdir -p .github/badges + + - name: Calculate DORA Metrics + run: | + # Get date 30 days ago in ISO format + THIRTY_DAYS_AGO=$(date -d "30 days ago" -u +"%Y-%m-%dT%H:%M:%SZ") + + echo "=== Calculating DORA Metrics for Last 30 Days ===" + + #========================================================= + # 1. Deployment Frequency + #========================================================= + echo "Calculating Deployment Frequency..." + + # Get pushes to main branch in last 30 days as a proxy for deployments + # Or use your actual deployment workflow runs if available + DEPLOY_COUNT=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + "https://api.github.com/repos/${{ github.repository }}/commits?since=$THIRTY_DAYS_AGO&sha=main" | \ + jq '. | length') + + echo "Total deployments in last 30 days: $DEPLOY_COUNT" + + if [ -z "$DEPLOY_COUNT" ] || [ "$DEPLOY_COUNT" == "null" ]; then + DEPLOY_COUNT=0 + fi + + # Calculate per day/week/month metrics + if [ "$DEPLOY_COUNT" -gt 0 ]; then + DEPLOY_PER_DAY=$(echo "scale=2; $DEPLOY_COUNT / 30" | bc) + DEPLOY_PER_WEEK=$(echo "scale=2; $DEPLOY_COUNT / 4.3" | bc) + DEPLOY_PER_MONTH="$DEPLOY_COUNT" + + echo "Deployments per day: $DEPLOY_PER_DAY" + echo "Deployments per week: $DEPLOY_PER_WEEK" + + # Determine DORA level based on deployment frequency + if (( $(echo "$DEPLOY_PER_DAY >= 1" | bc -l) )); then + DF_VALUE="$DEPLOY_PER_DAY per day" + DF_LEVEL="Elite" + DF_COLOR="brightgreen" + elif (( $(echo "$DEPLOY_PER_WEEK >= 1" | bc -l) )); then + DF_VALUE="$DEPLOY_PER_WEEK per week" + DF_LEVEL="High" + DF_COLOR="green" + elif (( $(echo "$DEPLOY_PER_MONTH >= 1" | bc -l) )); then + DF_VALUE="$DEPLOY_PER_MONTH per month" + DF_LEVEL="Medium" + DF_COLOR="yellow" + else + DF_VALUE="$DEPLOY_PER_MONTH per month" + DF_LEVEL="Low" + DF_COLOR="red" + fi + else + DF_VALUE="0 per month" + DF_LEVEL="Low" + DF_COLOR="red" + fi + + echo "Deployment Frequency: $DF_VALUE ($DF_LEVEL)" + + #========================================================= + # 2. Lead Time for Changes + #========================================================= + echo "Calculating Lead Time for Changes..." + + # Get merged PRs in the last 30 days + MERGED_PRS=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + "https://api.github.com/repos/${{ github.repository }}/pulls?state=closed&sort=updated&direction=desc&per_page=100" | \ + jq '[.[] | select(.merged_at != null and .merged_at > "'$THIRTY_DAYS_AGO'")]') + + PR_COUNT=$(echo "$MERGED_PRS" | jq 'length') + echo "Merged PRs in last 30 days: $PR_COUNT" + + if [ "$PR_COUNT" -gt 0 ]; then + TOTAL_HOURS=0 + + for i in $(seq 0 $(($PR_COUNT-1))); do + CREATED=$(echo "$MERGED_PRS" | jq -r ".[$i].created_at") + MERGED=$(echo "$MERGED_PRS" | jq -r ".[$i].merged_at") + + CREATED_TS=$(date -d "$CREATED" +%s) + MERGED_TS=$(date -d "$MERGED" +%s) + + DIFF_SECS=$(($MERGED_TS - $CREATED_TS)) + PR_HOURS=$(echo "scale=2; $DIFF_SECS / 3600" | bc) + + TOTAL_HOURS=$(echo "scale=2; $TOTAL_HOURS + $PR_HOURS" | bc) + done + + AVG_HOURS=$(echo "scale=2; $TOTAL_HOURS / $PR_COUNT" | bc) + echo "Average lead time: $AVG_HOURS hours" + + # Determine DORA level based on lead time + if (( $(echo "$AVG_HOURS < 24" | bc -l) )); then + LT_VALUE="$AVG_HOURS hours" + LT_LEVEL="Elite" + LT_COLOR="brightgreen" + elif (( $(echo "$AVG_HOURS < 168" | bc -l) )); then + AVG_DAYS=$(echo "scale=2; $AVG_HOURS / 24" | bc) + LT_VALUE="$AVG_DAYS days" + LT_LEVEL="High" + LT_COLOR="green" + elif (( $(echo "$AVG_HOURS < 730" | bc -l) )); then + AVG_DAYS=$(echo "scale=2; $AVG_HOURS / 24" | bc) + LT_VALUE="$AVG_DAYS days" + LT_LEVEL="Medium" + LT_COLOR="yellow" + else + AVG_DAYS=$(echo "scale=2; $AVG_HOURS / 24" | bc) + LT_VALUE="$AVG_DAYS days" + LT_LEVEL="Low" + LT_COLOR="red" + fi + else + LT_VALUE="No PRs" + LT_LEVEL="N/A" + LT_COLOR="gray" + fi + + echo "Lead Time: $LT_VALUE ($LT_LEVEL)" + + #========================================================= + # 3. Change Failure Rate + #========================================================= + echo "Calculating Change Failure Rate..." + + # Get bugs/incidents reported in the last 30 days + # (Using issues with "bug" or "incident" labels) + BUG_COUNT=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + "https://api.github.com/repos/${{ github.repository }}/issues?state=all&labels=bug&since=$THIRTY_DAYS_AGO&per_page=100" | \ + jq '. | length') + + INCIDENT_COUNT=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + "https://api.github.com/repos/${{ github.repository }}/issues?state=all&labels=incident&since=$THIRTY_DAYS_AGO&per_page=100" | \ + jq '. | length') + + if [ -z "$BUG_COUNT" ] || [ "$BUG_COUNT" == "null" ]; then + BUG_COUNT=0 + fi + + if [ -z "$INCIDENT_COUNT" ] || [ "$INCIDENT_COUNT" == "null" ]; then + INCIDENT_COUNT=0 + fi + + TOTAL_FAILURES=$(($BUG_COUNT + $INCIDENT_COUNT)) + echo "Bugs/incidents in last 30 days: $TOTAL_FAILURES" + + if [ "$DEPLOY_COUNT" -gt 0 ]; then + FAILURE_RATE=$(echo "scale=2; $TOTAL_FAILURES / $DEPLOY_COUNT * 100" | bc) + echo "Change failure rate: $FAILURE_RATE%" + + # Determine DORA level based on failure rate + if (( $(echo "$FAILURE_RATE <= 15" | bc -l) )); then + CFR_VALUE="$FAILURE_RATE%" + CFR_LEVEL="Elite" + CFR_COLOR="brightgreen" + elif (( $(echo "$FAILURE_RATE <= 30" | bc -l) )); then + CFR_VALUE="$FAILURE_RATE%" + CFR_LEVEL="High" + CFR_COLOR="green" + elif (( $(echo "$FAILURE_RATE <= 45" | bc -l) )); then + CFR_VALUE="$FAILURE_RATE%" + CFR_LEVEL="Medium" + CFR_COLOR="yellow" + else + CFR_VALUE="$FAILURE_RATE%" + CFR_LEVEL="Low" + CFR_COLOR="red" + fi + else + CFR_VALUE="N/A (No deployments)" + CFR_LEVEL="N/A" + CFR_COLOR="gray" + fi + + echo "Change Failure Rate: $CFR_VALUE ($CFR_LEVEL)" + + #========================================================= + # 4. Mean Time to Recovery (MTTR) + #========================================================= + echo "Calculating Mean Time to Recovery..." + + # Get closed incidents in the last 30 days + CLOSED_INCIDENTS=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + "https://api.github.com/repos/${{ github.repository }}/issues?state=closed&labels=incident&per_page=100" | \ + jq '[.[] | select(.closed_at > "'$THIRTY_DAYS_AGO'")]') + + INCIDENT_COUNT=$(echo "$CLOSED_INCIDENTS" | jq 'length') + echo "Closed incidents in last 30 days: $INCIDENT_COUNT" + + if [ "$INCIDENT_COUNT" -gt 0 ]; then + TOTAL_MINUTES=0 + + for i in $(seq 0 $(($INCIDENT_COUNT-1))); do + CREATED=$(echo "$CLOSED_INCIDENTS" | jq -r ".[$i].created_at") + CLOSED=$(echo "$CLOSED_INCIDENTS" | jq -r ".[$i].closed_at") + + CREATED_TS=$(date -d "$CREATED" +%s) + CLOSED_TS=$(date -d "$CLOSED" +%s) + + DIFF_MINS=$(echo "scale=2; ($CLOSED_TS - $CREATED_TS) / 60" | bc) + TOTAL_MINUTES=$(echo "scale=2; $TOTAL_MINUTES + $DIFF_MINS" | bc) + done + + AVG_MINUTES=$(echo "scale=2; $TOTAL_MINUTES / $INCIDENT_COUNT" | bc) + AVG_HOURS=$(echo "scale=2; $AVG_MINUTES / 60" | bc) + echo "Average recovery time: $AVG_HOURS hours" + + # Determine DORA level based on recovery time + if (( $(echo "$AVG_HOURS < 1" | bc -l) )); then + MTTR_VALUE="$AVG_MINUTES minutes" + MTTR_LEVEL="Elite" + MTTR_COLOR="brightgreen" + elif (( $(echo "$AVG_HOURS < 24" | bc -l) )); then + MTTR_VALUE="$AVG_HOURS hours" + MTTR_LEVEL="High" + MTTR_COLOR="green" + elif (( $(echo "$AVG_HOURS < 168" | bc -l) )); then + MTTR_VALUE="$AVG_HOURS hours" + MTTR_LEVEL="Medium" + MTTR_COLOR="yellow" + else + AVG_DAYS=$(echo "scale=2; $AVG_HOURS / 24" | bc) + MTTR_VALUE="$AVG_DAYS days" + MTTR_LEVEL="Low" + MTTR_COLOR="red" + fi + else + MTTR_VALUE="N/A (No incidents)" + MTTR_LEVEL="N/A" + MTTR_COLOR="gray" + fi + + echo "Mean Time to Recovery: $MTTR_VALUE ($MTTR_LEVEL)" + + #========================================================= + # Generate Badge Files + #========================================================= + echo "Generating badge files..." + + # Deployment Frequency Badge + cat > .github/badges/deployment-frequency.json << EOF + { + "schemaVersion": 1, + "label": "Deployment Frequency", + "message": "$DF_VALUE ($DF_LEVEL)", + "color": "$DF_COLOR" + } + EOF + + # Lead Time Badge + cat > .github/badges/lead-time.json << EOF + { + "schemaVersion": 1, + "label": "Lead Time", + "message": "$LT_VALUE ($LT_LEVEL)", + "color": "$LT_COLOR" + } + EOF + + # Change Failure Rate Badge + cat > .github/badges/change-failure-rate.json << EOF + { + "schemaVersion": 1, + "label": "Change Failure Rate", + "message": "$CFR_VALUE ($CFR_LEVEL)", + "color": "$CFR_COLOR" + } + EOF + + # MTTR Badge + cat > .github/badges/mttr.json << EOF + { + "schemaVersion": 1, + "label": "MTTR", + "message": "$MTTR_VALUE ($MTTR_LEVEL)", + "color": "$MTTR_COLOR" + } + EOF + + # Combined DORA Metrics Badge + cat > .github/badges/dora-metrics.json << EOF + { + "schemaVersion": 1, + "label": "DORA Metrics", + "message": "Deployment Frequency: $DF_LEVEL | Lead Time: $LT_LEVEL | Change Failure Rate: $CFR_LEVEL | Mean Time to Recovery: $MTTR_LEVEL", + "color": "blue" + } + EOF + + echo "Badge files generated successfully!" + + #========================================================= + # Generate Metrics Report + #========================================================= + echo "Generating metrics report..." + + cat > dora-metrics-report.md << EOF + # DORA Metrics Report + + *Generated on $(date)* + + ## Summary + + | Metric | Value | Performance Level | + |--------|-------|------------------| + | Deployment Frequency | $DF_VALUE | $DF_LEVEL | + | Lead Time for Changes | $LT_VALUE | $LT_LEVEL | + | Change Failure Rate | $CFR_VALUE | $CFR_LEVEL | + | Mean Time to Recovery | $MTTR_VALUE | $MTTR_LEVEL | + + ## How to Add Badges to Your README + + Add the following to your README.md: + + \`\`\`markdown + ![Deployment Frequency](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/${{ github.repository }}/main/.github/badges/deployment-frequency.json) + ![Lead Time](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/${{ github.repository }}/main/.github/badges/lead-time.json) + ![Change Failure Rate](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/${{ github.repository }}/main/.github/badges/change-failure-rate.json) + ![MTTR](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/${{ github.repository }}/main/.github/badges/mttr.json) + ![DORA Metrics](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/${{ github.repository }}/main/.github/badges/dora-metrics.json) + \`\`\` + + ## Details + + ### Deployment Frequency + + - Total deployments in last 30 days: $DEPLOY_COUNT + - Deployments per day: $DEPLOY_PER_DAY + - Performance level: $DF_LEVEL + + ### Lead Time for Changes + + - Merged PRs in last 30 days: $PR_COUNT + - Average lead time: $LT_VALUE + - Performance level: $LT_LEVEL + + ### Change Failure Rate + + - Total failures in last 30 days: $TOTAL_FAILURES + - Change failure rate: $CFR_VALUE + - Performance level: $CFR_LEVEL + + ### Mean Time to Recovery + + - Closed incidents in last 30 days: $INCIDENT_COUNT + - Average recovery time: $MTTR_VALUE + - Performance level: $MTTR_LEVEL + EOF + + echo "Metrics report generated successfully!" + + - name: Create GitHub Issue with Report + run: | + REPORT=$(cat dora-metrics-report.md) + TODAY=$(date +"%Y-%m-%d") + + # Create or update issue with metrics report + ISSUE_DATA=$(cat << EOF + { + "title": "DORA Metrics Report - $TODAY", + "body": $REPORT, + "labels": ["metrics", "dora"] + } + EOF + ) + + # Try to find existing open issue with the same label + EXISTING_ISSUES=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + "https://api.github.com/repos/${{ github.repository }}/issues?state=open&labels=dora") + + ISSUE_COUNT=$(echo "$EXISTING_ISSUES" | jq 'length') + + if [ "$ISSUE_COUNT" -gt 0 ]; then + # Update existing issue + ISSUE_NUMBER=$(echo "$EXISTING_ISSUES" | jq -r '.[0].number') + echo "Updating existing issue #$ISSUE_NUMBER" + + curl -s -X PATCH -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + -H "Accept: application/vnd.github.v3+json" \ + -d "$ISSUE_DATA" \ + "https://api.github.com/repos/${{ github.repository }}/issues/$ISSUE_NUMBER" + else + # Create new issue + echo "Creating new DORA metrics issue" + + curl -s -X POST -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ + -H "Accept: application/vnd.github.v3+json" \ + -d "$ISSUE_DATA" \ + "https://api.github.com/repos/${{ github.repository }}/issues" + fi + + - name: Commit badge files + run: | + git config --local user.email "github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions[bot]" + git add .github/badges/ + git commit -m "Update DORA metrics badges [skip ci]" || echo "No changes to commit" + git push \ No newline at end of file From a2379616ee0b0e7b2f28675be14810b48b41c025 Mon Sep 17 00:00:00 2001 From: Kyongsik Yun Date: Thu, 1 May 2025 14:36:20 -0700 Subject: [PATCH 4/7] dora metrics --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2e81a556e..04c83b6cf 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ [![SLIM](https://img.shields.io/badge/Best%20Practices%20from-SLIM-blue)](https://nasa-ammos.github.io/slim/) -![DORA Metrics](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/NASA-AMMOS/slim/tree/issue-160/.github/badges/dora-metrics.json) +![DORA Metrics](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/NASA-AMMOS/slim/main/.github/badges/dora-metrics.json) ![screen-slim](https://github.com/NASA-AMMOS/slim/assets/3129134/d4da5150-aae6-4986-b18e-5c463f8ff38a) From 2bf755436fb375f92d8afc3c65fc99ddf4d4926e Mon Sep 17 00:00:00 2001 From: Kyongsik Yun Date: Thu, 1 May 2025 14:46:29 -0700 Subject: [PATCH 5/7] dora metrics badge example --- docs/guides/software-lifecycle/metrics/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/guides/software-lifecycle/metrics/README.md b/docs/guides/software-lifecycle/metrics/README.md index b0c3bdaf5..7bc5d1e1e 100644 --- a/docs/guides/software-lifecycle/metrics/README.md +++ b/docs/guides/software-lifecycle/metrics/README.md @@ -97,9 +97,8 @@ To add simple metrics collection for a single repository: 1. Add the following GitHub Action to your repository's [`.github/workflows/metrics.yml` file](/static/assets/software-lifecycle/metrics/metrics.yml): -2. After a push to your repository, metrics such as deployment frequency and lead time for changes will be collected and displayed as badges on your project README. +2. After a push to your repository, metrics such as deployment frequency and lead time for changes will be collected and displayed as badges on your project README. For example: ![DORA Metrics](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/yunks128/slim-leaderboard/main/.github/badges/dora-metrics.json) -For more information, check out the [DeveloperMetrics repository](https://github.com/DeveloperMetrics). --- From 8953d4025cd95b06d7055aba9276dd1be1cbf60d Mon Sep 17 00:00:00 2001 From: Kyongsik Yun Date: Thu, 8 May 2025 09:08:26 -0700 Subject: [PATCH 6/7] dora metrics readme improvement --- docs/guides/software-lifecycle/metrics/README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/guides/software-lifecycle/metrics/README.md b/docs/guides/software-lifecycle/metrics/README.md index 7bc5d1e1e..40ab69269 100644 --- a/docs/guides/software-lifecycle/metrics/README.md +++ b/docs/guides/software-lifecycle/metrics/README.md @@ -97,7 +97,13 @@ To add simple metrics collection for a single repository: 1. Add the following GitHub Action to your repository's [`.github/workflows/metrics.yml` file](/static/assets/software-lifecycle/metrics/metrics.yml): -2. After a push to your repository, metrics such as deployment frequency and lead time for changes will be collected and displayed as badges on your project README. For example: ![DORA Metrics](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/yunks128/slim-leaderboard/main/.github/badges/dora-metrics.json) +2. After a push to your repository, metrics such as deployment frequency and lead time for changes are automatically computed, and the results are saved to `.github/badges/` as JOSN files. + +3. Add badges to your project `README.md` to showcase metrics. +``` +![DORA Metrics](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com///main/.github/badges/dora-metrics.json) +``` +For example: ![DORA Metrics](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/yunks128/slim-leaderboard/main/.github/badges/dora-metrics.json) ![Deployment Frequency](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/yunks128/slim-leaderboard/main/.github/badges/deployment-frequency.json) ![Change Failure Rate](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/yunks128/slim-leaderboard/main/.github/badges/change-failure-rate.json) --- From 9c935fe6aacfb17386f28487a0485945a54a5f14 Mon Sep 17 00:00:00 2001 From: Kyongsik Yun Date: Wed, 2 Jul 2025 10:40:19 -0700 Subject: [PATCH 7/7] dora metrics badge --- .github/badges/dora-metrics.json | 6 ++++++ README.md | 3 +-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 .github/badges/dora-metrics.json diff --git a/.github/badges/dora-metrics.json b/.github/badges/dora-metrics.json new file mode 100644 index 000000000..66e74eb17 --- /dev/null +++ b/.github/badges/dora-metrics.json @@ -0,0 +1,6 @@ +{ + "schemaVersion": 1, + "label": "DORA Metrics", + "message": "Deployment Frequency: High | Lead Time: Medium | Change Failure Rate: Elite | Mean Time to Recovery: N/A", + "color": "blue" +} \ No newline at end of file diff --git a/README.md b/README.md index 04c83b6cf..987ba61a9 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,7 @@ -[![SLIM](https://img.shields.io/badge/Best%20Practices%20from-SLIM-blue)](https://nasa-ammos.github.io/slim/) -![DORA Metrics](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/NASA-AMMOS/slim/main/.github/badges/dora-metrics.json) +[![SLIM](https://img.shields.io/badge/Best%20Practices%20from-SLIM-blue)](https://nasa-ammos.github.io/slim/) ![DORA Metrics](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/NASA-AMMOS/slim/main/.github/badges/dora-metrics.json) ![screen-slim](https://github.com/NASA-AMMOS/slim/assets/3129134/d4da5150-aae6-4986-b18e-5c463f8ff38a)