Skip to content
Back to skills

Generate Allure Report

ASecurity

Generate Allure-ready reports from bigpowers YAML metadata. Reads execution-status.yaml, release-plan.yaml, epic capsules, task YAMLs, cycle-times.yaml, and bug registry to produce allure-results/junit-results.xml, categories.json, and executor.json. Use when preparing progress dashboards, integrating with Allure TestOps, or generating CI reports.

  • 274 stars
  • 0 votes
  • 0 copies
  • 4 views
  • Added October 25, 2026
developmentpythongobashgitsecurity

Works with

  • terminal

Security analysis

A100/100

Scanned October 25, 2026

npx -y skills add danielvm-git/bigpowers --skill generate-allure-report --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Generate Allure Report?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Generate Allure Report
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/danielvm-git-generate-allure-report-bigpowers/badge)](https://www.skillsdirectory.com/skills/danielvm-git-generate-allure-report-bigpowers)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: generate-allure-report
model: sonnet
description: "Generate Allure-ready reports from bigpowers YAML metadata. Reads execution-status.yaml, release-plan.yaml, epic capsules, task YAMLs, cycle-times.yaml, and bug registry to produce allure-results/junit-results.xml, categories.json, and executor.json. Use when preparing progress dashboards, integrating with Allure TestOps, or generating CI reports."
disable-model-invocation: true
---

# Generate Allure Report

Generate Allure TestOps-compatible reports from bigpowers project metadata. Produces JUnit XML for story-level test results, custom categories for filtering, and executor metadata — all in the `allure-results/` directory.

## Quick Start

```bash
bash scripts/generate-allure-report.sh
```

## What It Produces

Three files in `allure-results/`:

| File | Description |
|------|-------------|
| `junit-results.xml` | One `<testcase>` per story with `<properties>` for risk, security, WSJF, tier, wave, and status. Incomplete stories get a `<failure>` element. |
| `categories.json` | Custom Allure categories for filtering by epic, risk level (P0), and security reviews. |
| `executor.json` | Build metadata — name, type, version from release-plan.yaml, build order. |

## Data Sources

See [REFERENCE.md](REFERENCE.md)

## Verify

```bash
test -f allure-results/junit-results.xml && test -f allure-results/categories.json && test -f allure-results/executor.json
```

## Handoff

- next_skill: null (terminal skill — no downstream workflow step)

---

# generate-allure-report — Reference

## Data Sources

The script reads five YAML sources from the project:

| Source | Path | Fields Used |
|--------|------|-------------|
| Execution status | `specs/execution-status.yaml` | `epics`, `stories`, `development_status` |
| Release plan | `specs/release-plan.yaml` | `release.version`, `release.status`, `bugs` summary |
| Epic capsules | `specs/epics/**/epic.yaml` + `-tasks.yaml` | Epic metadata, task pass/fail counts |
| Cycle times | `specs/metrics/cycle-times.yaml` | Story-level `cycle_minutes`, `bcp_per_hour`, `source` |
| Bug registry | `specs/bugs/registry.yaml` | Bug counts by status and severity |

## Script Body

`scripts/generate-allure-report.sh`:

```bash
#!/usr/bin/env bash
set -euo pipefail
source "$(dirname "${BASH_SOURCE[0]}")/lib/python-env.sh"
ROOT="$(git rev-parse --show-toplevel 2>/dev/null)" || ROOT="$(dirname "${BASH_SOURCE[0]}")/.."

mkdir -p "$ROOT/allure-results"

$PYTHON - "$ROOT" <<'PY'
import json
import sys
import xml.etree.ElementTree as ET
from pathlib import Path

root = Path(sys.argv[1])
out = root / "allure-results"

# 1. Read execution-status.yaml
exec_status_file = root / "specs" / "execution-status.yaml"
release_plan_file = root / "specs" / "release-plan.yaml"
cycle_times_file = root / "specs" / "metrics" / "cycle-times.yaml"
bugs_registry_file = root / "specs" / "bugs" / "registry.yaml"

sys.path.insert(0, str(root / "scripts" / "lib"))
from simple_yaml import parse_simple_yaml

exec_status = parse_simple_yaml(exec_status_file.read_text()) if exec_status_file.exists() else {}
release_plan = parse_simple_yaml(release_plan_file.read_text()) if release_plan_file.exists() else {}
cycle_times = parse_simple_yaml(cycle_times_file.read_text()) if cycle_times_file.exists() else {"stories": []}
bugs_registry = parse_simple_yaml(bugs_registry_file.read_text()) if bugs_registry_file.exists() else {"bugs": []}

# Build cycle-times lookup
ct_lookup = {}
for ct in cycle_times.get("stories", []):
    if isinstance(ct, dict):
        ct_lookup[ct.get("id", "")] = ct

# 2. Build JUnit XML
stories = exec_status.get("stories", {})

# Counts for testsuite attributes
total_stories = len(stories)
incomplete = sum(1 for s in stories.values() if isinstance(s, dict) and s.get("status") != "done")

testsuite = ET.Element("testsuite", {
    "name": "bigpowers-epic-progress",
    "tests": str(total_stories),
    "failures": str(incomplete),
    "errors": "0",
    "skipped": "0",
})

for story_id in sorted(stories.keys()):
    story = stories[story_id]
    if not isinstance(story, dict):
        continue

    epic_id = story.get("epic", "unknown")
    title = story.get("title", story_id)
    bcps = story.get("bcps", 0)
    status = story.get("status", "backlog")
    risk_max = story.get("risk_max", "none")
    security_max = story.get("security_max", "none")

    # Enrich with cycle-times data
    ct_data = ct_lookup.get(story_id, {})
    cycle_minutes = ct_data.get("cycle_minutes", 0)
    bcp_per_hour = ct_data.get("bcp_per_hour", 0)

    # Time: cycle_minutes * 60 for seconds in Allure display
    time_seconds = cycle_minutes * 60.0 if cycle_minutes else 0.0

    testcase = ET.SubElement(testsuite, "testcase", {
        "classname": epic_id,
        "name": f"{story_id}: {title}",
        "time": str(round(time_seconds, 3)),
    })

    props = ET.SubElement(testcase, "properties")
    ET.SubElement(props, "property", {"name": "risk", "value": risk_max})
    ET.SubElement(props, "property", {"name": "security", "value": security_max})
    ET.SubElement(props, "property", {"name": "bcps", "value": str(bcps)})
    ET.SubElement(props, "property", {"name": "status", "value": status})
    ET.SubElement(props, "property", {"name": "bcp_per_hour", "value": str(bcp_per_hour)})
    ET.SubElement(props, "property", {"name": "lead_time_minutes", "value": str(cycle_minutes)})

    if status != "done":
        ET.SubElement(testcase, "failure", {
            "message": f"Story {story_id} is {status} [risk={risk_max}, security={security_max}]",
            "type": "StoryIncomplete"
        })

tree = ET.ElementTree(testsuite)
ET.indent(tree, space="  ")
tree.write(str(out / "junit-results.xml"), encoding="utf-8", xml_declaration=True)

# 3. Build categories.json
epics = exec_status.get("epics", {})
categories = []

for epic_id in sorted(epics.keys()):
    epic = epics[epic_id]
    if isinstance(epic, dict) and epic.get("status") != "done":
        categories.append({
            "name": f"Epic: {epic.get('title', epic_id)}",
            "matchedStatuses": ["failed"],
            "messageRegex": f".*{epic_id}:.*"
        })

categories.append({
    "name": "P0 Risk",
    "matchedStatuses": ["failed"],
    "messageRegex": ".*risk.*P0.*"
})
categories.append({
    "name": "Security Review",
    "matchedStatuses": ["failed"],
    "messageRegex": ".*security.*(?:medium|high).*"
})

# Add bug-based categories
bug_list = bugs_registry.get("bugs", [])
bug_count = len(bug_list) if isinstance(bug_list, list) else 0
open_bugs = sum(1 for b in bug_list if isinstance(b, dict) and b.get("status") not in ("fixed", "closed", None))
if open_bugs > 0:
    categories.append({
        "name": "Open Bugs",
        "matchedStatuses": ["failed"],
        "messageRegex": ".*Bug.*"
    })

(out / "categories.json").write_text(json.dumps(categories, indent=2))

# 4. Build executor.json
rl = release_plan.get("release", {}) if isinstance(release_plan.get("release"), dict) else {}
executor = {
    "name": "bigpowers",
    "type": "bigpowers",
    "buildName": rl.get("version", "unknown") if isinstance(rl, dict) else "unknown",
    "buildOrder": len(exec_status.get("development_status", {})),
}
(out / "executor.json").write_text(json.dumps(executor, indent=2))

# Summary
epic_count = len([e for e in epics.values() if isinstance(e, dict) and e.get("status") == "done"])
total_epics = len(epics)
print(f"generate-allure-report: {total_stories} stories, {epic_count}/{total_epics} epics done, {bug_count} bugs")
print(f"  -> {out}/junit-results.xml")
print(f"  -> {out}/categories.json")
print(f"  -> {out}/executor.json")
PY
```

## JUnit XML Schema

```xml
<?xml version="1.0" encoding="utf-8"?>
<testsuite name="bigpowers-epic-progress" tests="N" failures="F" errors="0" skipped="0">
  <testcase classname="e01" name="e01s01: Security slopcheck tags" time="0.75">
    <properties>
      <property name="risk" value="none"/>
      <property name="security" value="none"/>
      <property name="bcps" value="1"/>
      <property name="status" value="done"/>
      <property name="bcp_per_hour" value="1.3"/>
      <property name="lead_time_minutes" value="45"/>
    </properties>
  </testcase>
  <testcase classname="e01" name="e01s99: Some incomplete story" time="0.0">
    <properties>...</properties>
    <failure message="Story e01s99 is backlog [risk=P0, security=high]" type="StoryIncomplete"/>
  </testcase>
</testsuite>
```

## Categories JSON Schema

```json
[
  {
    "name": "Epic: Quality Core - Skill Hardening",
    "matchedStatuses": ["failed"],
    "messageRegex": ".*e45:.*"
  },
  {
    "name": "P0 Risk",
    "matchedStatuses": ["failed"],
    "messageRegex": ".*risk.*P0.*"
  },
  {
    "name": "Security Review",
    "matchedStatuses": ["failed"],
    "messageRegex": ".*security.*(?:medium|high).*"
  }
]
```

## Executor JSON Schema

```json
{
  "name": "bigpowers",
  "type": "bigpowers",
  "buildName": "2.76.2",
  "buildOrder": 400
}
```

## Example Usage

```bash
# Generate reports
bash scripts/generate-allure-report.sh

# Verify output
test -f allure-results/junit-results.xml && echo "JUnit OK"
test -f allure-results/categories.json && echo "Categories OK"
test -f allure-results/executor.json && echo "Executor OK"

# Serve with Allure
allure serve allure-results/

# Or open the Allure TestOps UI
allure open allure-results/
```

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.