diff --git a/CHANGELOG.md b/CHANGELOG.md index f254161..57368a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Groups PRs by repository with placeholder sections for human curation - New `comment-template` action output for downstream workflow steps - Labels from PRs are included to aid thematic categorization + - Auto-detects contributors from merged PRs (filters bots and Copilot) + - Uses markdown link format for clean GitHub rendering - See [Comment Summary Template docs](docs/comment-summary-template.md) for details +- **Release tracking in summary template**: Repos that publish releases now show them in the template + - Fetches releases published in the report date range via GitHub API + - Displays a single releases table at the top of the template (omitted if no releases) + - Table columns: Repository, Release (name/tag with link), Date + - Sorted by publication date (newest first) + - Works for both organization repos and external tracked repos + - Helps summarize important milestones alongside PR activity +- **Releases column in main report**: Include release activity directly in the primary report table + - Adds a **Releases** column to the main activity table for each repository + - Counts non-draft releases published in the report date range and includes them in the totals row + - Clickable link to repo releases page when count > 0 + - Keeps release metrics alongside issues, PRs, and commits for a unified overview ## [2.2.0] - 2025-10-23 diff --git a/docs/comment-summary-template.md b/docs/comment-summary-template.md index cc97f77..1bfe0e8 100644 --- a/docs/comment-summary-template.md +++ b/docs/comment-summary-template.md @@ -36,8 +36,9 @@ See [QuantEcon/meta#280](https://github.com/QuantEcon/meta/issues/280) for an ex The template is written to `comment-template.md` (default) and contains: 1. **Placeholder summary** — Editable topic bullets for high-level themes -2. **Merged PRs by repository** — Every merged PR with title, URL, labels, and author -3. **Contributor acknowledgement** — Template for thanking contributors +2. **Releases table** — All releases published in the period in a single table (omitted if none) +3. **Merged PRs by repository** — Every merged PR with title, URL, labels, and author +4. **Contributor acknowledgement** — Auto-generated from PR authors (bots and Copilot excluded) ### Example Output @@ -49,16 +50,24 @@ The template is written to `comment-template.md` (default) and contains: --- +## 📦 Releases + +| Repository | Release | Date | +|------------|---------|------| +| lecture-python.myst | [publish-2026feb19b](https://github.com/.../publish-2026feb19b) | Feb 19 | +| quantecon-book-theme | [v0.17.0](https://github.com/.../v0.17.0) | Feb 19 | +| QuantEcon.py | [v0.11.0](https://github.com/.../v0.11.0) | Feb 15 | + **lecture-python.myst:** - - Update consumer problem lecture https://github.com/QuantEcon/lecture-python.myst/pull/757 [maintenance] (@HumphreyYang) - - Fix typo in GDP lecture https://github.com/QuantEcon/lecture-python.myst/pull/756 (@contributor) + - [Update consumer problem lecture](https://github.com/QuantEcon/lecture-python.myst/pull/757) [maintenance] (@HumphreyYang) + - [Fix typo in GDP lecture](https://github.com/QuantEcon/lecture-python.myst/pull/756) (@contributor) **quantecon-book-theme:** - - Major refactor for responsiveness https://github.com/QuantEcon/quantecon-book-theme/pull/335 [infrastructure, priority: high] (@mmcky) + - [Major refactor for responsiveness](https://github.com/QuantEcon/quantecon-book-theme/pull/335) [infrastructure, priority: high] (@mmcky) --- -thanks @contributor1 and @contributor2 for all your contributions. +thanks @HumphreyYang, @mmcky, and @contributor for all your contributions. ``` ## How Labels Help diff --git a/generate-report.sh b/generate-report.sh index 8fe27d2..357a36d 100755 --- a/generate-report.sh +++ b/generate-report.sh @@ -366,6 +366,31 @@ process_external_repo() { local commits=0 commits=$(echo "$commits_response" | jq 'if type == "array" then length else 0 end' 2>/dev/null || echo 0) + # Count releases published in the date range + local releases_response + releases_response=$(api_call "/repos/${full_repo}/releases") + local releases=0 + releases=$(echo "$releases_response" | jq --arg since "$WEEK_AGO" --arg until "$NOW" 'if type == "array" then [.[] | select(.published_at != null and .published_at >= $since and .published_at <= $until and .draft == false)] | length else 0 end' 2>/dev/null || echo 0) + + # Collect release details for summary template + local local_ext_release_details="" + if [ "$SUMMARY_TEMPLATE" = "true" ] && [ "$releases" -gt 0 ]; then + local_ext_release_details=$(echo "$releases_response" | jq -c --arg since "$WEEK_AGO" --arg until "$NOW" --arg repo "$full_repo" --arg org "$repo_org" ' + if type == "array" then + [.[] | select(.published_at != null and .published_at >= $since and .published_at <= $until and .draft == false) | + { + repo: $repo, + org: $org, + tag: .tag_name, + name: (.name // .tag_name), + url: .html_url, + published_at: .published_at, + body: (.body // "" | split("\n")[0:3] | join(" ")) + }] | .[] + else empty end + ' 2>/dev/null) + fi + # Handle null/empty values current_issues=${current_issues:-0} opened_issues=${opened_issues:-0} @@ -373,14 +398,19 @@ process_external_repo() { merged_prs=${merged_prs:-0} opened_prs=${opened_prs:-0} commits=${commits:-0} + releases=${releases:-0} # Return values as JSON for easy parsing - # Include PR details as a nested array for summary template + # Include PR details and release details as nested arrays for summary template local pr_details_json="[]" if [ -n "$local_ext_pr_details" ]; then pr_details_json=$(echo "$local_ext_pr_details" | jq -s '.') fi - echo "{\"repo\":\"$full_repo\",\"current_issues\":$current_issues,\"opened_issues\":$opened_issues,\"closed_issues\":$closed_issues,\"opened_prs\":$opened_prs,\"merged_prs\":$merged_prs,\"commits\":$commits,\"pr_details\":$pr_details_json}" + local release_details_json="[]" + if [ -n "$local_ext_release_details" ]; then + release_details_json=$(echo "$local_ext_release_details" | jq -s '.') + fi + echo "{\"repo\":\"$full_repo\",\"current_issues\":$current_issues,\"opened_issues\":$opened_issues,\"closed_issues\":$closed_issues,\"opened_prs\":$opened_prs,\"merged_prs\":$merged_prs,\"releases\":$releases,\"commits\":$commits,\"pr_details\":$pr_details_json,\"release_details\":$release_details_json}" } # Get all repositories and filter by activity @@ -541,6 +571,7 @@ total_closed_issues=0 total_merged_prs=0 total_commits=0 total_opened_prs=0 +total_releases=0 failed_repos=0 rate_limited_repos=0 report_content="" @@ -570,14 +601,15 @@ if [ "$OUTPUT_FORMAT" = "markdown" ]; then ## Summary -| Repository | Current Issues | Opened Issues | Closed Issues | Opened PRs | Merged PRs | Commits | -|------------|----------------|---------------|---------------|------------|------------|---------|" +| Repository | Current Issues | Opened Issues | Closed Issues | Opened PRs | Merged PRs | Releases | Commits | +|------------|----------------|---------------|---------------|------------|------------|----------|---------|" echo "DEBUG: Initial report content set, length: ${#report_content}" fi # Initialize summary template data collection -# We collect merged PR details as newline-delimited JSON records +# We collect merged PR details and release info as newline-delimited JSON records summary_template_data="" +summary_release_data="" # Process each repository repo_count=0 @@ -693,6 +725,45 @@ ${local_pr_details}" fi fi + # Count releases published in the date range + releases_response=$(api_call "/repos/${ORGANIZATION}/${repo}/releases") + if [ $? -eq 0 ]; then + releases=$(echo "$releases_response" | jq --arg since "$WEEK_AGO" --arg until "$NOW" 'if type == "array" then [.[] | select(.published_at != null and .published_at >= $since and .published_at <= $until and .draft == false)] | length else 0 end') + + # Collect release details for summary template + if [ "$SUMMARY_TEMPLATE" = "true" ] && [ "$releases" -gt 0 ]; then + local_release_details=$(echo "$releases_response" | jq -c --arg since "$WEEK_AGO" --arg until "$NOW" --arg repo "$repo" --arg org "$ORGANIZATION" ' + if type == "array" then + [.[] | select(.published_at != null and .published_at >= $since and .published_at <= $until and .draft == false) | + { + repo: $repo, + org: $org, + tag: .tag_name, + name: (.name // .tag_name), + url: .html_url, + published_at: .published_at, + body: (.body // "" | split("\n")[0:3] | join(" ")) + }] | .[] + else empty end + ' 2>/dev/null) + if [ -n "$local_release_details" ]; then + if [ -n "$summary_release_data" ]; then + summary_release_data="${summary_release_data} +${local_release_details}" + else + summary_release_data="$local_release_details" + fi + fi + fi + else + releases=0 + if echo "$releases_response" | jq -e '.error' 2>/dev/null | grep -q "rate_limit"; then + rate_limited_repos=$((rate_limited_repos + 1)) + else + failed_repos=$((failed_repos + 1)) + fi + fi + # Handle null/empty values current_issues=${current_issues:-0} opened_issues=${opened_issues:-0} @@ -700,6 +771,7 @@ ${local_pr_details}" merged_prs=${merged_prs:-0} opened_prs=${opened_prs:-0} commits=${commits:-0} + releases=${releases:-0} # Add to totals total_current_issues=$((total_current_issues + current_issues)) @@ -708,10 +780,11 @@ ${local_pr_details}" total_merged_prs=$((total_merged_prs + merged_prs)) total_opened_prs=$((total_opened_prs + opened_prs)) total_commits=$((total_commits + commits)) + total_releases=$((total_releases + releases)) # Only include repos with actual activity (exclude repos with all zeros in activity columns) # Note: We check activity metrics only, not current_issues (which is current state, not activity) - if [ $((opened_issues + closed_issues + opened_prs + merged_prs + commits)) -gt 0 ]; then + if [ $((opened_issues + closed_issues + opened_prs + merged_prs + commits + releases)) -gt 0 ]; then repos_with_activity=$((repos_with_activity + 1)) if [ "$OUTPUT_FORMAT" = "markdown" ]; then # Create GitHub search URLs for clickable metrics @@ -721,6 +794,7 @@ ${local_pr_details}" closed_issues_url="https://github.com/${ORGANIZATION}/${repo}/issues?q=is:issue+closed:${start_display}..${end_display}" opened_prs_url="https://github.com/${ORGANIZATION}/${repo}/pulls?q=is:pr+created:${start_display}..${end_display}" merged_prs_url="https://github.com/${ORGANIZATION}/${repo}/pulls?q=is:pr+merged:${start_display}..${end_display}" + releases_url="https://github.com/${ORGANIZATION}/${repo}/releases" commits_url="https://github.com/${ORGANIZATION}/${repo}/commits?since=${start_display}&until=${end_display}" # Format metrics as clickable links if > 1 @@ -729,10 +803,11 @@ ${local_pr_details}" closed_issues_display=$(format_metric "$closed_issues" "$closed_issues_url") opened_prs_display=$(format_metric "$opened_prs" "$opened_prs_url") merged_prs_display=$(format_metric "$merged_prs" "$merged_prs_url") + releases_display=$(format_metric "$releases" "$releases_url") commits_display=$(format_metric "$commits" "$commits_url") report_content="${report_content} -| $repo | $current_issues_display | $opened_issues_display | $closed_issues_display | $opened_prs_display | $merged_prs_display | $commits_display |" +| $repo | $current_issues_display | $opened_issues_display | $closed_issues_display | $opened_prs_display | $merged_prs_display | $releases_display | $commits_display |" fi else echo "DEBUG: Skipping $repo from report (no activity: all metrics are zero)" @@ -748,7 +823,7 @@ echo "DEBUG: Final report content length: ${#report_content}" # Add summary to report if [ "$OUTPUT_FORMAT" = "markdown" ]; then report_content="${report_content} -|**Total**|**$total_current_issues**|**$total_opened_issues**|**$total_closed_issues**|**$total_opened_prs**|**$total_merged_prs**|**$total_commits**| +|**Total**|**$total_current_issues**|**$total_opened_issues**|**$total_closed_issues**|**$total_opened_prs**|**$total_merged_prs**|**$total_releases**|**$total_commits**| ## Details @@ -758,6 +833,7 @@ if [ "$OUTPUT_FORMAT" = "markdown" ]; then - **Total Issues Closed:** $total_closed_issues - **Total PRs Opened:** $total_opened_prs - **Total PRs Merged:** $total_merged_prs +- **Total Releases:** $total_releases - **Total Commits:** $total_commits" # Add warnings about incomplete data if any API calls failed @@ -791,6 +867,7 @@ if [ "$OUTPUT_FORMAT" = "markdown" ]; then ext_total_merged_prs=0 ext_total_commits=0 ext_total_opened_prs=0 + ext_total_releases=0 ext_repos_with_activity=0 ext_report_content="" @@ -809,6 +886,7 @@ if [ "$OUTPUT_FORMAT" = "markdown" ]; then closed_issues=$(echo "$repo_result" | jq -r '.closed_issues') opened_prs=$(echo "$repo_result" | jq -r '.opened_prs') merged_prs=$(echo "$repo_result" | jq -r '.merged_prs') + releases=$(echo "$repo_result" | jq -r '.releases') commits=$(echo "$repo_result" | jq -r '.commits') # Extract PR details for summary template @@ -822,6 +900,17 @@ ${ext_pr_details}" summary_template_data="$ext_pr_details" fi fi + + # Extract release details for summary template + ext_release_details=$(echo "$repo_result" | jq -c '.release_details[]?' 2>/dev/null) + if [ -n "$ext_release_details" ]; then + if [ -n "$summary_release_data" ]; then + summary_release_data="${summary_release_data} +${ext_release_details}" + else + summary_release_data="$ext_release_details" + fi + fi fi # Add to totals @@ -831,9 +920,10 @@ ${ext_pr_details}" ext_total_merged_prs=$((ext_total_merged_prs + merged_prs)) ext_total_opened_prs=$((ext_total_opened_prs + opened_prs)) ext_total_commits=$((ext_total_commits + commits)) + ext_total_releases=$((ext_total_releases + releases)) # Only include repos with activity - if [ $((opened_issues + closed_issues + opened_prs + merged_prs + commits)) -gt 0 ]; then + if [ $((opened_issues + closed_issues + opened_prs + merged_prs + commits + releases)) -gt 0 ]; then ext_repos_with_activity=$((ext_repos_with_activity + 1)) # Create GitHub search URLs @@ -842,6 +932,7 @@ ${ext_pr_details}" closed_issues_url="https://github.com/${full_repo}/issues?q=is:issue+closed:${start_display}..${end_display}" opened_prs_url="https://github.com/${full_repo}/pulls?q=is:pr+created:${start_display}..${end_display}" merged_prs_url="https://github.com/${full_repo}/pulls?q=is:pr+merged:${start_display}..${end_display}" + releases_url="https://github.com/${full_repo}/releases" commits_url="https://github.com/${full_repo}/commits?since=${start_display}&until=${end_display}" # Format metrics as clickable links if > 0 @@ -850,10 +941,11 @@ ${ext_pr_details}" closed_issues_display=$(format_metric "$closed_issues" "$closed_issues_url") opened_prs_display=$(format_metric "$opened_prs" "$opened_prs_url") merged_prs_display=$(format_metric "$merged_prs" "$merged_prs_url") + releases_display=$(format_metric "$releases" "$releases_url") commits_display=$(format_metric "$commits" "$commits_url") ext_report_content="${ext_report_content} -| $full_repo | $current_issues_display | $opened_issues_display | $closed_issues_display | $opened_prs_display | $merged_prs_display | $commits_display |" +| $full_repo | $current_issues_display | $opened_issues_display | $closed_issues_display | $opened_prs_display | $merged_prs_display | $releases_display | $commits_display |" else echo "DEBUG: Skipping $full_repo from report (no activity: all metrics are zero)" fi @@ -865,9 +957,9 @@ ${ext_pr_details}" ## External Repositories -| Repository | Current Issues | Opened Issues | Closed Issues | Opened PRs | Merged PRs | Commits | -|------------|----------------|---------------|---------------|------------|------------|---------|${ext_report_content} -|**Total**|**$ext_total_current_issues**|**$ext_total_opened_issues**|**$ext_total_closed_issues**|**$ext_total_opened_prs**|**$ext_total_merged_prs**|**$ext_total_commits**|" +| Repository | Current Issues | Opened Issues | Closed Issues | Opened PRs | Merged PRs | Releases | Commits | +|------------|----------------|---------------|---------------|------------|------------|----------|---------|${ext_report_content} +|**Total**|**$ext_total_current_issues**|**$ext_total_opened_issues**|**$ext_total_closed_issues**|**$ext_total_opened_prs**|**$ext_total_merged_prs**|**$ext_total_releases**|**$ext_total_commits**|" echo "DEBUG: External repositories with activity: $ext_repos_with_activity" echo "DEBUG: External repos totals - Issues: $ext_total_opened_issues opened, $ext_total_closed_issues closed | PRs: $ext_total_opened_prs opened, $ext_total_merged_prs merged | Commits: $ext_total_commits" @@ -882,7 +974,7 @@ ${ext_pr_details}" fi # Create summary -summary="Summary: $total_current_issues current open issues, $total_opened_issues issues opened, $total_closed_issues issues closed, $total_opened_prs PRs opened, $total_merged_prs PRs merged, $total_commits commits" +summary="Summary: $total_current_issues current open issues, $total_opened_issues issues opened, $total_closed_issues issues closed, $total_opened_prs PRs opened, $total_merged_prs PRs merged, $total_releases releases, $total_commits commits" # Generate comment summary template if enabled if [ "$SUMMARY_TEMPLATE" = "true" ]; then @@ -902,9 +994,41 @@ if [ "$SUMMARY_TEMPLATE" = "true" ]; then ---" - # Group PRs by repository and generate sections + # --- Releases table (Option A: single table at top, omitted if no releases) --- + if [ -n "$summary_release_data" ]; then + template_content="${template_content} + +## 📦 Releases + +| Repository | Release | Date | +|------------|---------|------|" + + # Sort all releases by published_at descending + sorted_releases=$(echo "$summary_release_data" | jq -s 'sort_by(.published_at) | reverse | .[]' -c 2>/dev/null) + + while IFS= read -r release_json; do + [ -z "$release_json" ] && continue + release_repo=$(echo "$release_json" | jq -r '.repo') + release_name=$(echo "$release_json" | jq -r '.name') + release_tag=$(echo "$release_json" | jq -r '.tag') + release_url=$(echo "$release_json" | jq -r '.url') + release_date=$(echo "$release_json" | jq -r '.published_at' | cut -d'T' -f1) + # Format the date as "Feb 21" style (GNU date -d first, then BSD date -j -f, then fallback) + release_date_display=$(date -d "$release_date" "+%b %d" 2>/dev/null || date -j -f "%Y-%m-%d" "$release_date" "+%b %d" 2>/dev/null || echo "$release_date") + # Use name if different from tag, otherwise just show tag + if [ "$release_name" != "$release_tag" ] && [ -n "$release_name" ]; then + release_label="${release_name} (${release_tag})" + else + release_label="${release_tag}" + fi + template_content="${template_content} +| ${release_repo} | [${release_label}](${release_url}) | ${release_date_display} |" + done <<< "$sorted_releases" + fi + + # --- PR listings per repository --- if [ -n "$summary_template_data" ]; then - # Get unique repos from the collected data + # Get unique repos from the collected PR data repo_list=$(echo "$summary_template_data" | jq -r '.repo' | sort -u) while IFS= read -r template_repo; do @@ -915,7 +1039,7 @@ if [ "$SUMMARY_TEMPLATE" = "true" ]; then **${template_repo}:**" # Get PRs for this repo, sorted by merged_at - repo_prs=$(echo "$summary_template_data" | jq -c --arg repo "$template_repo" 'select(.repo == $repo)' | jq -s 'sort_by(.merged_at) | reverse | .[]' -c) + repo_prs=$(echo "$summary_template_data" | jq -c --arg repo "$template_repo" 'select(.repo == $repo)' | jq -s 'sort_by(.merged_at) | reverse | .[]' -c 2>/dev/null) while IFS= read -r pr_json; do [ -z "$pr_json" ] && continue @@ -929,10 +1053,11 @@ if [ "$SUMMARY_TEMPLATE" = "true" ]; then done <<< "$repo_prs" done <<< "$repo_list" - else + elif [ -z "$summary_release_data" ]; then + # No PRs and no releases template_content="${template_content} -_No merged PRs found in the report period._" +_No merged PRs or releases found in the report period._" fi # Build contributors line from actual PR authors