diff --git a/README.md b/README.md index 8ffa35b..eedc196 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,9 @@ When a team edits their `devops-maturity.yml` assessment file the action will: 3. Update the `README.md` badge in-place (or prepend one if none exists). 4. Open (or update) a pull request containing the badge change for review. +Set `report: true` to also generate a human-readable maturity report in the +workflow run summary (see [Reports](#reports)). + ## Usage ### Minimal setup @@ -80,6 +83,7 @@ D202: false # Functional Testing (must have) | `pr-title` | no | `chore: update devops-maturity badges` | Title of the pull request. | | `pr-body` | no | *(auto-generated)* | Body text of the pull request. | | `cli-version` | no | *(latest)* | Pin a specific CLI version for reproducible results (e.g. `0.1.0`). | +| `report` | no | `false` | When `true`, write a maturity report (score, category breakdown, recommendations) to the run summary. | ## Outputs @@ -89,6 +93,7 @@ D202: false # Functional Testing (must have) | `level` | Maturity level: `WIP`, `PASSING`, `BRONZE`, `SILVER`, or `GOLD`. | | `badge-url` | shields.io badge URL for the current maturity level. | | `badge-markdown` | Ready-to-paste Markdown snippet for the badge. | +| `report-path` | Path to the generated Markdown report (only when `report: true`). | | `pull-request-number`| Number of the created (or updated) pull request. | | `pull-request-url` | HTML URL of the created (or updated) pull request. | @@ -107,6 +112,37 @@ D202: false # Functional Testing (must have) echo "PR : ${{ steps.maturity.outputs.pull-request-url }}" ``` +## Reports + +Set `report: true` to generate a human-readable maturity report — the overall +score and level, a per-category breakdown, and the list of unmet criteria with +improvement recommendations. The report is written to the workflow run's +[job summary](https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-job-summary), +so it shows up directly on the Actions run page — no artifact download needed. + +```yaml +- uses: devops-maturity/devops-maturity-action@v1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + report: true +``` + +The same Markdown is also written to a file, exposed via the `report-path` +output, so you can upload it as an artifact if you want to keep it: + +```yaml +- id: maturity + uses: devops-maturity/devops-maturity-action@v1 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + report: true + +- uses: actions/upload-artifact@v4 + with: + name: devops-maturity-report + path: ${{ steps.maturity.outputs.report-path }} +``` + ## Permissions The workflow job must have the following permissions: diff --git a/action.yml b/action.yml index 0f99bb0..b3c0571 100644 --- a/action.yml +++ b/action.yml @@ -60,6 +60,16 @@ inputs: required: false default: '' + report: + description: > + When 'true', generate a human-readable maturity report (score, level, + category breakdown, and improvement recommendations) and write it to the + GitHub Actions job summary. The same Markdown is written to a file whose + path is exposed via the 'report-path' output, so it can be uploaded as an + artifact. + required: false + default: 'false' + outputs: score: description: 'Overall DevOps maturity score as a percentage (e.g. "72.3%").' @@ -77,6 +87,12 @@ outputs: description: 'Ready-to-paste Markdown snippet for the badge.' value: ${{ steps.assessment.outputs.badge_markdown }} + report-path: + description: > + Filesystem path to the generated Markdown report. Only set when the + 'report' input is 'true'. + value: ${{ steps.report.outputs.report_path }} + pull-request-number: description: 'Number of the created (or updated) pull request.' value: ${{ steps.create-pr.outputs.pull-request-number }} @@ -134,6 +150,76 @@ runs: echo "badge_url=${BADGE_URL}" >> "$GITHUB_OUTPUT" echo "badge_markdown=${BADGE_MD}" >> "$GITHUB_OUTPUT" + # Persist the full JSON so the (optional) report step can reuse it. + printf '%s' "$JSON_OUTPUT" > "$RUNNER_TEMP/devops-maturity.json" + + # ── 2b. Generate maturity report (optional) ────────────────────────────── + - name: Generate maturity report + id: report + if: ${{ inputs.report == 'true' }} + shell: python + env: + DM_JSON: ${{ runner.temp }}/devops-maturity.json + run: | + import json + import os + + with open(os.environ["DM_JSON"], encoding="utf-8") as fh: + result = json.load(fh) + + def bar(pct: float) -> str: + filled = int(round(pct / 10)) + return "█" * filled + "░" * (10 - filled) + + passed = result.get("passed", []) + failed = result.get("failed", []) + total = len(passed) + len(failed) + + lines = [ + f"# DevOps Maturity Report — {result.get('project_name', 'project')}", + "", + f"**Score:** {result.get('score')}% · **Level:** {result.get('level')}", + "", + result.get("badge_markdown", ""), + "", + "## Category breakdown", + "", + "| Category | Score | |", + "|---|---:|:--|", + ] + for category, cat_score in result.get("category_scores", {}).items(): + lines.append(f"| {category} | {cat_score:.0f}% | `{bar(cat_score)}` |") + + lines += ["", f"## Met ({len(passed)}/{total})", ""] + lines.append(", ".join(f"`{c['id']}`" for c in passed) if passed else "_None yet._") + + lines += ["", f"## Improvement recommendations ({len(failed)})", ""] + if failed: + for c in failed: + desc = c.get("description", "") + suffix = f" — {desc}" if desc else "" + lines.append(f"- **{c['id']} · {c['criteria']}**{suffix}") + else: + lines.append("_All criteria met. 🎉_") + + report_md = "\n".join(lines) + "\n" + + # Render into the Actions run summary (visible in the workflow UI). + summary_path = os.environ.get("GITHUB_STEP_SUMMARY") + if summary_path: + with open(summary_path, "a", encoding="utf-8") as fh: + fh.write(report_md) + + # Write to a file outside the repo so it is not committed to the PR. + report_path = os.path.join(os.environ["RUNNER_TEMP"], "devops-maturity-report.md") + with open(report_path, "w", encoding="utf-8") as fh: + fh.write(report_md) + + with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as fh: + fh.write(f"report_path={report_path}\n") + + print(f"Maturity report written to the job summary and {report_path}") + # ── 3. Update README badge ──────────────────────────────────────────────── - name: Update README badge shell: python