ci(flink-smoke): bound the image build with a timeout and one retry #400
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: DORA Metrics | |
| on: | |
| schedule: | |
| - cron: "0 6 * * 1" | |
| workflow_dispatch: | |
| pull_request: | |
| branches: [main] | |
| permissions: | |
| actions: read | |
| contents: read | |
| issues: write | |
| pull-requests: write | |
| jobs: | |
| dora-report: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| with: | |
| fetch-depth: 0 | |
| - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 | |
| with: | |
| python-version: "3.11" | |
| - name: Ensure local main ref | |
| # pull_request runs on a detached merge commit with no local 'main', | |
| # which made 'git log main' in dora_metrics.py exit 128. Create the | |
| # local ref from origin/main (fetched by checkout fetch-depth: 0) so | |
| # the script's --branch main default keeps working — and so the | |
| # GitHub Actions API / .dora/ deployment-log branch filters in | |
| # _load_github_runs() and _load_deployment_log() get the plain | |
| # branch name 'main' they expect, not a remote ref. | |
| # On push-to-main, 'main' is already the checked-out branch and | |
| # update-ref refuses to touch it — that's fine, the ref exists. | |
| # On pull_request, HEAD is detached and update-ref creates main. | |
| run: git update-ref refs/heads/main "$(git rev-parse origin/main)" || true | |
| - name: Generate DORA report | |
| env: | |
| GITHUB_API_URL: ${{ github.api_url }} | |
| GITHUB_REPOSITORY: ${{ github.repository }} | |
| GITHUB_TOKEN: ${{ github.token }} | |
| run: python scripts/dora_metrics.py --days 30 --output dora-report.json | |
| - name: Render markdown summary | |
| run: | | |
| python - <<'PY' | |
| import json | |
| from pathlib import Path | |
| report = json.loads(Path("dora-report.json").read_text(encoding="utf-8")) | |
| metrics = report["metrics"] | |
| deployment = metrics["deployment_frequency"] | |
| lead_time = metrics["lead_time_for_changes"] | |
| failure_rate = metrics["change_failure_rate"] | |
| mttr = metrics["mttr"] | |
| def format_value(value, suffix=""): | |
| return "n/a" if value is None else f"{value}{suffix}" | |
| lines = [ | |
| "## DORA Metrics", | |
| "", | |
| f"- Window: last {report['window_days']} days", | |
| f"- Branch: `{report['branch']}`", | |
| f"- Deployment frequency: {deployment['deployments']} total / {format_value(deployment['per_week'], ' per week')}", | |
| f"- Lead time for changes: avg {format_value(lead_time['average_hours'], 'h')} / median {format_value(lead_time['median_hours'], 'h')}", | |
| f"- Change failure rate: {format_value(failure_rate['percentage'], '%')} ({failure_rate['failed_deployments']}/{failure_rate['deployments']})", | |
| f"- MTTR: {format_value(mttr['average_hours'], 'h')} across {mttr['incidents']} incident(s)", | |
| ] | |
| if mttr.get("note"): | |
| lines.extend(["", f"MTTR note: {mttr['note']}"]) | |
| if report.get("notes"): | |
| lines.extend(["", "Notes:"]) | |
| lines.extend([f"- {note}" for note in report["notes"]]) | |
| summary = "\n".join(lines) + "\n" | |
| Path("dora-summary.md").write_text(summary, encoding="utf-8") | |
| Path("dora-comment.md").write_text( | |
| "<!-- dora-report -->\n" + summary, | |
| encoding="utf-8", | |
| ) | |
| PY | |
| cat dora-summary.md >> "$GITHUB_STEP_SUMMARY" | |
| - name: Upload DORA artifact | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: dora-report | |
| path: | | |
| dora-report.json | |
| dora-summary.md | |
| - name: Comment on pull request | |
| if: github.event_name == 'pull_request' | |
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | |
| with: | |
| script: | | |
| const fs = require("fs"); | |
| const body = fs.readFileSync("dora-comment.md", "utf8"); | |
| const marker = "<!-- dora-report -->"; | |
| const { owner, repo } = context.repo; | |
| const issue_number = context.issue.number; | |
| const comments = await github.paginate(github.rest.issues.listComments, { | |
| owner, | |
| repo, | |
| issue_number, | |
| per_page: 100, | |
| }); | |
| const existing = comments.find((comment) => | |
| comment.user.type === "Bot" && comment.body.includes(marker) | |
| ); | |
| if (existing) { | |
| await github.rest.issues.updateComment({ | |
| owner, | |
| repo, | |
| comment_id: existing.id, | |
| body, | |
| }); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| owner, | |
| repo, | |
| issue_number, | |
| body, | |
| }); | |
| } |