diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 12970656c..ae4a0eb63 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -88,7 +88,7 @@ "name": "ci", "source": "./plugins/ci", "description": "A plugin to work with OpenShift CI and analyze Prow job results", - "version": "0.0.55", + "version": "0.0.56", "category": "ci", "keywords": [ "prow", diff --git a/.github/workflows/lint-plugins.yml b/.github/workflows/lint-plugins.yml index b98a7f5d3..64505c3d1 100644 --- a/.github/workflows/lint-plugins.yml +++ b/.github/workflows/lint-plugins.yml @@ -19,6 +19,7 @@ jobs: persist-credentials: false - name: Run skillsaw - uses: stbenjam/skillsaw@3e1188f446413e6d6818c98644d2d6a84e4038e7 # v0.14.1 + uses: stbenjam/skillsaw@a1d7340ef19cd0949f884a5381155843589dbad8 # v0.15.0 with: strict: true + no-custom-rules: false diff --git a/.github/workflows/lint-review.yml b/.github/workflows/lint-review.yml index 0c7f74506..e23ecc1df 100644 --- a/.github/workflows/lint-review.yml +++ b/.github/workflows/lint-review.yml @@ -25,4 +25,4 @@ jobs: persist-credentials: false - name: Post review comments - uses: stbenjam/skillsaw/review@3e1188f446413e6d6818c98644d2d6a84e4038e7 # v0.14.1 + uses: stbenjam/skillsaw/review@a1d7340ef19cd0949f884a5381155843589dbad8 # v0.15.0 diff --git a/.skillsaw.yaml b/.skillsaw.yaml index 9ccb6afc3..fd5bdefc3 100644 --- a/.skillsaw.yaml +++ b/.skillsaw.yaml @@ -1,6 +1,6 @@ # skillsaw configuration # https://github.com/stbenjam/skillsaw -version: "0.14.1" +version: "0.15.0" strict: true rules: @@ -111,6 +111,7 @@ custom-rules: # Use exclude: [] to disable all excludes including defaults exclude: - "node_modules/**" + - "**/__pycache__/**" - "**/template/**" - "**/templates/**" - "**/_template/**" diff --git a/Makefile b/Makefile index 3aa19ccc3..02c324059 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ CONTAINER_RUNTIME ?= $(shell command -v podman 2>/dev/null || echo docker) # skillsaw image -SKILLSAW_IMAGE = ghcr.io/stbenjam/skillsaw:0.14.1 +SKILLSAW_IMAGE = ghcr.io/stbenjam/skillsaw:0.15.0 # Detect if SELinux is enforcing and add security option SELINUX_OPT := $(shell if command -v getenforce >/dev/null 2>&1 && [ "$$(getenforce 2>/dev/null)" = "Enforcing" ]; then echo "--security-opt label=disable"; fi) diff --git a/docs/index.html b/docs/index.html index f0675747a..3a0036d83 100644 --- a/docs/index.html +++ b/docs/index.html @@ -512,7 +512,7 @@

ai-helpers

{ "name": "ci", "description": "Tools for working with OpenShift CI and analyzing Prow job results", - "version": "0.0.55", + "version": "0.0.56", "has_readme": true, "commands": [ { diff --git a/plugins/ci/.claude-plugin/plugin.json b/plugins/ci/.claude-plugin/plugin.json index b86bc1f71..d1d26b339 100644 --- a/plugins/ci/.claude-plugin/plugin.json +++ b/plugins/ci/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "ci", "description": "Tools for working with OpenShift CI and analyzing Prow job results", - "version": "0.0.55", + "version": "0.0.56", "author": { "name": "github.com/openshift-eng" } diff --git a/plugins/ci/skills/payload-autodl-json/SKILL.md b/plugins/ci/skills/payload-autodl-json/SKILL.md index 70ce752c0..bcbead421 100644 --- a/plugins/ci/skills/payload-autodl-json/SKILL.md +++ b/plugins/ci/skills/payload-autodl-json/SKILL.md @@ -213,6 +213,14 @@ After staging reverts, find rows matching `candidate_pr_url` and set: - **PASS** (confirmed cause): `revert_pr_status`: `"open"` - **FAIL** (innocent): `revert_pr_url`: `""`, `revert_pr_status`: `""` (draft was closed) +## Validation + +Use [scripts/validate.py](scripts/validate.py) to check your file against the canonical schema: + +```bash +python3 scripts/validate.py +``` + ## See Also - Related Skill: `payload-analysis` — creates this file in Step 8 diff --git a/plugins/ci/skills/payload-results-yaml/SKILL.md b/plugins/ci/skills/payload-results-yaml/SKILL.md index eaca210e9..06a57120e 100644 --- a/plugins/ci/skills/payload-results-yaml/SKILL.md +++ b/plugins/ci/skills/payload-results-yaml/SKILL.md @@ -214,6 +214,14 @@ For a given candidate's action entry (matched by `pr_url` and `type`), update it Scan all candidates. If any candidate has an action with `type: "experiment"` and `status: "pending"`, the file has in-progress experiments awaiting Phase 2 collection. Phase 2 processes only pending experiments — candidates with other statuses are left unchanged. +## Validation + +Use [scripts/validate.py](scripts/validate.py) to check your file against the canonical schema: + +```bash +python3 scripts/validate.py +``` + ## See Also - Related Skill: `payload-analysis` — creates the results file diff --git a/plugins/ci/skills/prow-job-analyze-resource/SKILL.md b/plugins/ci/skills/prow-job-analyze-resource/SKILL.md index 7b02c2bae..7d78b96b6 100644 --- a/plugins/ci/skills/prow-job-analyze-resource/SKILL.md +++ b/plugins/ci/skills/prow-job-analyze-resource/SKILL.md @@ -579,6 +579,7 @@ Output: - Supports regex patterns for resource matching - `generate_html_report.py` - Generates interactive HTML report from JSON - Scripts output status messages to stderr for progress display. JSON output to stdout is clean. + - See [SCRIPTS.md](SCRIPTS.md) for detailed documentation of every script. 5. **Pod Log Glog Format Support:** - The parser automatically detects and parses glog format logs diff --git a/plugins/ci/skills/prow-job-analyze-resource/create_inline_html_files.py b/plugins/ci/skills/prow-job-analyze-resource/create_inline_html_files.py deleted file mode 100644 index a75e21e3c..000000000 --- a/plugins/ci/skills/prow-job-analyze-resource/create_inline_html_files.py +++ /dev/null @@ -1,333 +0,0 @@ -#!/usr/bin/env python3 -"""Create HTML files with line numbers for inline viewing.""" - -import os -import sys -import hashlib -import html as html_module -from pathlib import Path - - -def create_html_files_for_logs(logs_dir, build_id): - """Create .html files with line numbers for log files under 1MB.""" - MAX_INLINE_SIZE = 1 * 1024 * 1024 # 1MB - links_dir = os.path.join(logs_dir, '_links') - - # Create _links directory if it doesn't exist - os.makedirs(links_dir, exist_ok=True) - - html_count = 0 - file_mapping = {} # Map from original path to HTML path - - # Walk through all log files - for root, dirs, filenames in os.walk(logs_dir): - # Skip the _links directory itself - if '_links' in root: - continue - - for filename in filenames: - file_path = os.path.join(root, filename) - - try: - # Get file size - size = os.path.getsize(file_path) - - if size < MAX_INLINE_SIZE: - # Get relative path from logs_dir - rel_path = os.path.relpath(file_path, logs_dir) - - # Generate unique HTML name by hashing the full path - path_hash = hashlib.md5(rel_path.encode()).hexdigest()[:8] - html_name = f"{filename}.{path_hash}.html" - html_path = os.path.join(links_dir, html_name) - - # Read original file content - with open(file_path, 'r', encoding='utf-8', errors='replace') as f: - content = f.read() - - # Split into lines and add line numbers - lines = content.split('\n') - line_count = len(lines) - line_number_width = len(str(line_count)) - - # Build content with line numbers - numbered_lines = [] - for i, line in enumerate(lines, 1): - escaped_line = html_module.escape(line) - line_num = str(i).rjust(line_number_width) - numbered_lines.append(f'{line_num} {escaped_line}') - - numbered_content = '\n'.join(numbered_lines) - - # Wrap in HTML - html_content = f''' - - - - {html_module.escape(filename)} - - - -
-
- - -
-
Invalid regex pattern
-
-
-
{numbered_content}
-
- - -''' - - # Write HTML file - with open(html_path, 'w', encoding='utf-8') as f: - f.write(html_content) - - # Store mapping - rel_html_path = f"logs/_links/{html_name}" - file_mapping[rel_path] = rel_html_path - html_count += 1 - - except Exception as e: - print(f"WARNING: Could not create HTML for {file_path}: {e}", file=sys.stderr) - - print(f"Created {html_count} .html files for inline viewing", file=sys.stderr) - return file_mapping - - -def main(): - if len(sys.argv) < 3: - print("Usage: create_inline_html_files.py ") - sys.exit(1) - - logs_dir = sys.argv[1] - build_id = sys.argv[2] - - if not os.path.exists(logs_dir): - print(f"ERROR: Logs directory not found: {logs_dir}", file=sys.stderr) - sys.exit(1) - - file_mapping = create_html_files_for_logs(logs_dir, build_id) - - # Output mapping as JSON for use by other scripts - import json - print(json.dumps(file_mapping)) - - -if __name__ == '__main__': - main() diff --git a/plugins/jira/skills/status-analysis/SKILL.md b/plugins/jira/skills/status-analysis/SKILL.md index bf3b18866..5e4cef4ec 100644 --- a/plugins/jira/skills/status-analysis/SKILL.md +++ b/plugins/jira/skills/status-analysis/SKILL.md @@ -102,6 +102,9 @@ This skill is composed of four sub-modules. Read each when executing the analysi | External Links | `external-links.md` | GitHub PR and GitLab MR integration | | Formatting | `formatting.md` | Output templates for different modes | | Data Gatherer | `scripts/gather_status_data.py` | Async batch data collection (update-weekly-status) | +| Issue Summarizer | `scripts/summarize_issue.py` | Structured per-issue summaries for LLM analysis (update-weekly-status, generate-feature-updates) | +| Issue Triage | `scripts/triage_issues.py` | Classifies issues as significant or skippable by activity and R/Y/G status (generate-feature-updates) | +| Update Validator | `scripts/validate_feature_updates.py` | Validates generated feature-update markdown and HTML (generate-feature-updates) | ## Configuration Parameters diff --git a/plugins/must-gather/skills/must-gather-analyzer/SKILL.md b/plugins/must-gather/skills/must-gather-analyzer/SKILL.md index f12f23b00..de3184400 100644 --- a/plugins/must-gather/skills/must-gather-analyzer/SKILL.md +++ b/plugins/must-gather/skills/must-gather-analyzer/SKILL.md @@ -189,6 +189,22 @@ Shows monitoring information: - Alerts (state, namespace, name, active since, labels) - Total of pending/firing alerts +#### OVN Database Analysis +```bash +./scripts/analyze_ovn_dbs.py +``` + +Analyzes OVN Northbound and Southbound databases collected per-node under +`network_logs/` (requires `ovsdb-tool`). + +#### Windows Node Logs Analysis +```bash +./scripts/analyze_windows_logs.py +``` + +Parses Windows node logs from `host_service_logs/windows/log_files/` and +identifies issues. + ### 3. Interpret and Report After running the scripts: diff --git a/plugins/olm-team/skills/k8s-ocp-olm-expert/SKILL.md b/plugins/olm-team/skills/k8s-ocp-olm-expert/SKILL.md index ea65c8056..cc4b70b23 100644 --- a/plugins/olm-team/skills/k8s-ocp-olm-expert/SKILL.md +++ b/plugins/olm-team/skills/k8s-ocp-olm-expert/SKILL.md @@ -15,6 +15,10 @@ You are an elite software engineer with deep, specialized expertise in Kubernete The configuration file should be located at: `~/.config/claude-code/olm-agent-config.json` +The expected structure is defined by [config-template.json](config-template.json) +(JSON schema) with a filled-in example in [config-example.json](config-example.json); +`/olm-team:configure-agent` creates the file from these. + ```bash # Check if configuration file exists if [ -f ~/.config/claude-code/olm-agent-config.json ]; then