Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .github/scripts/pull-request-dashboard/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -1073,6 +1073,8 @@ def update_dashboard(args: argparse.Namespace) -> int:
md = render_pr_tables(
prs,
calculation.results,
max_rows_per_section=args.max_rows_per_section or None,
skip_drafts=args.skip_drafts,
)
output_path = dashboard_markdown_path()
output_path.parent.mkdir(parents=True, exist_ok=True)
Expand Down Expand Up @@ -1121,9 +1123,22 @@ def main() -> int:
help="minimum non-bot approvals needed before a PR can route to maintainers",
)
parser.add_argument("--model", default=DEFAULT_MODEL, help=f"copilot model (default: {DEFAULT_MODEL})")
parser.add_argument(
"--max-rows-per-section",
type=int,
default=0,
help="cap rows per section in the rendered dashboard (0 = no limit)",
)
parser.add_argument(
"--skip-drafts",
action="store_true",
help="omit the Draft pull requests section from the rendered dashboard",
)
args = parser.parse_args()
if args.required_approvals < 1:
parser.error("--required-approvals must be at least 1")
if args.max_rows_per_section < 0:
parser.error("--max-rows-per-section must be zero or positive")
with state_branch.temporary_state_dir() as state_dir:
repo_key = repo_state_key(args.repo) if args.repo else repo_state_key(detect_repo())
set_state_dir(state_dir / repo_key)
Expand Down
34 changes: 31 additions & 3 deletions .github/scripts/pull-request-dashboard/render.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,26 @@ def _md_escape(s: str) -> str:
)


def render_draft_pr_section(prs: list[dict[str, Any]]) -> list[str]:
def _limit_rows(rows: list[Any], max_rows: int | None) -> tuple[list[Any], int]:
if max_rows is None or max_rows <= 0 or len(rows) <= max_rows:
return rows, 0
return rows[:max_rows], len(rows) - max_rows


def _truncation_note(count: int) -> str:
plural = "PR" if count == 1 else "PRs"
return f"_More {count} {plural} not shown_"


def render_draft_pr_section(
prs: list[dict[str, Any]],
max_rows_per_section: int | None = None,
) -> list[str]:
drafts = [p for p in prs if p.get("isDraft")]
if not drafts:
return []
drafts.sort(key=lambda p: p.get("updatedAt") or "")
drafts, truncated = _limit_rows(drafts, max_rows_per_section)
lines = ["## Draft pull requests", ""]
lines.append("| PR | Author | Updated |")
lines.append("|---|---|:---:|")
Expand All @@ -49,6 +64,9 @@ def render_draft_pr_section(prs: list[dict[str, Any]]) -> list[str]:
updated = activity_age(parse_ts(pr.get("updatedAt") or ""))
lines.append(f"| [{title} (#{number})]({url}) | {author} | {updated} |")
lines.append("")
if truncated:
lines.append(_truncation_note(truncated))
lines.append("")
return lines


Expand Down Expand Up @@ -159,7 +177,12 @@ def render_diagnostics_section(results: dict[int, dict[str, Any]]) -> list[str]:
]


def render_pr_tables(prs: list[dict[str, Any]], results: dict[int, dict[str, Any]]) -> str:
def render_pr_tables(
prs: list[dict[str, Any]],
results: dict[int, dict[str, Any]],
max_rows_per_section: int | None = None,
skip_drafts: bool = False,
) -> str:
source_url = "https://github.com/open-telemetry/shared-workflows/blob/main/.github/scripts/pull-request-dashboard/dashboard.py"
refresh_url = "https://github.com/open-telemetry/shared-workflows/actions/workflows/pull-request-dashboard.yml"
grouping_note = (
Expand Down Expand Up @@ -200,6 +223,7 @@ def row_sort_key(pr: dict[str, Any]) -> tuple[int, int]:
if not rows:
continue
rows.sort(key=row_sort_key, reverse=True)
rows, truncated = _limit_rows(rows, max_rows_per_section)
out.append(f"## {ROUTE_LABELS.get(route, route)}")
out.append("")
out.append("| PR | Author | Reviewers | CI | Conflicts | Age |")
Expand All @@ -219,8 +243,12 @@ def row_sort_key(pr: dict[str, Any]) -> tuple[int, int]:
f"{conflicts_cell(facts)} | {activity_cell} |"
)
out.append("")
if truncated:
out.append(_truncation_note(truncated))
out.append("")

out.extend(render_draft_pr_section(prs))
if not skip_drafts:
out.extend(render_draft_pr_section(prs, max_rows_per_section))
out.extend(render_diagnostics_section(results))
out.append(f"_Approvers may [force a refresh]({refresh_url})._")
out.append("")
Expand Down
4 changes: 3 additions & 1 deletion .github/scripts/pull-request-dashboard/repositories.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
"name": "opentelemetry-collector-contrib",
"approver_teams": ["collector-contrib-approvers"],
"slack_channel": "",
"slack_user_mapping": {}
"slack_user_mapping": {},
"max_rows_per_section": 50,
"skip_drafts": true
},
{
"name": "opentelemetry-java",
Expand Down
16 changes: 16 additions & 0 deletions .github/workflows/pull-request-dashboard-repo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ on:
required: false
default: "{}"
type: string
max_rows_per_section:
required: false
default: 0
type: number
skip_drafts:
required: false
default: false
type: boolean
secrets:
PR_DASHBOARD_PRIVATE_KEY:
required: true
Expand Down Expand Up @@ -189,6 +197,8 @@ jobs:
REPO_NAME: ${{ inputs.repository }}
REQUIRED_APPROVALS: ${{ inputs.required_approvals }}
APPROVER_TEAMS_JSON: ${{ inputs.approver_teams_json }}
MAX_ROWS_PER_SECTION: ${{ inputs.max_rows_per_section }}
SKIP_DRAFTS: ${{ inputs.skip_drafts }}
run: |
set -euo pipefail
dashboard_args=(--state-branch "$DASHBOARD_STATE_BRANCH" --repo "$REPO_NAME")
Expand All @@ -199,6 +209,12 @@ jobs:
if [[ -n "${TRIGGER_PR_NUMBER:-}" ]]; then
dashboard_args+=(--pr-number "$TRIGGER_PR_NUMBER")
fi
if [[ "${MAX_ROWS_PER_SECTION:-0}" -gt 0 ]]; then
dashboard_args+=(--max-rows-per-section "$MAX_ROWS_PER_SECTION")
fi
if [[ "${SKIP_DRAFTS:-false}" == "true" ]]; then
dashboard_args+=(--skip-drafts)
fi
python3 .github/scripts/pull-request-dashboard/dashboard.py "${dashboard_args[@]}"

notify-slack:
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/pull-request-dashboard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ jobs:
approver_teams_json: ${{ toJSON(matrix.approver_teams || fromJSON('[]')) }}
slack_channel: ${{ matrix.slack_channel }}
slack_user_mapping_json: ${{ toJSON(matrix.slack_user_mapping || fromJSON('{}')) }}
max_rows_per_section: ${{ matrix.max_rows_per_section || 0 }}
skip_drafts: ${{ matrix.skip_drafts || false }}
secrets:
PR_DASHBOARD_PRIVATE_KEY: ${{ secrets.PR_DASHBOARD_PRIVATE_KEY }}
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
Expand Down
2 changes: 2 additions & 0 deletions pull-request-dashboard/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ Fields:
| `required_approvals` | yes | Number of approvals required for an open PR to be marked ready to merge. |
| `slack_channel` | no | Slack channel for notifications. Omit to skip Slack processing for this repository. |
| `slack_user_mapping` | no | Map of GitHub login to Slack user ID for at-mentions. |
| `max_rows_per_section` | no | Cap on rows rendered per group section (and for drafts) in the dashboard issue body. Rows past the cap are dropped and replaced with a `_More X PRs not shown_` note. Omit for no cap. Needed for very large repos where the full dashboard exceeds GitHub's 65,536-character issue-body limit. |
| `skip_drafts` | no | If `true`, omit the *Draft pull requests* section from the dashboard body entirely. Defaults to `false` (drafts are shown). Useful for very large repos where drafts add significant size without triage value. |

Ask a maintainer or admin to add the repository under [Repository access](https://github.com/organizations/open-telemetry/settings/installations/133550497).

Expand Down