Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
167 changes: 167 additions & 0 deletions .claude/skills/analyze-quarterly-metrics/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
---
name: analyze-quarterly-metrics
description: This skill should be used when the user asks to "analyze quarterly metrics", "analyze the quarter", "generate quarterly report", "quarterly analysis", mentions a specific quarter like "2026-Q2", or discusses trends, risks, and growth opportunities for Linux System Roles metrics.
---

# Quarterly Metrics Analysis Skill

This skill analyzes quarterly metrics data and generates a comprehensive report with insights, trends, risks, and recommendations.

## What to do

1. **Determine if the quarter is complete or in-progress:**
- Get today's date and compare to the quarter being analyzed
- If analyzing current or future quarter: Add a disclaimer that data is PARTIAL/INCOMPLETE
- Adjust your interpretation: low numbers may just mean "not much time has passed yet", not a crisis
- For partial quarters: focus on trends and rates rather than absolute numbers

2. **Load the raw data** for the specified quarter:
- Read the summary CSV files: `data/github_prs_summary.csv`, `data/github_issues_summary.csv`, `data/galaxy_legacy_summary.csv`, `data/galaxy_collections_summary.csv`
- Extract data for the specified quarter and the previous 3-4 quarters for comparison
- If `data/{{quarter}}/galaxy_legacy.csv` exists, read it for per-role download analysis

3. **Calculate key metrics** from the raw data:
- **PR Merge Rate**: PRs Merged / (PRs Created - PRs Open) × 100 (excludes PRs still under review)
- **External Acceptance Rate**: External PRs Merged / (External PRs Created - External PRs Open) × 100
- **External Contribution %**: External PRs Created / PRs Created × 100
- **Issue Resolution Rate**: Issues Closed / Issues Created × 100
- **QoQ Growth rates**: Compare current quarter to previous quarter
- **Fastest growing roles**: If per-role data exists, identify top gainers by comparing to previous quarter

4. **Analyze the data** and generate a detailed report with these sections:

### Executive Summary (2-3 sentences)
- High-level overview of the quarter's performance
- Most significant achievement or concern

### Key Findings (Quick-Scan Section)
**Improvements:**
- Notable positive changes and improvements from previous quarter
- Metrics that show upward trends

**Critical Concerns:**
1. Most urgent issues requiring immediate attention (ranked by severity)
2. Trending problems that could impact project health
3. Metrics showing significant decline

**Top Recommendations:**
1. **Immediate:** Critical actions needed within 2 weeks
2. **Short-term:** Actions needed through end of quarter
3. **Ongoing:** Continuous improvement areas

### Key Metrics Overview
- Present the main numbers (PRs, Issues, Downloads)
- Compare to previous quarter (QoQ change)
- Compare to same quarter last year (YoY if available)

### Trend Analysis
- **PR Activity**: Are PRs increasing/decreasing? Merge rate trends?
- **External Contributions**: Growing or declining? Acceptance rate healthy?
- **Issue Management**: Resolution rate? Backlog growing?
- **Galaxy Downloads**: Which collections/roles are trending? Growth rate sustainable?

### Highlights & Achievements
- What went well this quarter?
- Notable improvements in metrics
- Fastest growing roles or areas

### Risks & Concerns
- Declining trends that need attention
- Bottlenecks or capacity issues
- Quality concerns (low acceptance rates, etc.)
- Areas falling behind

### Growth Opportunities
- Underutilized roles with potential
- Areas showing momentum
- External contributor engagement opportunities

### Recommendations
- 2-4 specific, actionable recommendations based on the data
- Focus on addressing risks and capturing opportunities

5. **Be specific with numbers**: Always cite actual metrics, percentages, and comparisons. Don't use vague language like "significant" without quantifying it.

6. **Be smart about partial quarters**:
- If the quarter is incomplete, DO NOT flag low absolute numbers as risks
- Focus on rates (merge rate, acceptance rate) rather than volumes for partial data
- Only flag things as concerns if they represent actual problems, not just "we're only 2 weeks into the quarter"
- Make it clear in the Executive Summary if data is partial

7. **Automatically save the report**:
- Save to `reports/{{quarter}}-analysis.md`
- Create the reports directory if it doesn't exist
- **Safe to overwrite**: If the report file already exists, overwrite it (reports are tracked in git, so previous versions are preserved)
- Notify the user where the file was saved

8. **Output the analysis** directly to the user in Markdown format.

## Guidelines

- **Detect partial quarters**: Compare today's date to the quarter end date. If analyzing an incomplete quarter, prominently note this and adjust your analysis
- **Compare to historical data**: Always reference previous quarters for context
- **Identify patterns**: Look for multi-quarter trends, not just single-quarter changes
- **Be balanced**: Include both positive and negative findings
- **Be actionable**: Recommendations should be specific and implementable
- **Consider seasonality**: Note if quarterly patterns are typical or anomalous
- **Highlight outliers**: Call out unusual spikes or drops in any metric
- **Don't cry wolf on partial data**: For incomplete quarters, only flag true risks (bad rates, declining trends), not low volumes that are expected mid-quarter
- **Key Findings should be scannable**: The Key Findings section should provide a quick executive summary that busy stakeholders can read in 30 seconds. Keep it concise with 2-3 improvements, 3-4 critical concerns, and 3 top recommendations

## Example invocations

**Via skill invocation:**
User types: `/analyze-quarterly-metrics 2026-Q2`

**Via natural language:**
- "Analyze the quarterly metrics for 2026-Q2"
- "Generate a quarterly report for Q2 2026"
- "What do the metrics show for this quarter?"

You should:
1. Extract the quarter from the user's request or args (format: YYYY-QN, e.g., 2026-Q2)
2. Determine if the quarter is complete or in-progress based on today's date
3. Read all the raw metrics data from CSV files for that quarter
4. Calculate derived metrics from the raw data (merge rates, growth rates, etc.)
5. Read historical data for comparison (previous 3-4 quarters)
6. Generate the comprehensive analysis (being smart about partial data)
7. Present it in a well-formatted Markdown document
8. Automatically save to `reports/{{quarter}}-analysis.md`
9. Notify user that the report was saved

## Important

- **Always check if the quarter is complete**: Compare today's date to quarter end
- Q1: January 1 - March 31
- Q2: April 1 - June 30
- Q3: July 1 - September 30
- Q4: October 1 - December 31
- For partial quarters: add clear disclaimer in Executive Summary and adjust risk assessment
- **Always calculate metrics from CSV data** - don't rely on pre-computed derived_metrics.json
- If the quarter directory doesn't exist (like 2026-Q1), work with summary CSV data only
- For per-role analysis, check if `data/{{quarter}}/galaxy_legacy.csv` exists
- Always show your reasoning and cite specific data points
- **Automatically save** the report to `reports/{{quarter}}-analysis.md` (create directory if needed)
- Safe to overwrite existing report files - they're tracked in git
- Notify the user where the file was saved

## Metric Calculation Formulas

Use these formulas when calculating metrics from the raw CSV data:

**PR Metrics:**
- Merge Rate = (PRs Merged) / (PRs Created - PRs Open) × 100
- Excludes PRs still under review from the calculation
- External Acceptance = (External PRs Merged) / (External PRs Created - External PRs Open) × 100
- Excludes external PRs still under review
- External % = (External PRs Created) / (PRs Created) × 100
- QoQ Growth = ((Current - Previous) / Previous) × 100

**Issue Metrics:**
- Resolution Rate = (Issues Closed) / (Issues Created) × 100
- External % = (External Issues Created) / (Issues Created) × 100
- QoQ Growth = ((Current - Previous) / Previous) × 100

**Galaxy Metrics:**
- Legacy QoQ Growth = ((Current Total - Previous Total) / Previous Total) × 100
- Collections QoQ Growth = ((Current Total - Previous Total) / Previous Total) × 100
159 changes: 159 additions & 0 deletions .github/workflows/quarterly-metrics.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
name: Quarterly Metrics Report

on:
# Scheduled: Run on the last day of each quarter at 9am UTC
schedule:
- cron: '0 9 31 3,12 *' # March 31, December 31 at 9am UTC
- cron: '0 9 30 6,9 *' # June 30, September 30 at 9am UTC

# Manual trigger with optional parameters
workflow_dispatch:
inputs:
quarter:
description: 'Quarter (e.g., 2025-Q1)'
required: false
type: string
date_range:
description: 'Date range (e.g., 2025-01-01..2025-03-31)'
required: false
type: string

jobs:
generate-report:
runs-on: ubuntu-latest

permissions:
contents: write # Required to commit and push changes
pull-requests: write # Required to create pull requests

Comment thread
coderabbitai[bot] marked this conversation as resolved.
steps:
- name: Checkout repository
uses: actions/checkout@v4

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

cat -n .github/workflows/quarterly-metrics.yml | sed -n '25,40p'

Repository: linux-system-roles/linux-system-roles-upstream-metrics

Length of output: 605


🌐 Web query:

GitHub Actions pinning by commit SHA vs tag security best practice

💡 Result:

Pinning GitHub Actions by commit SHA is the definitive security best practice, whereas relying on tags poses a significant supply chain risk [1][2][3]. The primary difference lies in immutability: 1. Commit SHA (Best Practice): Pinning to a full-length commit SHA guarantees that the exact, validated code version is executed every time [4][5][3]. Because SHAs are immutable, they cannot be silently altered by an attacker who gains access to the repository, providing protection against retroactive supply chain attacks [1][5][6]. 2. Tags (High Risk): Version tags (e.g., v3) are mutable references [1][7]. Even if you trust an action's creator, a compromised maintainer account or repository can allow an attacker to move tags to point to malicious "imposter" commits [5][6][7]. Any workflow referencing the tag will automatically pull the malicious code upon the next execution without warning [5][6]. Recommendation for Implementation: - Enforce SHA Pinning: Administrators can configure organization or repository-level policies to enforce the use of full commit SHAs, causing workflows that use tags or branches to fail automatically [2][8][9]. - Use Descriptive Comments: To maintain readability and manageability while using SHAs, append the human-readable version tag as a comment in the workflow file (e.g., uses: actions/checkout@f43a0e5 # v3.6.0) [8][10]. - Automate Updates: Since SHA pinning prevents automatic updates, use automated dependency management tools like Dependabot or Renovate to monitor for new versions and propose pull requests for updates [1][10][7]. - Consider Cooldowns: When updating actions, implementing a "cooldown" period (e.g., waiting 7-14 days after a release) can help detect malicious activity or community reports of issues before adopting new versions into your production environment [9]. For high-security requirements, verify that the SHA belongs to the legitimate repository and avoid pinning to forks [3]. Note that while SHA pinning secures the immediate action, transitive dependencies resolved at runtime by the action remain a potential attack vector [9][7].

Citations:


🏁 Script executed:

grep -n "uses:" .github/workflows/quarterly-metrics.yml

Repository: linux-system-roles/linux-system-roles-upstream-metrics

Length of output: 176


Pin GitHub Actions by commit SHA instead of version tags.

Lines 30 and 33 use tag-pinned actions (@v4, @v5), which are mutable references that pose a supply chain risk. An attacker who gains access to the upstream repository could move the tag to point to malicious code, and all workflows would automatically pull the compromised version without warning. Pin to immutable commit SHAs instead:

Proposed fix
      - name: Checkout repository
-       uses: actions/checkout@v4
+       uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v4

      - name: Set up Python
-       uses: actions/setup-python@v5
+       uses: actions/setup-python@40c695bfec7a6cc14eaaf3fe5b33537548c3f129 # v5

Use Dependabot or similar tools to automate SHA updates and maintain currency.

🧰 Tools
🪛 zizmor (1.25.2)

[warning] 29-30: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 30-30: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/quarterly-metrics.yml at line 30, The workflow uses
mutable action tags (uses: actions/checkout@v4 and uses: actions/setup-node@v5);
replace those tag pinning with the corresponding immutable commit SHAs for each
action reference (i.e., change the uses entries to uses:
actions/checkout@<commit-sha> and uses: actions/setup-node@<commit-sha>), and
optionally add Dependabot/workflow auto-update to keep SHAs current; update the
two occurrences in the workflow file where actions/checkout and
actions/setup-node are referenced.


- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'pip'

- name: Install Python dependencies
run: |
pip install -r requirements.txt

- name: Install GitHub CLI
run: |
# gh CLI is pre-installed on ubuntu-latest runners
gh --version

- name: Determine quarter and date range
id: quarter
env:
INPUT_QUARTER: ${{ github.event.inputs.quarter }}
INPUT_DATE_RANGE: ${{ github.event.inputs.date_range }}
run: |
# Use input if provided, otherwise calculate current quarter
if [ -n "$INPUT_QUARTER" ]; then
QUARTER="$INPUT_QUARTER"
else
# Calculate quarter from current date
YEAR=$(date +%Y)
MONTH=$(date +%m)
Q=$(( (MONTH - 1) / 3 + 1 ))
QUARTER="${YEAR}-Q${Q}"
fi
echo "quarter=${QUARTER}" >> $GITHUB_OUTPUT

# Determine date range
if [ -n "$INPUT_DATE_RANGE" ]; then
DATE_RANGE="$INPUT_DATE_RANGE"
else
# Auto-calculate date range based on quarter
YEAR=$(echo ${QUARTER} | cut -d'-' -f1)
Q_NUM=$(echo ${QUARTER} | cut -d'Q' -f2)

case ${Q_NUM} in
1)
DATE_RANGE="${YEAR}-01-01..${YEAR}-03-31"
;;
2)
DATE_RANGE="${YEAR}-04-01..${YEAR}-06-30"
;;
3)
DATE_RANGE="${YEAR}-07-01..${YEAR}-09-30"
;;
4)
DATE_RANGE="${YEAR}-10-01..${YEAR}-12-31"
;;
esac
fi
echo "date_range=${DATE_RANGE}" >> $GITHUB_OUTPUT

- name: Collect GitHub statistics
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
QUARTER: ${{ steps.quarter.outputs.quarter }}
DATE_RANGE: ${{ steps.quarter.outputs.date_range }}
run: bash scripts/collect_all_github_stats.sh

- name: Collect Galaxy statistics
env:
GALAXY_API_KEY: ${{ secrets.GALAXY_API_KEY }}
QUARTER: ${{ steps.quarter.outputs.quarter }}
run: python3 scripts/collect_galaxy_stats.py

- name: Update quarterly summary files
env:
QUARTER: ${{ steps.quarter.outputs.quarter }}
run: python3 scripts/update_quarterly_summary.py

- name: Generate graphs
env:
QUARTER: ${{ steps.quarter.outputs.quarter }}
run: python3 scripts/generate_graphs.py

- name: Create Pull Request with results
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
QUARTER: ${{ steps.quarter.outputs.quarter }}
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

git add data/ reports/

# Check if there are changes to commit
if git diff --staged --quiet; then
echo "No changes to commit"
exit 0
fi

# Create a new branch for this quarter
BRANCH_NAME="metrics/${QUARTER}"
git checkout -b "$BRANCH_NAME"

# Commit changes
git commit -m "Add metrics for ${QUARTER}" -m "Generated by GitHub Actions workflow" -m "- Data: data/${QUARTER}/" -m "- Graphs: reports/images/"
Comment on lines +130 to +142

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Staged changes are lost when switching to existing remote branch.

The workflow stages changes with git add data/ reports/ (line 122), then checks for staged changes (line 125). However, when the branch already exists remotely, git checkout -B "$BRANCH_NAME" "origin/$BRANCH_NAME" (line 135) resets the working tree and index to the remote state, discarding the staged changes. The subsequent commit will then fail or commit nothing.

Consider re-staging after checkout, or use a different approach:

Proposed fix
           if git ls-remote --exit-code --heads origin "$BRANCH_NAME" >/dev/null 2>&1; then
             echo "Branch $BRANCH_NAME exists, updating it"
             git fetch origin "$BRANCH_NAME"
             git checkout -B "$BRANCH_NAME" "origin/$BRANCH_NAME"
+            # Re-stage changes after checkout
+            git add data/ reports/
           else
             echo "Creating new branch $BRANCH_NAME"
             git checkout -b "$BRANCH_NAME"
           fi
+
+          # Verify there are still changes to commit after branch switch
+          if git diff --staged --quiet; then
+            echo "No changes to commit after branch switch"
+            exit 0
+          fi

           # Commit changes
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/quarterly-metrics.yml around lines 130 - 142, The workflow
currently stages files with git add data/ reports/ before switching to an
existing remote branch using git checkout -B "$BRANCH_NAME"
"origin/$BRANCH_NAME", which resets the index and discards staged changes; to
fix, move or repeat the staging so changes are added after the checkout (i.e.,
ensure git add data/ reports/ runs after git checkout -B "$BRANCH_NAME"
"origin/$BRANCH_NAME"), or alternatively stash before checkout and pop after,
then run git commit with BRANCH_NAME as before so the commit includes the
intended files.


# Push the branch
git push origin "$BRANCH_NAME"

# Create Pull Request
gh pr create \
--title "Quarterly Metrics - ${QUARTER}" \
--body "Automated metrics collection for ${QUARTER}. **Data:** \`data/${QUARTER}/\` **Graphs:** \`reports/images/\` After merging, generate analysis: \`/analyze-quarterly-metrics ${QUARTER}\`" \
--base main \
--head "$BRANCH_NAME"

- name: Create workflow summary
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
QUARTER: ${{ steps.quarter.outputs.quarter }}
run: |
echo "## Quarterly Metrics - ${QUARTER}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
PR_URL=$(gh pr view metrics/${QUARTER} --json url -q .url 2>/dev/null || echo "")
if [ -n "$PR_URL" ]; then
echo "**[Review Pull Request](${PR_URL})**" >> $GITHUB_STEP_SUMMARY
else
echo "Data: \`data/${QUARTER}/\`" >> $GITHUB_STEP_SUMMARY
fi
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
__pycache__/
venv/
49 changes: 49 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Makefile for Linux System Roles Quarterly Metrics
.PHONY: help collect-github collect-galaxy update-summary generate-graphs quarterly-report clean

# Auto-detect quarter and date range
CURRENT_MONTH := $(shell date +%-m)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
CURRENT_YEAR := $(shell date +%Y)
CURRENT_Q := $(shell echo $$((($(CURRENT_MONTH)-1)/3+1)))
QUARTER ?= $(CURRENT_YEAR)-Q$(CURRENT_Q)
YEAR := $(shell echo $(QUARTER) | cut -d'-' -f1)
Q_NUM := $(shell echo $(QUARTER) | cut -d'Q' -f2)

ifeq ($(Q_NUM),1)
DATE_RANGE := $(YEAR)-01-01..$(YEAR)-03-31
else ifeq ($(Q_NUM),2)
DATE_RANGE := $(YEAR)-04-01..$(YEAR)-06-30
else ifeq ($(Q_NUM),3)
DATE_RANGE := $(YEAR)-07-01..$(YEAR)-09-30
else ifeq ($(Q_NUM),4)
DATE_RANGE := $(YEAR)-10-01..$(YEAR)-12-31
endif

help:
@echo "Targets: collect-github, collect-galaxy, update-summary, generate-graphs, quarterly-report, clean"
@echo "Current quarter: $(QUARTER) ($(DATE_RANGE))"
@echo "Requires: GITHUB_TOKEN, optionally GALAXY_API_KEY"

collect-github:
@test -n "$(GITHUB_TOKEN)" || (echo "ERROR: GITHUB_TOKEN not set" && exit 1)
@QUARTER=$(QUARTER) DATE_RANGE=$(DATE_RANGE) bash scripts/collect_all_github_stats.sh

collect-galaxy:
@QUARTER=$(QUARTER) python3 scripts/collect_galaxy_stats.py

update-summary:
@QUARTER=$(QUARTER) python3 scripts/update_quarterly_summary.py

generate-graphs:
@QUARTER=$(QUARTER) python3 scripts/generate_graphs.py

quarterly-report: collect-github collect-galaxy update-summary generate-graphs
@echo ""
@echo "✅ Complete for $(QUARTER)"
@echo "To generate AI analysis with your AI agent:"
@echo " Use the skill defined in .claude/skills/analyze-quarterly-metrics/"
@echo " (For Claude Code users: /analyze-quarterly-metrics $(QUARTER))"

clean:
@find . -type f -name "*.pyc" -delete
@find . -type d -name "__pycache__" -delete
Loading