Skip to content

[hack] Add z-stream-release-check.py pre-sprint planning tool#4045

Draft
mtnbikenc wants to merge 1 commit into
openshift:masterfrom
mtnbikenc:z-stream-release-check
Draft

[hack] Add z-stream-release-check.py pre-sprint planning tool#4045
mtnbikenc wants to merge 1 commit into
openshift:masterfrom
mtnbikenc:z-stream-release-check

Conversation

@mtnbikenc
Copy link
Copy Markdown
Member

@mtnbikenc mtnbikenc commented May 1, 2026

Summary

  • Adds hack/z-stream-release-check.py — a script for determining which WMCO release branches need a z-stream release before sprint planning
  • Adds .claude/commands/z-stream-release-check.md — a Claude slash command (/z-stream-release-check) that runs the script and interprets the output

What the script does

Fetches data from four sources and produces a four-section report:

  1. Release branches — classifies every release-X.Y branch as active, pre-release, or old EOM; shows last release tag, publish date, and EOM date from the OCP lifecycle API; optionally shows open Jira release tickets
  2. Image health — fetches freshness grades (A–F) and CVE counts from the Red Hat Container Catalog; shows threshold date and whether a rebuild from the current ubi9/ubi-minimal base would extend the grade window
  3. Unreleased PRs — uses the GitHub Compare API to find team PRs merged since the last release tag, filtering out bot bumps (Konflux, Renovate, mintmaker, dependabot), non-shipped PRs (test/docs/hack + CI skip-if-only-changed pattern), and version-bump PRs (shown as [INFO])
  4. Sprint recommendation — flags branches needing action with the reason(s): grade below B, grade will drop within 21 days (sprint lookahead), or unreleased team PRs

Release recommendation logic

Any one condition is sufficient:

  • ✗ UNRELEASED PRs — non-bot, shipped team PRs exist since the last tag
  • ✗ IMAGE GRADE — current grade is C, D, E, or F
  • ⚠ UPCOMING GRADE — grade is A/B but drops below B within 21 days

CVE counts are informational only and do not trigger a recommendation.

Usage

python3 hack/z-stream-release-check.py                   # in-support branches
python3 hack/z-stream-release-check.py --all             # include past-EOM
python3 hack/z-stream-release-check.py --branch release-4.18
python3 hack/z-stream-release-check.py --json            # machine-readable
python3 hack/z-stream-release-check.py --pre-release-prs # include pre-release PR list
python3 hack/z-stream-release-check.py --connectivity    # test APIs only

Optional env vars: GITHUB_TOKEN (avoid rate limiting), JIRA_API_TOKEN + JIRA_USERNAME (enable Jira release ticket tracking).

Test plan

  • Run python3 hack/z-stream-release-check.py and verify output sections render correctly
  • Run with --json and verify valid JSON output with no progress noise on stdout
  • Run with --connectivity and verify all APIs report reachable
  • Run with --all and verify past-EOM branches appear
  • Run with --branch release-4.18 and verify single-branch output
  • Verify exit code is 0 on success and 2 on connectivity failure

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added a z-stream release check command for analyzing WMCO releases, evaluating image health, identifying unreleased PRs, and detecting CVE vulnerabilities across OCP minor versions.
    • Supports human-readable and JSON output formats with configurable CLI flags and environment variables.
  • Documentation

    • Added documentation for the z-stream release check command with usage instructions, output interpretation guide, and related tools reference.

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 1, 2026

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@openshift-ci openshift-ci Bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label May 1, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 1, 2026

Important

Review skipped

Auto reviews are limited based on label configuration.

🚫 Excluded labels (none allowed) (2)
  • do-not-merge/work-in-progress
  • do-not-merge/hold

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: ca6ca6d1-686c-461b-a164-c23380136ca4

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 1, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: mtnbikenc
Once this PR has been reviewed and has the lgtm label, please assign mansikulkarni96 for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@mtnbikenc
Copy link
Copy Markdown
Member Author

mtnbikenc commented May 1, 2026

Example output — python3 hack/z-stream-release-check.py

Run against the live data on 2026-05-01:

Connectivity check
------------------------------
  [OK]   Red Hat Container Catalog
  [OK]   Red Hat OCP Lifecycle API
  [OK]   GitHub API
  [OK]   Jira (WINC project)

Fetching WMCO image list from Red Hat Container Catalog... done (12 images)
Fetching OCP lifecycle (EOM dates) from Red Hat API... done
Fetching GitHub release branches... done (21 branches)
Fetching GitHub tags... done (49 tags)
Fetching Jira release tickets... done (1 open ticket)
Fetching base image (ubi9/ubi-minimal) grade data... done (grade B, threshold 2026-05-30)
Checking release branches...
  release-4.18 [EOM 2028-02-25]: CVEs. PRs. done
  release-4.19 [EOM 2026-12-17]: CVEs. PRs. done
  release-4.20 [EOM 2028-10-21]: CVEs. PRs. done
  release-4.21 [EOM 2027-08-03]: CVEs. PRs. done
  release-4.22: [pre-release] (use --pre-release-prs to show PRs)
  release-4.23: [pre-release] (no previous tag found)
  release-5.0: [pre-release] (no previous tag found)
  release-5.1: [pre-release] (no previous tag found)

WMCO Z-Stream Release Check — 2026-05-01
============================================================

RELEASE BRANCHES
Branch                 Last Release     Published    OCP     Status
------------------------------------------------------------------------------------------
release-4.18           v10.18.2         2026-03-17   4.18    Active (EOM 2028-02-25)
release-4.19           v10.19.2         2026-04-15   4.19    Active (EOM 2026-12-17)
release-4.20           v10.20.1         2026-03-12   4.20    Active (EOM 2028-10-21)
release-4.21           v10.21.1         2026-03-03   4.21    Active (EOM 2027-08-03)
release-4.22           [PRE-RELEASE]    --           4.22    Pre-release (no catalog entry yet)
                      ↳ WINC-1539 v10.22.0 (Epic) — New
release-4.23           [PRE-RELEASE]    --           4.23    Pre-release (no catalog entry yet)
release-5.0            [PRE-RELEASE]    --           5.0     Pre-release (no catalog entry yet)
release-5.1            [PRE-RELEASE]    --           5.1     Pre-release (no catalog entry yet)

IMAGE HEALTH (Red Hat Container Catalog)
Version        Grade    Threshold Date   CVEs           Base       Status
------------------------------------------------------------------------
v10.18.2       C        --               3I 2M 1L       ext ✓      ✗
v10.19.2       B        2026-05-13       2I 1M          ext ✓      ⚠
v10.20.1       C        --               3I 2M 1L       ext ✓      ✗
v10.21.1       C        --               3I 2M 1L       ext ✓      ✗

UNRELEASED PULL REQUESTS
------------------------------------------------------------
release-4.18 (since v10.18.2): no team PRs  ✓  (23 bot bumps filtered)
  PR #3875  [INFO] [release-4.18] WINC-1742: Update version to 10.18.3
release-4.19 (since v10.19.2): no team PRs  ✓  (13 bot bumps filtered)
  PR #3998  [INFO] WINC-1795: [release-4.19] Update version to 10.19.3
release-4.20 (since v10.20.1): no team PRs  ✓  (21 bot bumps filtered)
  PR #3895  [INFO] [release-4.20] Update version to 10.20.2
release-4.21 (since v10.21.1): no team PRs  ✓  (38 bot bumps filtered)
  PR #3840  [INFO] [release-4.21] Update version to 10.21.2
release-4.22 (since v10.21.0): [pre-release] — use --pre-release-prs to show unreleased PRs
release-4.23: [pre-release] — no base tag found
release-5.0: [pre-release] — no base tag found
release-5.1: [pre-release] — no base tag found

SPRINT RECOMMENDATION
------------------------------------------------------------

release-4.18
  ✗ Image health: Grade C — below threshold
    ↑ base image extends grade window — rebuild improves threshold date
  ℹ CVEs (info): 3 Important, 2 Moderate, 1 Low
  → No open release ticket  (PR #3875 bumped version to 10.18.3)

release-4.19
  ⚠ Image grade: Currently B, will drop below B on 2026-05-13 (12 days) — start release now
    ↑ base image extends grade window — rebuild improves threshold date
  ℹ CVEs (info): 2 Important, 1 Moderate
  → No open release ticket  (PR #3998 bumped version to 10.19.3)

release-4.20
  ✗ Image health: Grade C — below threshold
    ↑ base image extends grade window — rebuild improves threshold date
  ℹ CVEs (info): 3 Important, 2 Moderate, 1 Low
  → No open release ticket  (PR #3895 bumped version to 10.20.2)

release-4.21
  ✗ Image health: Grade C — below threshold
    ↑ base image extends grade window — rebuild improves threshold date
  ℹ CVEs (info): 3 Important, 2 Moderate, 1 Low
  → No open release ticket  (PR #3840 bumped version to 10.21.2)

Status: action required

@mtnbikenc
Copy link
Copy Markdown
Member Author

Example output — python3 hack/z-stream-release-check.py --pre-release-prs

Same run as above but with --pre-release-prs, which fetches unreleased PRs for the
pre-release branch (release-4.22 in this case). Only the UNRELEASED PULL REQUESTS section
differs — everything else is identical.

  release-4.22: [pre-release] PRs.......................... done

UNRELEASED PULL REQUESTS
------------------------------------------------------------
release-4.18 (since v10.18.2): no team PRs  ✓  (23 bot bumps filtered)
  PR #3875  [INFO] [release-4.18] WINC-1742: Update version to 10.18.3
release-4.19 (since v10.19.2): no team PRs  ✓  (13 bot bumps filtered)
  PR #3998  [INFO] WINC-1795: [release-4.19] Update version to 10.19.3
release-4.20 (since v10.20.1): no team PRs  ✓  (21 bot bumps filtered)
  PR #3895  [INFO] [release-4.20] Update version to 10.20.2
release-4.21 (since v10.21.1): no team PRs  ✓  (38 bot bumps filtered)
  PR #3840  [INFO] [release-4.21] Update version to 10.21.2
release-4.22 (since v10.21.0): 18 team PRs  ⚠  (58 bot bumps, 8 non-shipped filtered) [pre-release]
  PR #3583  MON-4437: Migrate windows-exporter ServiceMonitor to EndpointSlice
  PR #3678  WINC-1542: 4.22 branching
  PR #3711  Master submodule update 01 19
  PR #3611  [build] include windows-exporter-webconfig.yaml in Dockerfile.base
  PR #3717  OCPBUGS-69902: vendor: bump x/crypto to v0.47.0
  PR #3718  vendor: bump spf13/cobra to v1.10.2
  PR #3796  Master submodule update 02 17
  PR #3766  WINC-1635, WINC-1592: enable log rotation for kubelet and kubeproxy services
  PR #3835  WINC-1437: Remove deprecated `cs` collector from windows_exporter service
  PR #3854  [vendor] bump x/crypto to v0.48.0
  PR #3873  WINC-1488: [windows] Retry SSH authentication failure
  PR #3860  WINC-1566: React to 1.35 kube rebase and use go 1.25
  PR #3874  WINC-1777: [ote] Add OTE extension binary skeleton
  PR #3916  Master submodule update 04 02
  PR #3918  OCPBUGS-38401: Mirror MAPI userData to openshift-cluster-api namespace for CAPI
  PR #3917  [vendor] bump x/crypto to v0.49.0
  PR #4015  [release-4.22] [vendor] bump kubernetes to v1.35.3 and x/net to v0.52.0
  PR #4039  [release-4.22] WINC-1873: update windows_exporter and submodule updates 04 29
release-4.23: [pre-release] — no base tag found
release-5.0: [pre-release] — no base tag found
release-5.1: [pre-release] — no base tag found

The 18 team PRs and 58 filtered bot bumps on release-4.22 represent work accumulated since
the v10.21.0 GA tag — this is what will ship in the first 10.22.x release. The 8 non-shipped
PRs (docs/test/hack-only changes) were filtered automatically.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.claude/commands/z-stream-release-check.md:
- Around line 16-19: The docs and script disagree: update
hack/z-stream-release-check.py so IMAGE HEALTH matches the markdown by (1)
treating images with Critical or Important CVEs as "action needed" (not
informational-only) when computing the grade/flag, and (2) showing the actual
"threshold crossing" date for images already below B instead of printing `--`.
Locate the reporting logic in functions named like generate_image_health_row or
format_image_health_table (and any CVE filter/threshold-check helper) and change
the CVE severity check to mark Critical/Important as degradations and remove the
code path that replaces threshold dates with `--` for degraded images so the
real threshold date is displayed.

In `@hack/z-stream-release-check.py`:
- Around line 1423-1426: When computing the previous OCP minor for pre-release
branches, don't compute prev_ocp_minor by decrementing ocp_parts_pr[1] (which
yields invalid values like "5.-1"); instead, find the previous released minor by
locating ocp_minor in the ordered list of branches/tags (all_tags) and taking
the immediate predecessor. Update the block that sets prev_ocp_minor and
base_tag (the code using ocp_minor, ocp_parts_pr, prev_ocp_minor and calling
_find_pre_release_base_tag) to look up the prior entry in the sorted/ordered
branch/tag sequence and pass that value to _find_pre_release_base_tag so
major-version rollovers are handled correctly.
- Around line 726-730: The except block around the call to _fetch_support_dates
currently swallows RuntimeError and sets support_dates = {}, which must instead
be treated as a fatal lifecycle API failure; update the except RuntimeError as
exc handler to log the error (same stderr message) and then call sys.exit(2) (or
re-raise) instead of assigning an empty dict so the process fails fast and does
not continue with empty support_dates.
- Around line 1620-1629: The fetch_unreleased_prs error path stores an "error"
in result["unreleased"] but the downstream branch-clear logic still treats that
branch as "No action needed"; update the decision at the branch disposition
point to check unreleased.get("error") and treat any non-empty error as a
non-clear state (or fail the run for critical API errors). Specifically, when
evaluating the "clear" condition that currently inspects unreleased["ahead_by"],
unreleased["total_prs"], etc., add a check like: if unreleased.get("error"):
mark the branch as needing attention (or raise/exit) so branches with failed
compare calls cannot be reported as ✓ No action needed; refer to
fetch_unreleased_prs, result["unreleased"], and the unreleased variable in that
decision logic to implement this.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 12c76d81-9605-4a0c-bfe6-5f8c168f6d88

📥 Commits

Reviewing files that changed from the base of the PR and between 9ec8fc4 and 4ed0525.

📒 Files selected for processing (2)
  • .claude/commands/z-stream-release-check.md
  • hack/z-stream-release-check.py

Comment thread .claude/commands/z-stream-release-check.md Outdated
Comment thread hack/z-stream-release-check.py Outdated
Comment thread hack/z-stream-release-check.py Outdated
Comment thread hack/z-stream-release-check.py
Introduces hack/z-stream-release-check.py and a companion Claude slash
command (.claude/commands/z-stream-release-check.md) for determining
which WMCO release branches need a z-stream release. Run before sprint
planning to produce a per-branch report covering image health,
unreleased PRs, and a concrete sprint recommendation.

Data sources
  - Red Hat Container Catalog (catalog.redhat.com): WMCO operator image
    freshness grades (A–F) and CVE vulnerability counts per branch.
    Also fetches ubi9/ubi-minimal base image grade to assess whether a
    rebuild would extend the grade window.
  - OCP Lifecycle JSON API (access.redhat.com): EOM dates per OCP minor
    version from the phases[] array. Uses EUS Term 2 end dates for OCP
    4.18+ / WMCO 10.18+ when available; falls back to Maintenance
    support end dates for all other releases.
  - GitHub API (api.github.com): release branches, tags, and PR
    metadata. Uses the Compare API to find commits on each branch since
    its last release tag, then fetches per-PR file lists to filter
    non-shipped changes.
  - Jira (redhat.atlassian.net): open release Epics and Tasks in the
    WINC project. Optional; requires JIRA_API_TOKEN + JIRA_USERNAME.
    Shown as supplementary context only — does not affect
    recommendations.

Branch classification
  - In catalog (active): RHEL9 catalog entry exists; support status
    determined by OCP lifecycle API.
  - Pre-release: branch exists in GitHub but no release tags yet —
    the newest branch still tracking master. Shown with [PRE-RELEASE];
    skipped in image health and sprint recommendation. Use
    --pre-release-prs to fetch and display unreleased PRs for it.
  - Old EOM / pre-RHEL9: tagged but not in RHEL9 catalog (e.g.
    release-4.17 and earlier). Hidden by default; shown with --all.
  - OCP 4.x below 4.15: predates WMCO 10.x entirely; always classified
    as old EOM without tag checks.

Image health (Container Health Index)
  Grade A–F is time-based (age of oldest unpatched Critical/Important
  erratum). Release recommendation triggers when:
    - Grade is below B (C, D, E, or F) — image needs a rebuild now.
    - Grade is A or B but will drop within SPRINT_LOOKAHEAD_DAYS (21
      days) — sprint planning happens at sprint start; a release may
      not ship until sprint end, so upcoming degradation must be acted
      on now.
  The Threshold Date column shows when the grade first crosses below B:
    - For A/B images: the upcoming deadline.
    - For already-degraded images: the column is suppressed since the
      catalog API generates start_date dynamically from today.
  CVE counts (C/I/M/L) are informational only and do not trigger
  recommendations — the grade already encodes CVE timeliness.
  Base image rebuild value (ext ✓ / same / ↓ / —) indicates whether
  rebuilding from ubi9/ubi-minimal:latest would extend the grade
  window; advisory only, does not trigger recommendations.

Unreleased PR detection
  Uses the GitHub Compare API (tag...branch) to find merge commits
  since the last release tag. Smart filtering excludes:
    - Bot bump PRs by branch prefix: konflux/, mintmaker/, renovate/,
      dependabot/. openshift-cherrypick-robot PRs are kept (they carry
      real bug/CVE fixes).
    - Bot PRs by GitHub login: openshift-bot, openshift-merge-robot,
      openshift-ci-robot.
    - Non-shipped PRs: PRs where every changed file matches test/,
      docs/, or hack/ prefixes, or the CI skip-if-only-changed pattern
      (ote/, .github/, .tekton/, *.md, root config files including
      .coderabbit.yaml). Conservatively treated as shipped on fetch
      failure.
    - Version-bump PRs ("Update version to X.Y.Z"): shown as [INFO]
      to indicate release prep has started but do not themselves
      trigger a recommendation.
  Any remaining non-bot, non-version-bump team PR triggers a release
  recommendation.

Sprint recommendation logic (any one condition is sufficient)
  ✗ UNRELEASED PRs  — shipped team PRs exist since the last release tag
  ✗ IMAGE GRADE     — current grade below B (C/D/E/F)
  ⚠ UPCOMING GRADE  — grade A/B now but drops within 21 days

Output modes
  Default: four-section human-readable text report (RELEASE BRANCHES,
  IMAGE HEALTH, UNRELEASED PULL REQUESTS, SPRINT RECOMMENDATION) with
  ANSI color coding, auto-disabled when stdout is not a TTY.
  --json: machine-readable JSON with all fields; progress suppressed.
  --connectivity: probe all required APIs and exit.
  --all: include past-EOM and pre-RHEL9 branches in output.
  --branch BRANCH: restrict output to a single branch.
  --pre-release-prs: fetch and display PRs for pre-release branches.

Other
  - Progress feedback shown for all remote fetching; one dot per PR
    detail + file-check round trip.
  - Retry-enabled GET wrapper handles transient network failures.
  - Paginated fetching for catalog images, GitHub branches, tags, and
    PR file lists.
  - Exit 0 on success regardless of recommendations; exit 2 on fatal
    connectivity or API errors.
  - OCP major → WMCO major mapping: ocp_major + 6 (OCP 4 → WMCO 10,
    OCP 5 → WMCO 11), used throughout for tag patterns, Jira
    fixVersion parsing, and support date lookups.
  - EUS Term 2 eligibility: OCP 4.18+ (WMCO 10.18+) or any OCP 5.x+
    when the lifecycle API provides an EUS Term 2 end date.
@mtnbikenc mtnbikenc force-pushed the z-stream-release-check branch from 4ed0525 to 838f934 Compare May 1, 2026 20:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant