From 16364fe2fa4f7e5bd3da0d4eca7610981152837a Mon Sep 17 00:00:00 2001 From: Scot Breitenfeld Date: Thu, 22 Jan 2026 14:37:45 -0600 Subject: [PATCH] Badges (#6170) * Fix Release Progress badges and workflow - Fix update-progress.py to output blocker/mustdo counts in correct format The workflow expects blocker_done=, blocker_total=, mustdo_done=, mustdo_total= output lines but the script was only outputting human-readable format - Update README badge links to point to project view 24 instead of base project This fixes the workflow failures where BLOCKER_DONE and the related environment variables were not being set, causing badge updates to fail. The badges were pointing to old unmaintained gists under user X. Updated to use the gist automatically maintained by the Release Progress workflow (gist ID: 0ad2eabb63b28eb90d69f5e5b2c1496f). The workflow now successfully updates these badges every 4 hours with current release blocker and must-do progress. The script now auto-detects the HDF5 version from src/H5public.h and filters release blockers/must-do items by milestone matching that version. Changes: - Added get_hdf5_version_from_header() to read version from H5public.h - Updated GraphQL query to fetch milestone information from issues - Added milestone filtering logic to only count items for the target release - Made validation more lenient when using milestone filter (allows 0/0) - Added MILESTONE_FILTER environment variable for manual override For develop branch with version 2.1.0 in H5public.h, this will now only count items with milestone containing "2.1" (e.g., "2.1.0", "HDF5 2.1"). * Add version number to badge labels The badges now display the version (e.g., "2.1 Release Blockers" instead of just "Release Blockers") when filtering by milestone. Changes: - Python script outputs version to GitHub Actions - Workflow passes version to badge generation script - Badge script includes version in label if available - Labels show "X.Y Release Blockers" / "X.Y Release Must Do" The three badges now track: 1. Release Blockers - Critical issues that must be resolved 2. Release Must Do - Important items for the release 3. Release Nice to Have - Optional improvements for the release All three badges show version prefix (e.g., "2.1") and support 0/0 display when no items exist for a milestone. --------- Co-authored-by: Claude Sonnet 4.5 --- .github/workflows/update-badge.sh | 98 +++++++++++++++++--- .github/workflows/update-progress.py | 126 ++++++++++++++++++++++---- .github/workflows/update-progress.yml | 13 ++- README.md | 8 +- 4 files changed, 210 insertions(+), 35 deletions(-) diff --git a/.github/workflows/update-badge.sh b/.github/workflows/update-badge.sh index 72882213453..28f36bababb 100755 --- a/.github/workflows/update-badge.sh +++ b/.github/workflows/update-badge.sh @@ -15,6 +15,9 @@ # BLOCKER_TOTAL - Total number of blockers # MUSTDO_DONE - Number of completed must-dos # MUSTDO_TOTAL - Total number of must-dos +# NICETOHAVE_DONE - Number of completed nice-to-haves +# NICETOHAVE_TOTAL - Total number of nice-to-haves +# VERSION - Version string (e.g., "2.1") - optional # set -euo pipefail @@ -83,32 +86,80 @@ create_badge_json() { local percentage="$4" local color="$5" + # Handle 0/0 case (when percentage is -1 or total is 0) + local message + if [ "$total" -eq 0 ] || [ "$percentage" = "-1.0" ]; then + message="0/0" + else + message="$done/$total ($percentage%)" + fi + jq -n \ --arg label "$label" \ - --arg percentage "$percentage" \ - --arg done "$done" \ - --arg total "$total" \ + --arg message "$message" \ --arg color "$color" \ '{ "schemaVersion": 1, "label": $label, - "message": "\($done)/\($total) (\($percentage)%)", + "message": $message, "color": $color, "style": "flat-square" }' } # Calculate percentages for each category -BLOCKER_PERCENTAGE=$(awk "BEGIN {printf \"%.1f\", ($BLOCKER_DONE / $BLOCKER_TOTAL * 100)}" 2>/dev/null || echo "0") -MUSTDO_PERCENTAGE=$(awk "BEGIN {printf \"%.1f\", ($MUSTDO_DONE / $MUSTDO_TOTAL * 100)}" 2>/dev/null || echo "0") +if [ "$BLOCKER_TOTAL" -eq 0 ]; then + BLOCKER_PERCENTAGE="-1.0" +else + BLOCKER_PERCENTAGE=$(awk "BEGIN {printf \"%.1f\", ($BLOCKER_DONE / $BLOCKER_TOTAL * 100)}") +fi -# Determine colors using the shared function -BLOCKER_COLOR=$(get_badge_color "$BLOCKER_PERCENTAGE") -MUSTDO_COLOR=$(get_badge_color "$MUSTDO_PERCENTAGE") +if [ "$MUSTDO_TOTAL" -eq 0 ]; then + MUSTDO_PERCENTAGE="-1.0" +else + MUSTDO_PERCENTAGE=$(awk "BEGIN {printf \"%.1f\", ($MUSTDO_DONE / $MUSTDO_TOTAL * 100)}") +fi + +if [ "$NICETOHAVE_TOTAL" -eq 0 ]; then + NICETOHAVE_PERCENTAGE="-1.0" +else + NICETOHAVE_PERCENTAGE=$(awk "BEGIN {printf \"%.1f\", ($NICETOHAVE_DONE / $NICETOHAVE_TOTAL * 100)}") +fi + +# Determine colors using the shared function (use lightgrey for 0/0) +if [ "$BLOCKER_PERCENTAGE" = "-1.0" ]; then + BLOCKER_COLOR="lightgrey" +else + BLOCKER_COLOR=$(get_badge_color "$BLOCKER_PERCENTAGE") +fi + +if [ "$MUSTDO_PERCENTAGE" = "-1.0" ]; then + MUSTDO_COLOR="lightgrey" +else + MUSTDO_COLOR=$(get_badge_color "$MUSTDO_PERCENTAGE") +fi + +if [ "$NICETOHAVE_PERCENTAGE" = "-1.0" ]; then + NICETOHAVE_COLOR="lightgrey" +else + NICETOHAVE_COLOR=$(get_badge_color "$NICETOHAVE_PERCENTAGE") +fi + +# Determine badge labels - include version if available +if [ -n "${VERSION:-}" ] && [ "$VERSION" != "all" ]; then + BLOCKER_LABEL="${VERSION} Release Blockers" + MUSTDO_LABEL="${VERSION} Release Must Do" + NICETOHAVE_LABEL="${VERSION} Release Nice to Have" +else + BLOCKER_LABEL="Release Blockers" + MUSTDO_LABEL="Release Must Do" + NICETOHAVE_LABEL="Release Nice to Have" +fi # Create badge JSONs using the shared function -BLOCKER_BADGE_JSON=$(create_badge_json "Release Blockers" "$BLOCKER_DONE" "$BLOCKER_TOTAL" "$BLOCKER_PERCENTAGE" "$BLOCKER_COLOR") -MUSTDO_BADGE_JSON=$(create_badge_json "Release Must Do" "$MUSTDO_DONE" "$MUSTDO_TOTAL" "$MUSTDO_PERCENTAGE" "$MUSTDO_COLOR") +BLOCKER_BADGE_JSON=$(create_badge_json "$BLOCKER_LABEL" "$BLOCKER_DONE" "$BLOCKER_TOTAL" "$BLOCKER_PERCENTAGE" "$BLOCKER_COLOR") +MUSTDO_BADGE_JSON=$(create_badge_json "$MUSTDO_LABEL" "$MUSTDO_DONE" "$MUSTDO_TOTAL" "$MUSTDO_PERCENTAGE" "$MUSTDO_COLOR") +NICETOHAVE_BADGE_JSON=$(create_badge_json "$NICETOHAVE_LABEL" "$NICETOHAVE_DONE" "$NICETOHAVE_TOTAL" "$NICETOHAVE_PERCENTAGE" "$NICETOHAVE_COLOR") # Validate JSONs were created successfully if [ -z "$BLOCKER_BADGE_JSON" ] || ! echo "$BLOCKER_BADGE_JSON" | jq empty 2>/dev/null; then @@ -119,18 +170,25 @@ if [ -z "$MUSTDO_BADGE_JSON" ] || ! echo "$MUSTDO_BADGE_JSON" | jq empty 2>/dev/ echo "::error::Failed to generate valid must-do badge JSON" exit 1 fi +if [ -z "$NICETOHAVE_BADGE_JSON" ] || ! echo "$NICETOHAVE_BADGE_JSON" | jq empty 2>/dev/null; then + echo "::error::Failed to generate valid nice-to-have badge JSON" + exit 1 +fi # The filenames in the Gist BLOCKER_GIST_NAME="release-blocker-${GITHUB_REPOSITORY##*/}.json" MUSTDO_GIST_NAME="release-mustdo-${GITHUB_REPOSITORY##*/}.json" -echo "::notice::Updating Gist files: $BLOCKER_GIST_NAME, $MUSTDO_GIST_NAME" +NICETOHAVE_GIST_NAME="release-nicetohave-${GITHUB_REPOSITORY##*/}.json" +echo "::notice::Updating Gist files: $BLOCKER_GIST_NAME, $MUSTDO_GIST_NAME, $NICETOHAVE_GIST_NAME" -# Create the request payload with both files +# Create the request payload with all three files REQUEST_PAYLOAD=$(jq -n \ --arg blocker_filename "$BLOCKER_GIST_NAME" \ --arg mustdo_filename "$MUSTDO_GIST_NAME" \ + --arg nicetohave_filename "$NICETOHAVE_GIST_NAME" \ --argjson blocker_content "$BLOCKER_BADGE_JSON" \ --argjson mustdo_content "$MUSTDO_BADGE_JSON" \ + --argjson nicetohave_content "$NICETOHAVE_BADGE_JSON" \ '{ "files": { ($blocker_filename): { @@ -138,6 +196,9 @@ REQUEST_PAYLOAD=$(jq -n \ }, ($mustdo_filename): { "content": ($mustdo_content | tostring) + }, + ($nicetohave_filename): { + "content": ($nicetohave_content | tostring) } } }') @@ -166,15 +227,18 @@ echo "::notice::Gist updated successfully" # Generate badge URLs for use in README BLOCKER_BADGE_URL="https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/${GITHUB_REPOSITORY_OWNER}-Bot/${GIST_ID}/raw/${BLOCKER_GIST_NAME}" MUSTDO_BADGE_URL="https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/${GITHUB_REPOSITORY_OWNER}-Bot/${GIST_ID}/raw/${MUSTDO_GIST_NAME}" +NICETOHAVE_BADGE_URL="https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/${GITHUB_REPOSITORY_OWNER}-Bot/${GIST_ID}/raw/${NICETOHAVE_GIST_NAME}" PROJECT_URL="https://github.com/${GITHUB_REPOSITORY}/projects/39" echo "::notice::Blocker Badge URL: $BLOCKER_BADGE_URL" echo "::notice::Must-Do Badge URL: $MUSTDO_BADGE_URL" +echo "::notice::Nice-to-Have Badge URL: $NICETOHAVE_BADGE_URL" # Output to GitHub Actions if GITHUB_OUTPUT is set if [ -n "${GITHUB_OUTPUT:-}" ]; then echo "blocker_badge_url=$BLOCKER_BADGE_URL" >> "$GITHUB_OUTPUT" echo "mustdo_badge_url=$MUSTDO_BADGE_URL" >> "$GITHUB_OUTPUT" + echo "nicetohave_badge_url=$NICETOHAVE_BADGE_URL" >> "$GITHUB_OUTPUT" echo "project_url=$PROJECT_URL" >> "$GITHUB_OUTPUT" fi @@ -194,11 +258,16 @@ if [ -n "${GITHUB_STEP_SUMMARY:-}" ]; then **Progress:** ${MUSTDO_DONE} of ${MUSTDO_TOTAL} completed (${MUSTDO_PERCENTAGE}%) **Badge Color:** ${MUSTDO_COLOR} +### 💡 Release Nice to Have +**Progress:** ${NICETOHAVE_DONE} of ${NICETOHAVE_TOTAL} completed (${NICETOHAVE_PERCENTAGE}%) +**Badge Color:** ${NICETOHAVE_COLOR} + **Gist ID:** ${GIST_ID} ### Badge URLs **Blocker Markdown:** \`[![Release Blocker Progress](${BLOCKER_BADGE_URL})](${PROJECT_URL})\` **Must-Do Markdown:** \`[![Release Must Do Progress](${MUSTDO_BADGE_URL})](${PROJECT_URL})\` +**Nice-to-Have Markdown:** \`[![Release Nice to Have Progress](${NICETOHAVE_BADGE_URL})](${PROJECT_URL})\` ### Badge JSON Preview \`\`\`json @@ -207,6 +276,9 @@ ${BLOCKER_BADGE_JSON} // Must-Do Badge ${MUSTDO_BADGE_JSON} + +// Nice-to-Have Badge +${NICETOHAVE_BADGE_JSON} \`\`\` EOF fi diff --git a/.github/workflows/update-progress.py b/.github/workflows/update-progress.py index b690deac1b0..cd3cbd7c95c 100644 --- a/.github/workflows/update-progress.py +++ b/.github/workflows/update-progress.py @@ -28,15 +28,20 @@ FIELD_STATUS = "Status" # Expected values for Release gating field VALUE_RELEASE_BLOCKER = "Release_Blocker" VALUE_RELEASE_MUST_DO = "Release_Must Do" +VALUE_RELEASE_NICE_TO_HAVE = "Release_Nice to Have" # Expected value for Status field when an item is completed VALUE_STATUS_DONE = "Done" +# Milestone filtering +# Set to None to include all milestones, or specify a version like "2.1" to filter +DEFAULT_MILESTONE_FILTER = None # Will be set from environment or H5public.h + class GitHubProjectTracker: """Tracks release blocker progress in GitHub projects.""" - def __init__(self, token: str, owner: str, project_number: int): + def __init__(self, token: str, owner: str, project_number: int, milestone_filter: Optional[str] = None): self.api_url = "https://api.github.com/graphql" self.headers = { "Authorization": f"bearer {token}", @@ -44,6 +49,7 @@ class GitHubProjectTracker: } self.owner = owner self.project_number = project_number + self.milestone_filter = milestone_filter def _get_query(self) -> str: """Returns the GraphQL query for fetching project items.""" @@ -75,7 +81,12 @@ class GitHubProjectTracker: } } } - content { ... on Issue { id, title, url } } + content { + ... on Issue { + id, title, url + milestone { title } + } + } } } } @@ -115,16 +126,18 @@ class GitHubProjectTracker: def fetch_release_blocker_stats(self) -> Dict[str, int]: """ - Fetches release blocker and must-do statistics from the GitHub project. + Fetches release blocker, must-do, and nice-to-have statistics from the GitHub project. Returns: Dict with 'total', 'done', 'percentage', 'blocker_total', 'blocker_done', - 'mustdo_total', 'mustdo_done' keys + 'mustdo_total', 'mustdo_done', 'nicetohave_total', 'nicetohave_done' keys """ blocker_total = 0 blocker_done = 0 mustdo_total = 0 mustdo_done = 0 + nicetohave_total = 0 + nicetohave_done = 0 cursor = None # Track if we've seen the expected fields at least once @@ -162,6 +175,17 @@ class GitHubProjectTracker: if not item.get("content"): continue + # Check milestone filter if configured + content = item.get("content", {}) + milestone = content.get("milestone", {}) + milestone_title = milestone.get("title", "") if milestone else "" + + # Skip if milestone filter is set and doesn't match + if self.milestone_filter: + # Match milestone versions like "2.1" with milestones like "2.1.0" or "HDF5 2.1" + if not (milestone_title and self.milestone_filter in milestone_title): + continue + fields = self._parse_item_fields(item) # Validate expected fields exist @@ -181,6 +205,10 @@ class GitHubProjectTracker: mustdo_total += 1 if status == VALUE_STATUS_DONE: mustdo_done += 1 + elif release_gating == VALUE_RELEASE_NICE_TO_HAVE: + nicetohave_total += 1 + if status == VALUE_STATUS_DONE: + nicetohave_done += 1 # Check for next page page_info = items.get("pageInfo", {}) @@ -219,16 +247,22 @@ class GitHubProjectTracker: # Validate that we found at least some items # If total is 0, either the project is empty or field matching failed if total == 0: - print("ERROR: No release blocker or must-do items found (total=0).", file=sys.stderr) - print("This likely indicates:", file=sys.stderr) - print(f" 1. The '{FIELD_RELEASE_GATING}' field values changed", file=sys.stderr) - print(f" Expected values: '{VALUE_RELEASE_BLOCKER}' or '{VALUE_RELEASE_MUST_DO}'", file=sys.stderr) - print(" 2. Project has no items with these field values", file=sys.stderr) - print(" 3. Field matching logic needs to be updated", file=sys.stderr) - print("Refusing to report 0% or 100% with no items to prevent false positives.", file=sys.stderr) - raise ProjectDataError("No release items found - refusing to report false completion status") - - percentage = round((done / total * 100), 1) + if self.milestone_filter: + print(f"INFO: No release blocker or must-do items found for milestone '{self.milestone_filter}'.", file=sys.stderr) + print("This may be expected if no items exist for this milestone yet.", file=sys.stderr) + # Don't fail - return N/A indicators when filtering by milestone with no items + percentage = -1.0 # Use -1 to indicate N/A + else: + print("ERROR: No release blocker or must-do items found (total=0).", file=sys.stderr) + print("This likely indicates:", file=sys.stderr) + print(f" 1. The '{FIELD_RELEASE_GATING}' field values changed", file=sys.stderr) + print(f" Expected values: '{VALUE_RELEASE_BLOCKER}' or '{VALUE_RELEASE_MUST_DO}'", file=sys.stderr) + print(" 2. Project has no items with these field values", file=sys.stderr) + print(" 3. Field matching logic needs to be updated", file=sys.stderr) + print("Refusing to report 0% or 100% with no items to prevent false positives.", file=sys.stderr) + raise ProjectDataError("No release items found - refusing to report false completion status") + else: + percentage = round((done / total * 100), 1) return { 'total': total, @@ -237,19 +271,68 @@ class GitHubProjectTracker: 'blocker_total': blocker_total, 'blocker_done': blocker_done, 'mustdo_total': mustdo_total, - 'mustdo_done': mustdo_done + 'mustdo_done': mustdo_done, + 'nicetohave_total': nicetohave_total, + 'nicetohave_done': nicetohave_done } +def get_hdf5_version_from_header(header_path: str = "../../src/H5public.h") -> Optional[str]: + """ + Extract HDF5 major.minor version from H5public.h + Returns version string like "2.1" or None if not found. + """ + try: + # Try multiple possible paths relative to the script location + script_dir = os.path.dirname(os.path.abspath(__file__)) + possible_paths = [ + os.path.join(script_dir, header_path), + os.path.join(script_dir, "../../src/H5public.h"), + "src/H5public.h", + "../../src/H5public.h" + ] + + for path in possible_paths: + if os.path.exists(path): + with open(path, 'r') as f: + major = None + minor = None + for line in f: + if '#define H5_VERS_MAJOR' in line: + major = line.split()[-1] + elif '#define H5_VERS_MINOR' in line: + minor = line.split()[-1] + if major and minor: + return f"{major}.{minor}" + break + except Exception as e: + print(f"Warning: Could not read version from H5public.h: {e}", file=sys.stderr) + + return None + + def main(): """Main function to run the tracker.""" # Configuration - can be overridden by environment variables TOKEN = os.getenv("GITHUB_TOKEN") OWNER = os.getenv("GITHUB_OWNER", "HDFGroup") PROJECT_NUMBER = int(os.getenv("GITHUB_PROJECT_NUMBER", "39")) - + + # Milestone filtering - can be set via env var or auto-detected from H5public.h + MILESTONE_FILTER = os.getenv("MILESTONE_FILTER") + if MILESTONE_FILTER is None: + # Try to auto-detect from H5public.h + MILESTONE_FILTER = get_hdf5_version_from_header() + if MILESTONE_FILTER: + print(f"Auto-detected milestone filter from H5public.h: {MILESTONE_FILTER}", file=sys.stderr) + + if MILESTONE_FILTER: + print(f"Filtering by milestone: {MILESTONE_FILTER}", file=sys.stderr) + else: + print("No milestone filter - counting all release items", file=sys.stderr) + try: - tracker = GitHubProjectTracker(TOKEN, OWNER, PROJECT_NUMBER) + tracker = GitHubProjectTracker(TOKEN, OWNER, PROJECT_NUMBER, MILESTONE_FILTER) stats = tracker.fetch_release_blocker_stats() # Output for GitHub Actions @@ -263,6 +346,9 @@ def main(): f.write(f"blocker_done={stats['blocker_done']}\n") f.write(f"mustdo_total={stats['mustdo_total']}\n") f.write(f"mustdo_done={stats['mustdo_done']}\n") + f.write(f"nicetohave_total={stats['nicetohave_total']}\n") + f.write(f"nicetohave_done={stats['nicetohave_done']}\n") + f.write(f"version={MILESTONE_FILTER or 'all'}\n") # Also output to stdout for local testing print(f"percentage={stats['percentage']}") @@ -270,10 +356,16 @@ def main(): print(f"blocker_total={stats['blocker_total']}") print(f"mustdo_done={stats['mustdo_done']}") print(f"mustdo_total={stats['mustdo_total']}") + print(f"nicetohave_done={stats['nicetohave_done']}") + print(f"nicetohave_total={stats['nicetohave_total']}") + print(f"version={MILESTONE_FILTER or 'all'}") print(f"Calculated progress: {stats['percentage']}%") print(f"Done / Total: {stats['done']} / {stats['total']}") print(f"Blockers: {stats['blocker_done']} / {stats['blocker_total']}") print(f"Must Do: {stats['mustdo_done']} / {stats['mustdo_total']}") + print(f"Nice to Have: {stats['nicetohave_done']} / {stats['nicetohave_total']}") + if MILESTONE_FILTER: + print(f"Milestone filter: {MILESTONE_FILTER}") except Exception as e: print(f"Error: {e}", file=sys.stderr) diff --git a/.github/workflows/update-progress.yml b/.github/workflows/update-progress.yml index fb1d99d8640..ef42833fbe2 100644 --- a/.github/workflows/update-progress.yml +++ b/.github/workflows/update-progress.yml @@ -115,11 +115,14 @@ jobs: exit 1 fi - # Extract blocker and must-do counts + # Extract blocker, must-do, and nice-to-have counts BLOCKER_DONE=$(grep "^blocker_done=" progress_output.txt | cut -d'=' -f2 | head -1) BLOCKER_TOTAL=$(grep "^blocker_total=" progress_output.txt | cut -d'=' -f2 | head -1) MUSTDO_DONE=$(grep "^mustdo_done=" progress_output.txt | cut -d'=' -f2 | head -1) MUSTDO_TOTAL=$(grep "^mustdo_total=" progress_output.txt | cut -d'=' -f2 | head -1) + NICETOHAVE_DONE=$(grep "^nicetohave_done=" progress_output.txt | cut -d'=' -f2 | head -1) + NICETOHAVE_TOTAL=$(grep "^nicetohave_total=" progress_output.txt | cut -d'=' -f2 | head -1) + VERSION=$(grep "^version=" progress_output.txt | cut -d'=' -f2 | head -1) # Set outputs for use in subsequent steps echo "percentage=$PERCENTAGE" >> $GITHUB_OUTPUT @@ -129,9 +132,12 @@ jobs: echo "blocker_total=$BLOCKER_TOTAL" >> $GITHUB_OUTPUT echo "mustdo_done=$MUSTDO_DONE" >> $GITHUB_OUTPUT echo "mustdo_total=$MUSTDO_TOTAL" >> $GITHUB_OUTPUT + echo "nicetohave_done=$NICETOHAVE_DONE" >> $GITHUB_OUTPUT + echo "nicetohave_total=$NICETOHAVE_TOTAL" >> $GITHUB_OUTPUT + echo "version=$VERSION" >> $GITHUB_OUTPUT echo "::notice::Progress calculation successful: ${PERCENTAGE}% (${DONE}/${TOTAL})" - echo "::notice:: Blockers: ${BLOCKER_DONE}/${BLOCKER_TOTAL}, Must Do: ${MUSTDO_DONE}/${MUSTDO_TOTAL}" + echo "::notice:: Version: ${VERSION}, Blockers: ${BLOCKER_DONE}/${BLOCKER_TOTAL}, Must Do: ${MUSTDO_DONE}/${MUSTDO_TOTAL}, Nice to Have: ${NICETOHAVE_DONE}/${NICETOHAVE_TOTAL}" # Clean up rm -f progress_output.txt @@ -152,6 +158,9 @@ jobs: BLOCKER_TOTAL: ${{ steps.progress.outputs.blocker_total }} MUSTDO_DONE: ${{ steps.progress.outputs.mustdo_done }} MUSTDO_TOTAL: ${{ steps.progress.outputs.mustdo_total }} + NICETOHAVE_DONE: ${{ steps.progress.outputs.nicetohave_done }} + NICETOHAVE_TOTAL: ${{ steps.progress.outputs.nicetohave_total }} + VERSION: ${{ steps.progress.outputs.version }} run: | # Execute dedicated badge generation script # This separates concerns: YAML orchestrates, scripts implement logic diff --git a/README.md b/README.md index 6bcd4135d67..4f85af0c84a 100644 --- a/README.md +++ b/README.md @@ -94,11 +94,13 @@ least one annual release for each maintenance branch. ### Release Progress -[![Release Blockers](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/brtnfld/a4fbdde293677bf3f63f3cfd3aef6b44/raw/release-blockers.json)](https://github.com/orgs/HDFGroup/projects/39/views/24) +[![Release Blockers](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/HDFGroup-Bot/0ad2eabb63b28eb90d69f5e5b2c1496f/raw/release-blocker-hdf5.json)](https://github.com/orgs/HDFGroup/projects/39/views/24) -[![Release Must Do](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/brtnfld/8a077a919d048ce5dc9f56350bec10bc/raw/release-mustdo.json)](https://github.com/orgs/HDFGroup/projects/39/views/24) +[![Release Must Do](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/HDFGroup-Bot/0ad2eabb63b28eb90d69f5e5b2c1496f/raw/release-mustdo-hdf5.json)](https://github.com/orgs/HDFGroup/projects/39/views/24) -The badges above show the current progress of **release-blocking** and **must-do** issues with colors that reflect completion status: +[![Release Nice to Have](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/HDFGroup-Bot/0ad2eabb63b28eb90d69f5e5b2c1496f/raw/release-nicetohave-hdf5.json)](https://github.com/orgs/HDFGroup/projects/39/views/24) + +The badges above show the current progress of **release-blocking**, **must-do**, and **nice-to-have** issues with colors that reflect completion status: - 🟢 **Green (90%+)**: Readying for Deployment - most issues completed - 🟡 **Yellow (60-89%)**: Nearing Completion - on track for release