commit 7b1bbe81ec65135d175f0511a805090fe508b5c6 Author: Zhongwei Li Date: Sat Nov 29 18:17:32 2025 +0800 Initial commit diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000..fbc672b --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,12 @@ +{ + "name": "osdu", + "description": "GitLab CI/CD test quality analysis for OSDU projects", + "version": "0.0.0-2025.11.28", + "author": { + "name": "Daniel Scholl", + "email": "dascholl@microsoft.com" + }, + "skills": [ + "./skills" + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..dc3a773 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# osdu + +GitLab CI/CD test quality analysis for OSDU projects diff --git a/plugin.lock.json b/plugin.lock.json new file mode 100644 index 0000000..a5d5843 --- /dev/null +++ b/plugin.lock.json @@ -0,0 +1,53 @@ +{ + "$schema": "internal://schemas/plugin.lock.v1.json", + "pluginId": "gh:danielscholl/agent-skills:plugins/osdu", + "normalized": { + "repo": null, + "ref": "refs/tags/v20251128.0", + "commit": "b042446ef5a2331fddd323f38359dee31b6eb63d", + "treeHash": "cdb065eb98ffd49fe853cd2785e40e9b2e9d3f96c3a9c93fe8a44e6706f94b54", + "generatedAt": "2025-11-28T10:16:01.562255Z", + "toolVersion": "publish_plugins.py@0.2.0" + }, + "origin": { + "remote": "git@github.com:zhongweili/42plugin-data.git", + "branch": "master", + "commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390", + "repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data" + }, + "manifest": { + "name": "osdu", + "description": "GitLab CI/CD test quality analysis for OSDU projects", + "version": null + }, + "content": { + "files": [ + { + "path": "README.md", + "sha256": "abddb9cb31a3632ddf27421f05c42f56e3bcd6f167b2c3e8854074712fa87181" + }, + { + "path": ".claude-plugin/plugin.json", + "sha256": "7cedc92de7adc58f6198df234f3eb239a108360ee67766979d1ae9b34432943a" + }, + { + "path": "skills/osdu/SKILL.md", + "sha256": "40fc8ae1cd8ddcf24923cdf3c589325d54bfd83b4522ba7223525e80950258c8" + }, + { + "path": "skills/osdu/scripts/analyze.py", + "sha256": "260d8f6251cc2fe66f51f6aa56ee29f4d00c5a3dcf9b1db41c654afbd787a035" + }, + { + "path": "skills/osdu/scripts/status.py", + "sha256": "65adc213de08c57f9c9bcaaebdded9a744cf8feeb838ce0382b36ec51d5337b8" + } + ], + "dirSha256": "cdb065eb98ffd49fe853cd2785e40e9b2e9d3f96c3a9c93fe8a44e6706f94b54" + }, + "security": { + "scannedAt": null, + "scannerVersion": null, + "flags": [] + } +} \ No newline at end of file diff --git a/skills/osdu/SKILL.md b/skills/osdu/SKILL.md new file mode 100644 index 0000000..ab82672 --- /dev/null +++ b/skills/osdu/SKILL.md @@ -0,0 +1,358 @@ +--- +name: osdu +description: "GitLab CI/CD test job reliability analysis for OSDU projects. Tracks test job (unit/integration/acceptance) pass/fail status across pipeline runs. Use for test job status, flaky test job detection, test reliability/quality metrics, cloud provider analytics. Wraps osdu-quality CLI." +version: 2.0.0 +brief_description: "OSDU GitLab CI/CD test reliability analysis" +triggers: + keywords: [osdu, gitlab, quality, ci, cd, pipeline, test, job, reliability, flaky, acceptance, integration, unit, azure, aws, gcp, cloud, provider] + verbs: [analyze, track, monitor, test, check] + patterns: + - "test.*(?:reliability|status|job)" + - "pipeline.*(?:analysis|status)" + - "flaky.*test" + - "ci.*cd" + - "gitlab.*(?:pipeline|job)" +allowed-tools: Bash +--- + + + + Analyze GitLab CI/CD test job reliability for OSDU platform projects, tracking test job pass/fail status across pipeline runs to identify flaky tests and provide quality metrics. + + + + + OSDU project test status queries ("how is {project} looking", "partition test quality") + Flaky test detection ("are there flaky tests in {project}") + Pipeline health monitoring ("recent pipeline failures") + Cloud provider comparison ("azure vs aws test reliability") + Stage-specific analysis ("unit test status", "integration test failures") + + + + Individual test case tracking (we track job-level, not test-level) + Non-test jobs (build, deploy, lint, security scans) + Non-OSDU projects or non-GitLab CI systems + Real-time monitoring (data is from completed pipelines only) + + + + + + Pipeline Run → Test Stage (unit/integration/acceptance) → Test Job → Test Suite (many tests) + + + + Test job pass/fail status across multiple pipeline runs + Flaky test job detection (jobs that intermittently fail) + Stage-level metrics (unit/integration/acceptance) + Cloud provider breakdown (azure, aws, gcp, ibm, cimpl) + Individual test results (not tracked) + Non-test jobs like build, deploy, lint + + + + Pipeline #1: job "unit-tests-azure" → PASS (100/100 tests passed) + Pipeline #2: job "unit-tests-azure" → FAIL (99/100 tests passed) + Pipeline #3: job "unit-tests-azure" → PASS (100/100 tests passed) + Result: This job is FLAKY (unreliable across runs) + + + + + + + + + + + + + + + Use status.py for quick overview + script_run osdu status.py --format json --pipelines 3 --project {name} + Lightweight, fast, safe token usage + + + + Use analyze.py with strict filters + script_run osdu analyze.py --format json --pipelines 5 --project {name} --stage unit + Heavy query, use only when status insufficient + + + + ALWAYS specify --project to avoid 30-project scan + Prevents token limit exceeded error + + + + + + Extracting specific metrics or calculating statistics + Building summaries or comparisons + Parsing structured data programmatically + ALWAYS for status.py (lightweight, parseable) + + + + Analyze.py queries (10x smaller than JSON, still readable) + Creating reports for sharing + Need human-readable tables without parsing + Token budget is tight + + + + Includes ANSI codes and colors, hard to parse + Only for direct human terminal viewing + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + osdu-quality CLI installed: uv tool install git+https://community.opengroup.org/danielscholl/osdu-quality.git + GitLab authentication (choose one): + - GITLAB_TOKEN environment variable, OR + - glab CLI authenticated (glab auth login) + + Access to OSDU GitLab projects + + + + + + + + + + + Best approach: Start with status.py + script_run osdu status.py --format json --pipelines 3 --project partition + + + + Check status + script_run osdu status.py --format json --pipelines 5 --project partition + If issues found, deep dive with analyze.py + script_run osdu analyze.py --format markdown --pipelines 5 --project partition --stage unit + + + + Compare Azure vs AWS for specific project/stage + script_run osdu analyze.py --format markdown --pipelines 5 --project storage --stage integration --provider azure + script_run osdu analyze.py --format markdown --pipelines 5 --project storage --stage integration --provider aws + + + + Focus on unit tests only + script_run osdu analyze.py --format markdown --pipelines 5 --project entitlements --stage unit + + + + + + script_run osdu analyze.py --format json --pipelines 10 + Will exceed 200K token limit! + + + + script_run osdu analyze.py --format json --pipelines 20 + Takes 3+ minutes, huge output + + + + script_run osdu status.py --format terminal --project partition + Includes ANSI codes, hard to parse + + + + script_run osdu analyze.py --format json --pipelines 10 --project partition + Heavy query when status.py would suffice + + + + + + Always start with status.py, only use analyze.py if needed + + + Always specify --format json or --format markdown + + + Always include --project {name} to avoid all-30-projects scan + + + Start with --pipelines 3-5, increase only if necessary + + + Use --stage or --provider to narrow scope + + + Prefer --format markdown for analyze.py (10x token savings) + + + + + + Structured parsing, metrics extraction + + + Reports, sharing, analyze.py queries + + + Human viewing in terminal with colors + + + + + Clear message with installation command + Message about authentication requirements + API error details + List of valid options + Suggestion to reduce --pipelines or add filters + + + + Always follow progressive query approach + Never query without --project filter + Start with minimal pipeline counts + Use markdown format for analyze.py to save tokens + Apply stage or provider filters when possible + + \ No newline at end of file diff --git a/skills/osdu/scripts/analyze.py b/skills/osdu/scripts/analyze.py new file mode 100644 index 0000000..0e4891d --- /dev/null +++ b/skills/osdu/scripts/analyze.py @@ -0,0 +1,221 @@ +#!/usr/bin/env python3 +# /// script +# dependencies = [ +# "click", +# ] +# /// + +""" +OSDU Quality Analysis Script + +Analyze test reliability across multiple pipelines for OSDU projects. +Detects flaky tests, calculates pass rates, and provides cloud provider metrics. + +Usage: + uv run analyze.py --json --pipelines 20 + uv run analyze.py --json --stage unit --pipelines 30 + uv run analyze.py --json --provider azure + uv run analyze.py --json --project "partition" +""" + +import json +import os +import subprocess +import sys +from typing import Any + +import click + + +def check_prerequisites() -> None: + """ + Check that osdu-quality CLI is installed and GitLab authentication is configured. + + Authentication can be either: + - GITLAB_TOKEN environment variable + - glab CLI authentication (glab auth login) + + Raises: + Exception: If prerequisites are not met + """ + # Check GitLab authentication (GITLAB_TOKEN or glab auth) + has_token = bool(os.getenv("GITLAB_TOKEN")) + has_glab_auth = False + + if not has_token: + # Check if glab is authenticated + try: + result = subprocess.run( + ["glab", "auth", "status"], + capture_output=True, + check=True, + text=True, + ) + has_glab_auth = True + except (FileNotFoundError, subprocess.CalledProcessError): + has_glab_auth = False + + if not has_token and not has_glab_auth: + raise Exception( + "GitLab authentication not configured.\n" + "Use one of:\n" + " - export GITLAB_TOKEN='your-token-here'\n" + " - glab auth login" + ) + + # Check osdu-quality CLI + try: + subprocess.run( + ["osdu-quality", "--version"], + capture_output=True, + check=True, + text=True, + ) + except FileNotFoundError: + raise Exception( + "osdu-quality CLI not found.\n" + "Install with: uv tool install git+https://community.opengroup.org/danielscholl/osdu-quality.git" + ) + except subprocess.CalledProcessError as e: + raise Exception(f"osdu-quality CLI check failed: {e.stderr}") + + +def run_osdu_analyze( + pipelines: int, + project: str | None, + stage: str | None, + provider: str | None, + output_format: str, +) -> tuple[str, int]: + """ + Execute osdu-quality analyze command. + + Args: + pipelines: Number of pipelines to analyze + project: Optional project name filter + stage: Optional test stage filter (unit/integration/acceptance) + provider: Optional cloud provider filter (azure/aws/gcp/ibm/cimpl) + output_format: Output format (json, markdown, or terminal) + + Returns: + Tuple of (output_string, exit_code) + + Raises: + Exception: If command execution fails + """ + # Build command + cmd = ["osdu-quality", "analyze", "--pipelines", str(pipelines)] + + if project: + cmd.extend(["--project", project]) + if stage: + cmd.extend(["--stage", stage]) + if provider: + cmd.extend(["--provider", provider]) + + # Add output format if not default terminal (tty) + if output_format != "terminal": + cmd.extend(["--output", output_format]) + + try: + # Execute command + result = subprocess.run( + cmd, + capture_output=True, + check=True, + text=True, + ) + return result.stdout, 0 + + except subprocess.CalledProcessError as e: + # Command failed - return stderr + error_msg = e.stderr if e.stderr else e.stdout + raise Exception(f"osdu-quality command failed:\n{error_msg}") + except Exception as e: + raise Exception(f"Unexpected error: {str(e)}") + + +@click.command() +@click.option( + "--pipelines", + default=10, + type=int, + help="Number of pipelines to analyze (default: 10)", +) +@click.option( + "--project", + type=str, + help="Filter by project name (e.g., 'partition')", +) +@click.option( + "--stage", + type=click.Choice(["unit", "integration", "acceptance"], case_sensitive=False), + help="Filter by test stage", +) +@click.option( + "--provider", + type=click.Choice(["azure", "aws", "gcp", "ibm", "cimpl"], case_sensitive=False), + help="Filter by cloud provider", +) +@click.option( + "--format", + "output_format", + type=click.Choice(["json", "markdown", "terminal"], case_sensitive=False), + default="terminal", + help="Output format: json (structured data), markdown (reports/docs), or terminal (default, colored tables)", +) +def main( + pipelines: int, + project: str | None, + stage: str | None, + provider: str | None, + output_format: str, +): + """ + Analyze test reliability across multiple OSDU pipelines. + + Provides: + - Flaky test detection (tests that fail intermittently) + - Pass rate calculations per test stage + - Cloud provider metrics breakdown + - Multi-project quality analysis + + Output Formats: + - json: Structured data for AI parsing and automation + - markdown: Human-readable reports, great for documentation and sharing + - terminal: Interactive display with colors and tables (default) + + Requires: + - osdu-quality CLI installed (uv tool install git+https://...) + - GitLab authentication (GITLAB_TOKEN env var OR glab auth login) + """ + try: + # Check prerequisites + check_prerequisites() + + # Run osdu-quality analyze command + output, exit_code = run_osdu_analyze( + pipelines=pipelines, + project=project, + stage=stage, + provider=provider, + output_format=output_format, + ) + + # Output results + click.echo(output) + sys.exit(exit_code) + + except Exception as e: + if output_format == "json": + # JSON error format + error_data = {"error": str(e)} + click.echo(json.dumps(error_data, indent=2)) + else: + # Human-readable error (markdown and terminal) + click.echo(f"Error: {e}", err=True) + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/skills/osdu/scripts/status.py b/skills/osdu/scripts/status.py new file mode 100644 index 0000000..9de72d5 --- /dev/null +++ b/skills/osdu/scripts/status.py @@ -0,0 +1,217 @@ +#!/usr/bin/env python3 +# /// script +# dependencies = [ +# "click", +# ] +# /// + +""" +OSDU Quality Status Script + +Get latest test status by stage (unit/integration/acceptance) for OSDU projects. +Wraps the osdu-quality CLI tool for GitLab CI/CD pipeline analysis. + +Usage: + uv run status.py --json --pipelines 10 + uv run status.py --json --project "partition" + uv run status.py --json --venus --no-release +""" + +import json +import os +import subprocess +import sys +from typing import Any + +import click + + +def check_prerequisites() -> None: + """ + Check that osdu-quality CLI is installed and GitLab authentication is configured. + + Authentication can be either: + - GITLAB_TOKEN environment variable + - glab CLI authentication (glab auth login) + + Raises: + Exception: If prerequisites are not met + """ + # Check GitLab authentication (GITLAB_TOKEN or glab auth) + has_token = bool(os.getenv("GITLAB_TOKEN")) + has_glab_auth = False + + if not has_token: + # Check if glab is authenticated + try: + result = subprocess.run( + ["glab", "auth", "status"], + capture_output=True, + check=True, + text=True, + ) + has_glab_auth = True + except (FileNotFoundError, subprocess.CalledProcessError): + has_glab_auth = False + + if not has_token and not has_glab_auth: + raise Exception( + "GitLab authentication not configured.\n" + "Use one of:\n" + " - export GITLAB_TOKEN='your-token-here'\n" + " - glab auth login" + ) + + # Check osdu-quality CLI + try: + subprocess.run( + ["osdu-quality", "--version"], + capture_output=True, + check=True, + text=True, + ) + except FileNotFoundError: + raise Exception( + "osdu-quality CLI not found.\n" + "Install with: uv tool install git+https://community.opengroup.org/danielscholl/osdu-quality.git" + ) + except subprocess.CalledProcessError as e: + raise Exception(f"osdu-quality CLI check failed: {e.stderr}") + + +def run_osdu_status( + pipelines: int, + project: str | None, + venus: bool, + no_release: bool, + output_format: str, +) -> tuple[str, int]: + """ + Execute osdu-quality status command. + + Args: + pipelines: Number of pipelines to analyze + project: Optional project name filter + venus: Filter Venus provider only + no_release: Exclude release pipelines + output_format: Output format (json, markdown, or terminal) + + Returns: + Tuple of (output_string, exit_code) + + Raises: + Exception: If command execution fails + """ + # Build command + cmd = ["osdu-quality", "status", "--pipelines", str(pipelines)] + + if project: + cmd.extend(["--project", project]) + if venus: + cmd.append("--venus") + if no_release: + cmd.append("--no-release") + + # Add output format if not default terminal (tty) + if output_format != "terminal": + cmd.extend(["--output", output_format]) + + try: + # Execute command + result = subprocess.run( + cmd, + capture_output=True, + check=True, + text=True, + ) + return result.stdout, 0 + + except subprocess.CalledProcessError as e: + # Command failed - return stderr + error_msg = e.stderr if e.stderr else e.stdout + raise Exception(f"osdu-quality command failed:\n{error_msg}") + except Exception as e: + raise Exception(f"Unexpected error: {str(e)}") + + +@click.command() +@click.option( + "--pipelines", + default=10, + type=int, + help="Number of pipelines to analyze (default: 10)", +) +@click.option( + "--project", + type=str, + help="Filter by project name (e.g., 'partition')", +) +@click.option( + "--venus", + is_flag=True, + help="Filter Venus provider pipelines only", +) +@click.option( + "--no-release", + is_flag=True, + help="Exclude release pipelines from analysis", +) +@click.option( + "--format", + "output_format", + type=click.Choice(["json", "markdown", "terminal"], case_sensitive=False), + default="terminal", + help="Output format: json (structured data), markdown (reports/docs), or terminal (default, colored tables)", +) +def main( + pipelines: int, + project: str | None, + venus: bool, + no_release: bool, + output_format: str, +): + """ + Get latest test status by stage for OSDU projects. + + Returns pipeline status with test results organized by stage + (unit, integration, acceptance). + + Output Formats: + - json: Structured data for AI parsing and automation + - markdown: Human-readable reports, great for documentation and sharing + - terminal: Interactive display with colors and tables (default) + + Requires: + - osdu-quality CLI installed (uv tool install git+https://...) + - GitLab authentication (GITLAB_TOKEN env var OR glab auth login) + """ + try: + # Check prerequisites + check_prerequisites() + + # Run osdu-quality status command + output, exit_code = run_osdu_status( + pipelines=pipelines, + project=project, + venus=venus, + no_release=no_release, + output_format=output_format, + ) + + # Output results + click.echo(output) + sys.exit(exit_code) + + except Exception as e: + if output_format == "json": + # JSON error format + error_data = {"error": str(e)} + click.echo(json.dumps(error_data, indent=2)) + else: + # Human-readable error (markdown and terminal) + click.echo(f"Error: {e}", err=True) + sys.exit(1) + + +if __name__ == "__main__": + main()