Skip to content

Daily Issue Health Report #59

Daily Issue Health Report

Daily Issue Health Report #59

name: Daily Issue Health Report
on:
schedule:
- cron: "30 23 * * *"
workflow_dispatch:
inputs:
hours:
description: "Lookback hours"
required: false
default: "24"
type: string
discussion_number:
description: "Discussion number to publish report"
required: false
default: ""
type: string
publish_comment:
description: "Publish report to discussion"
required: false
default: "true"
type: choice
options:
- "true"
- "false"
permissions:
contents: read
issues: read
actions: read
discussions: write
env:
REPO_NAME: ${{ github.repository }}
HOURS: ${{ github.event.inputs.hours || '24' }}
# 专用日报贴编号:优先 workflow_dispatch 输入,否则读取仓库变量 DAILY_REPORT_DISCUSSION_NUMBER
DISCUSSION_NUMBER: ${{ github.event.inputs.discussion_number || vars.DAILY_REPORT_DISCUSSION_NUMBER }}
PUBLISH_COMMENT: ${{ github.event.inputs.publish_comment || 'true' }}
GH_TOKEN: ${{ secrets.PAT_TOKEN || secrets.GITHUB_TOKEN }}
jobs:
report:
if: github.repository == 'gqy20/IssueLab'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v7
with:
python-version: '3.13'
enable-cache: true
- run: uv sync
- name: Generate daily facts
run: |
set -euo pipefail
mkdir -p artifacts
uv run python scripts/daily_issue_health_report.py \
--repo "${REPO_NAME}" \
--hours "${HOURS}" \
--output artifacts/daily_issue_health_facts.md \
--facts-output artifacts/daily_issue_health_facts.json
- name: Run ops_daily diagnosis
id: ops_daily
continue-on-error: true
env:
ANTHROPIC_AUTH_TOKEN: ${{ secrets.ANTHROPIC_AUTH_TOKEN }}
MINIMAX_API_KEY: ${{ secrets.ANTHROPIC_AUTH_TOKEN }}
ANTHROPIC_BASE_URL: ${{ secrets.ANTHROPIC_BASE_URL || 'https://api.minimaxi.com/anthropic' }}
ANTHROPIC_MODEL: ${{ secrets.ANTHROPIC_MODEL || 'MiniMax-M2.1' }}
run: |
set -euo pipefail
uv run python scripts/daily_issue_health_agent_report.py \
--facts artifacts/daily_issue_health_facts.json \
--output artifacts/daily_issue_health_agent.md \
--structured-output artifacts/daily_issue_health_agent.json
- name: Assemble final report
run: |
set -euo pipefail
{
cat artifacts/daily_issue_health_facts.md
echo ""
if [ -f artifacts/daily_issue_health_agent.md ]; then
cat artifacts/daily_issue_health_agent.md
else
echo "## 系统智能体诊断(ops_daily)"
echo ""
echo "> 当日诊断执行失败,已降级为仅发布 facts 报告。"
fi
} > artifacts/daily_issue_health_report.md
- name: Add step summary
run: |
cat artifacts/daily_issue_health_report.md >> "$GITHUB_STEP_SUMMARY"
- name: Validate discussion target
if: ${{ env.PUBLISH_COMMENT != 'false' }}
run: |
set -euo pipefail
if [ -z "${DISCUSSION_NUMBER}" ]; then
echo "DAILY_REPORT_DISCUSSION_NUMBER is not configured." >&2
echo "Please set repository variable DAILY_REPORT_DISCUSSION_NUMBER to your dedicated daily report discussion number." >&2
exit 1
fi
- name: Publish to discussion
if: ${{ env.PUBLISH_COMMENT != 'false' }}
run: |
set -euo pipefail
REPO_OWNER="${{ github.repository_owner }}"
REPO_SHORT="${{ github.event.repository.name }}"
DISC_ID=$(gh api graphql \
-f query='query($owner:String!,$name:String!,$number:Int!){repository(owner:$owner,name:$name){discussion(number:$number){id}}}' \
-f owner="${REPO_OWNER}" \
-f name="${REPO_SHORT}" \
-F number="${DISCUSSION_NUMBER}" \
--jq '.data.repository.discussion.id')
BODY="<!-- issuelab-daily-report -->"$'\n'"$(cat artifacts/daily_issue_health_report.md)"
gh api graphql \
-f query='mutation($discussionId:ID!,$body:String!){addDiscussionComment(input:{discussionId:$discussionId,body:$body}){comment{url}}}' \
-f discussionId="${DISC_ID}" \
-f body="${BODY}"
- name: Upload report artifact
uses: actions/upload-artifact@v4
with:
name: daily-issue-health-report-${{ github.run_id }}
path: |
artifacts/daily_issue_health_report.md
artifacts/daily_issue_health_facts.json
artifacts/daily_issue_health_agent.json
retention-days: 14
- name: Emit observability summary
if: always()
env:
WF_NAME: ${{ github.workflow }}
JOB_NAME: report
RUN_ID: ${{ github.run_id }}
REPO_NAME: ${{ github.repository }}
SHA: ${{ github.sha }}
OPS_OUTCOME: ${{ steps.ops_daily.outcome }}
PUBLISH_ENABLED: ${{ env.PUBLISH_COMMENT }}
run: |
set -euo pipefail
mkdir -p artifacts/observability
python - << 'PY'
import json
import os
from datetime import UTC, datetime
from pathlib import Path
facts_path = Path("artifacts/daily_issue_health_facts.json")
metrics = {}
if facts_path.exists():
try:
metrics = json.loads(facts_path.read_text(encoding="utf-8")).get("metrics", {})
except Exception:
metrics = {}
input_count = int(metrics.get("touched_issues", 0) or 0)
failed_count = int(metrics.get("workflow_failed", 0) or 0)
success_count = max(int(metrics.get("workflow_total", 0) or 0) - failed_count, 0)
skipped_count = 0
failures = []
if (os.getenv("OPS_OUTCOME") or "") == "failure":
failures.append({"code": "OPS_DAILY_FAILED", "count": 1, "samples": []})
if (os.getenv("PUBLISH_ENABLED") or "").lower() == "false":
failures.append({"code": "PUBLISH_SKIPPED_BY_CONFIG", "count": 1, "samples": []})
status = "success"
if failures:
status = "partial"
if failed_count > 0 and success_count == 0:
status = "failure"
payload = {
"schema_version": "v1",
"workflow": os.getenv("WF_NAME"),
"job": os.getenv("JOB_NAME"),
"run_id": os.getenv("RUN_ID"),
"repo": os.getenv("REPO_NAME"),
"sha": os.getenv("SHA"),
"finished_at": datetime.now(UTC).isoformat().replace("+00:00", "Z"),
"metrics": {
"input_count": input_count,
"success_count": success_count,
"failed_count": failed_count,
"skipped_count": skipped_count,
},
"failures_topn": failures[:5],
"status": status,
}
Path("artifacts/observability/daily_issue_health_report__report.json").write_text(
json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8"
)
summary = [
"## Observability (daily report)",
"",
"| metric | value |",
"|---|---:|",
f"| input_count | {input_count} |",
f"| success_count | {success_count} |",
f"| failed_count | {failed_count} |",
f"| skipped_count | {skipped_count} |",
f"| status | {status} |",
"",
"### Failure TopN",
]
if failures:
for item in failures:
summary.append(f"- `{item['code']}`: {item['count']}")
else:
summary.append("- none")
with open(os.environ["GITHUB_STEP_SUMMARY"], "a", encoding="utf-8") as f:
f.write("\n".join(summary) + "\n")
PY
- name: Upload observability artifact
if: always()
uses: actions/upload-artifact@v4
with:
name: daily-report-observability-${{ github.run_id }}
path: artifacts/observability/
retention-days: 14