From 6f23f371497f0d459bd99c970faf88ed3a17d2fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbyn=C4=9Bk=20Dr=C3=A1pela?= Date: Tue, 2 Jun 2026 10:49:36 +0200 Subject: [PATCH 1/7] feat(prow-trigger-nightly): add Gangway override flags for catalog index, chart version, playwright version Add --catalog-index-image (both repos), --chart-version (RHDH-only), and --playwright-version (overlay-only) flags to trigger_nightly_job.py. Restructure argument groups into shared, RHDH-only, and overlay-only with per-repo validation that rejects unsupported flags. Update SKILL.md with new options, RC/GA verification examples, and updated flag reference. Jira: https://redhat.atlassian.net/browse/RHIDP-14348 Assisted-by: OpenCode --- skills/prow-trigger-nightly/SKILL.md | 64 ++++++++++--- .../scripts/trigger_nightly_job.py | 90 +++++++++++++------ 2 files changed, 117 insertions(+), 37 deletions(-) diff --git a/skills/prow-trigger-nightly/SKILL.md b/skills/prow-trigger-nightly/SKILL.md index e1569cd..58c98ec 100644 --- a/skills/prow-trigger-nightly/SKILL.md +++ b/skills/prow-trigger-nightly/SKILL.md @@ -14,6 +14,7 @@ description: >- Trigger RHDH nightly ProwJobs via the OpenShift CI Gangway REST API. Supports two repositories: + - **rhdh** — the main RHDH application (`periodic-ci-redhat-developer-rhdh-*-nightly`) - **rhdh-plugin-export-overlays** — plugin export overlays (`periodic-ci-redhat-developer-rhdh-plugin-export-overlays-*-nightly`) @@ -56,6 +57,7 @@ Then ask the user to describe which job and branch they want in natural language Map the user's description to the matching full job name from the fetched list. If no branch is mentioned, default to `main`: **RHDH repo jobs:** + - "ocp helm" / "openshift helm" -> `e2e-ocp-helm-nightly` (not upgrade, not versioned) - "operator" / "ocp operator" -> `e2e-ocp-operator-nightly` (not auth-providers) - "helm upgrade" / "upgrade test" -> `e2e-ocp-helm-upgrade-nightly` @@ -72,6 +74,7 @@ Map the user's description to the matching full job name from the fetched list. - Multiple: "all AKS jobs", "all Operator jobs on main" -> offer to trigger them in sequence **Overlay repo jobs:** + - "overlay nightly" / "overlay helm" / "overlays nightly" -> `periodic-ci-redhat-developer-rhdh-plugin-export-overlays-main-e2e-ocp-helm-nightly` ### Shared Cluster Constraint (GKE / OSD-GCP only) @@ -80,21 +83,34 @@ GKE and OSD-GCP each share a single cluster — never run two jobs on the same p ## Step 2: Options -**Important:** Overlay repo jobs only support fork overrides (`--org`, `--repo`, `--branch`). Image overrides (`--image-registry`, `--image-repo`, `--tag`) and `--send-alerts` are NOT supported — the script will error if these are passed for an overlay job. If the user doesn't need fork overrides, skip this step and go directly to Step 3. +### Overlay repo jobs + +Overlay jobs support fork overrides (`--org`, `--repo`, `--branch`), catalog index override (`--catalog-index-image`), and Playwright version override (`--playwright-version`). + +Image overrides (`--image-registry`, `--image-repo`, `--tag`), `--chart-version`, and `--send-alerts` are NOT supported — the script will error if these are passed for an overlay job. + +If the user doesn't need any overrides, skip this step and go directly to Step 3. -For RHDH repo jobs, present all options together. The user picks by number — multiple selections allowed (e.g. "2, 5"): +### RHDH repo jobs + +Present all options together. The user picks by number — multiple selections allowed (e.g. "2, 5"): **Image override:** + 1. **Default image** — no image flags, use whatever the job is configured with 2. **Custom tag only** — override just the tag, keep default registry and repo 3. **Custom repo + tag** — override image repository and tag, keep default registry (`quay.io`) 4. **Fully custom image** — override registry, repo, and tag +**Catalog & chart override:** +5. **Catalog index image** — override the plugin catalog index image (`--catalog-index-image`) +6. **Chart version** — override the Helm chart version (`--chart-version`) + **Additional options:** -5. **Fork override** — run against a fork instead of `redhat-developer/rhdh` -6. **Send Slack alerts** — notify via `--send-alerts` +7. **Fork override** — run against a fork instead of `redhat-developer/rhdh` +8. **Send Slack alerts** — notify via `--send-alerts` -Constraint: `--image-repo` requires `--tag`, but `--tag` works on its own. +Constraint: `--image-repo` requires `--tag`, but `--tag` works on its own. `--playwright-version` is overlay-only and will error for RHDH jobs. ### Follow-up based on selections @@ -111,11 +127,17 @@ uv run scripts/trigger_nightly_job.py --list-tags Use `--image-repo ` to query a different image repository (default: `rhdh/rhdh-hub-rhel9`). Present the numbered results with a final option to enter a custom tag (e.g. `next`, `latest`). For option 3, also ask for the image repository. **If 4 selected (non-quay registry)** — ask for all three values (tag fetching not available): + - Registry (e.g. `brew.registry.redhat.io`) - Image repo (e.g. `rhdh/rhdh-hub-rhel9`) - Tag (e.g. `1.9`) -**If 5 selected** — ask for: +**If 5 selected** — ask for catalog index image (e.g. `quay.io/rhdh/plugin-catalog-index:1.9-60` for RC, `registry.access.redhat.com/rhdh/plugin-catalog-index:1.9.4` for GA). + +**If 6 selected** — ask for chart version (e.g. `1.9-227-CI`). + +**If 7 selected** — ask for: + - GitHub org (`--org`): e.g. `my-github-user` - Repo name (`--repo`): e.g. `rhdh` - Branch (`--branch`): e.g. `my-feature-branch` @@ -130,6 +152,9 @@ uv run scripts/trigger_nightly_job.py \ [--image-registry ] \ [--image-repo ] \ [--tag ] \ + [--catalog-index-image ] \ + [--chart-version ] \ + [--playwright-version ] \ [--org ] \ [--repo ] \ [--branch ] \ @@ -142,14 +167,33 @@ uv run scripts/trigger_nightly_job.py \ After execution, show the API response. If a job URL or ID is returned, display it prominently. On error, help diagnose (common issues: expired token, invalid job name). +### RC Verification Example + +```bash +uv run scripts/trigger_nightly_job.py \ + --job periodic-ci-redhat-developer-rhdh-main-e2e-ocp-helm-nightly \ + --image-repo rhdh/rhdh-hub-rhel9 --tag 1.9-227 \ + --catalog-index-image quay.io/rhdh/plugin-catalog-index:1.9 \ + --chart-version 1.9-227-CI +``` + +### GA Verification Example + +```bash +uv run scripts/trigger_nightly_job.py \ + --job periodic-ci-redhat-developer-rhdh-main-e2e-ocp-helm-nightly \ + --image-registry registry.redhat.io --image-repo rhdh/rhdh-hub-rhel9 --tag 1.9.4 \ + --catalog-index-image registry.access.redhat.com/rhdh/plugin-catalog-index:1.9.4 +``` + ## Reference -- Script flags: `-j/--job`, `-l/--list`, `-T/--list-tags`, `--tag-filter`, `-I/--image-registry`, `-q/--image-repo`, `-t/--tag`, `-o/--org`, `-r/--repo`, `-b/--branch`, `-S/--send-alerts`, `-n/--dry-run`, `--json` +- Script flags: `-j/--job`, `-l/--list`, `-T/--list-tags`, `--tag-filter`, `-I/--image-registry`, `-q/--image-repo`, `-t/--tag`, `--catalog-index-image`, `--chart-version`, `--playwright-version`, `-o/--org`, `-r/--repo`, `-b/--branch`, `-S/--send-alerts`, `-n/--dry-run`, `--json` - Dedicated kubeconfig at `~/.config/openshift-ci/kubeconfig` — won't interfere with your current cluster context - If auth is needed, the script opens a browser for SSO login -- RHDH jobs list: https://prow.ci.openshift.org/configured-jobs/redhat-developer/rhdh -- Overlay jobs list: https://prow.ci.openshift.org/configured-jobs/redhat-developer/rhdh-plugin-export-overlays -- Image tags: https://quay.io/repository/rhdh/rhdh-hub-rhel9?tab=tags +- RHDH jobs list: +- Overlay jobs list: +- Image tags: ## Related Skills diff --git a/skills/prow-trigger-nightly/scripts/trigger_nightly_job.py b/skills/prow-trigger-nightly/scripts/trigger_nightly_job.py index b9bbbac..fe95aeb 100755 --- a/skills/prow-trigger-nightly/scripts/trigger_nightly_job.py +++ b/skills/prow-trigger-nightly/scripts/trigger_nightly_job.py @@ -353,8 +353,8 @@ def build_payload(args: argparse.Namespace) -> dict: is_overlay = args.job.startswith(OVERLAY_JOB_PREFIX) if is_overlay: - # Overlay jobs support fork overrides only (org, repo, branch). - # Image overrides and alerts are not supported. + # Overlay jobs support fork overrides, catalog index, and playwright version. + # Image overrides, chart version, and alerts are not supported. unsupported: list[str] = [] if args.image_repo: unsupported.append("--image-repo") @@ -362,6 +362,8 @@ def build_payload(args: argparse.Namespace) -> dict: unsupported.append("--image-registry") if args.tag: unsupported.append("--tag") + if args.chart_version: + unsupported.append("--chart-version") if args.send_alerts: unsupported.append("--send-alerts") if unsupported: @@ -377,7 +379,16 @@ def build_payload(args: argparse.Namespace) -> dict: envs["MULTISTAGE_PARAM_OVERRIDE_GITHUB_REPOSITORY_NAME"] = args.repo if args.branch: envs["MULTISTAGE_PARAM_OVERRIDE_RELEASE_BRANCH_NAME"] = args.branch + if args.catalog_index_image: + envs["MULTISTAGE_PARAM_OVERRIDE_CATALOG_INDEX_IMAGE"] = args.catalog_index_image + if args.playwright_version: + envs["MULTISTAGE_PARAM_OVERRIDE_PLAYWRIGHT_VERSION"] = args.playwright_version else: + # RHDH repo jobs do not support playwright version. + if args.playwright_version: + log_error("--playwright-version is only supported for overlay jobs.") + sys.exit(1) + # RHDH repo jobs support full overrides. if args.image_repo: envs["MULTISTAGE_PARAM_OVERRIDE_IMAGE_REPO"] = args.image_repo @@ -391,6 +402,10 @@ def build_payload(args: argparse.Namespace) -> dict: envs["MULTISTAGE_PARAM_OVERRIDE_GITHUB_REPOSITORY_NAME"] = args.repo if args.branch: envs["MULTISTAGE_PARAM_OVERRIDE_RELEASE_BRANCH_NAME"] = args.branch + if args.catalog_index_image: + envs["MULTISTAGE_PARAM_OVERRIDE_CATALOG_INDEX_IMAGE"] = args.catalog_index_image + if args.chart_version: + envs["MULTISTAGE_PARAM_OVERRIDE_CHART_VERSION"] = args.chart_version skip_alert = "false" if args.send_alerts else "true" envs["MULTISTAGE_PARAM_OVERRIDE_SKIP_SEND_ALERT"] = skip_alert @@ -531,56 +546,77 @@ def parse_args(argv: list[str] | None = None) -> argparse.Namespace: help="Filter tags by version prefix (e.g. '1.10'). Used with --list-tags.", ) - overrides = parser.add_argument_group("RHDH job overrides (not supported for overlay jobs)") - overrides.add_argument( + shared = parser.add_argument_group("Shared overrides (both rhdh and overlay jobs)") + shared.add_argument( + "-o", + "--org", + dest="org", + default="", + help="Override the GitHub org (default: redhat-developer).", + ) + shared.add_argument( + "-r", + "--repo", + dest="repo", + default="", + help="Override the GitHub repo name (default: rhdh).", + ) + shared.add_argument( + "-b", + "--branch", + dest="branch", + default="", + help="Override the branch name.", + ) + shared.add_argument( + "--catalog-index-image", + dest="catalog_index_image", + default="", + help="Override the catalog index image (e.g. quay.io/rhdh/plugin-catalog-index:1.9-60).", + ) + + rhdh_only = parser.add_argument_group("RHDH-only overrides (not supported for overlay jobs)") + rhdh_only.add_argument( "-I", "--image-registry", dest="image_registry", default="", help="Override the image registry (default: quay.io).", ) - overrides.add_argument( + rhdh_only.add_argument( "-q", "--image-repo", dest="image_repo", default="", help="Override the image repository (e.g. rhdh/rhdh-hub-rhel9). Requires --tag.", ) - overrides.add_argument( + rhdh_only.add_argument( "-t", "--tag", dest="tag", default="", help="Override the image tag (e.g. 1.9-123).", ) - overrides.add_argument( - "-o", - "--org", - dest="org", - default="", - help="Override the GitHub org (default: redhat-developer).", - ) - overrides.add_argument( - "-r", - "--repo", - dest="repo", - default="", - help="Override the GitHub repo name (default: rhdh).", - ) - overrides.add_argument( - "-b", - "--branch", - dest="branch", + rhdh_only.add_argument( + "--chart-version", + dest="chart_version", default="", - help="Override the branch name.", + help="Override the Helm chart version (e.g. 1.9-227-CI).", ) - - parser.add_argument( + rhdh_only.add_argument( "-S", "--send-alerts", action="store_true", help="Send Slack alerts (default: alerts are skipped).", ) + + overlay_only = parser.add_argument_group("Overlay-only overrides (not supported for rhdh jobs)") + overlay_only.add_argument( + "--playwright-version", + dest="playwright_version", + default="", + help="Override the Playwright version (overlay jobs only).", + ) parser.add_argument( "-n", "--dry-run", From 4a1f7fa54ddd618f690ae6a60c03c119859bdfea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbyn=C4=9Bk=20Dr=C3=A1pela?= Date: Tue, 2 Jun 2026 10:51:39 +0200 Subject: [PATCH 2/7] feat(prow): add commission-release workflow with shared release branch config Add references/release-branch-config.md with shared definitions (file paths, branch protection template, release-vs-main differences) used by both commission and decommission workflows. Add workflows/commission-release.md for bootstrapping CI configuration when a new RHDH release branch is created. Refactor workflows/decommission-release.md to reference the shared config and use 'make update' for generated job cleanup instead of manual file deletion. Update SKILL.md description and routing table. Assisted-by: OpenCode --- skills/prow/SKILL.md | 7 +-- .../prow/references/release-branch-config.md | 53 +++++++++++++++++++ skills/prow/workflows/commission-release.md | 46 ++++++++++++++++ skills/prow/workflows/decommission-release.md | 9 ++-- 4 files changed, 108 insertions(+), 7 deletions(-) create mode 100644 skills/prow/references/release-branch-config.md create mode 100644 skills/prow/workflows/commission-release.md diff --git a/skills/prow/SKILL.md b/skills/prow/SKILL.md index 0009a7e..94320c0 100644 --- a/skills/prow/SKILL.md +++ b/skills/prow/SKILL.md @@ -4,9 +4,9 @@ description: >- Manage Prow CI job configurations for RHDH in the openshift/release repository. List, generate, add, and remove OCP test entries and cluster pools. List K8s platform test entries (AKS, EKS, GKE). Analyze OCP - version coverage gaps. Decommission end-of-life release branches. Use - when working with RHDH CI config, Prow jobs, cluster pools, or - openshift/release CI management. + version coverage gaps. Commission new release branches and decommission + end-of-life ones. Use when working with RHDH CI config, Prow jobs, + cluster pools, or openshift/release CI management. --- # RHDH Prow CI Management @@ -32,6 +32,7 @@ What CI management task do you need? | "cluster pool", "ClusterPool", "Hive pool" | `workflows/ocp-pools.md` | | "coverage", "gap analysis", "what OCP versions are missing" | `workflows/ocp-coverage.md` | | "AKS test", "EKS test", "GKE test", "K8s platform jobs" | `workflows/k8s-jobs.md` | +| "commission", "new release branch", "create release branch CI", "onboard release", "add release branch" | `workflows/commission-release.md` | | "decommission", "EOL release", "remove release branch", "clean up old release" | `workflows/decommission-release.md` | After reading the workflow, follow it exactly. diff --git a/skills/prow/references/release-branch-config.md b/skills/prow/references/release-branch-config.md new file mode 100644 index 0000000..aa0124a --- /dev/null +++ b/skills/prow/references/release-branch-config.md @@ -0,0 +1,53 @@ +# Release Branch CI Configuration + +Shared definitions for commissioning and decommissioning RHDH release branch CI in `openshift/release`. Both `workflows/commission-release.md` and `workflows/decommission-release.md` reference this file. + +## File Paths + +For a given release version `{VERSION}` (e.g. `1.10`): + +| File | Path | +|------|------| +| **CI config** | `ci-operator/config/redhat-developer/rhdh/redhat-developer-rhdh-release-{VERSION}.yaml` | +| **Generated jobs** | `ci-operator/jobs/redhat-developer/rhdh/redhat-developer-rhdh-release-{VERSION}-*.yaml` | +| **Branch protection** | `core-services/prow/02_config/redhat-developer/rhdh/_prowconfig.yaml` | + +## Branch Protection + +Each release branch has an entry under `branch-protection.orgs.redhat-developer.repos.rhdh.branches` in `_prowconfig.yaml`. + +When commissioning, **read the latest existing release branch entry** from `_prowconfig.yaml` and copy its structure (keys, contexts, settings). Do not hardcode the block — the required status check contexts and protection settings change over time. + +When decommissioning, remove the entire `release-{VERSION}:` block, preserving indentation and formatting of surrounding entries. + +## Release Branch vs Main Differences + +When creating a release branch config from `main` or another release branch, **read both the `main` config and the latest existing release branch config** to understand the current patterns, then apply these structural adjustments: + +| Adjustment | How to determine the correct value | +|------------|-----------------------------------| +| **Slack channel** | Read the latest release branch config. Pattern: `#rhdh-e2e-alerts-{X}-{Y}` (dots replaced with hyphens) | +| **Cron schedule** | Read the latest release branch config to see the current schedule pattern. Release branches use a different schedule than `main` to spread load | +| **Cleanup jobs** | Compare `main` with the latest release branch. Jobs present in `main` but absent from all release branches are main-only — remove them | +| **Presubmit tests** | Compare `main` with the latest release branch. Note differences in `always_run`, `max_concurrency`, and other settings — apply the release branch pattern | +| **`zz_generated_metadata.branch`** | Set to `release-{VERSION}` | + +Version-specific settings to verify with the user: + +| Setting | How to determine | +|---------|-----------------| +| **OCP versions** | Read the source config's `e2e-ocp-v4-*-helm-nightly` entries. Ask the user which OCP versions to include for the new branch | +| **K8s version** (`MAPT_KUBERNETES_VERSION`) | Read from the source config. Ask the user if it should change | +| **OSD version** | Read from the source config. Ask the user if it should change | +| **`releases.latest.release`** | Compare `channel` and `version` between main and release branches | +| **`build_root` tag** | Read from the source config. Ask the user if it should change | + +## Post-Change Step + +After modifying any CI config files, always run: + +```bash +make update +``` + +This regenerates Prow job configs in `ci-operator/jobs/` and `zz_generated_metadata` sections. It also cleans up generated jobs for deleted configs. diff --git a/skills/prow/workflows/commission-release.md b/skills/prow/workflows/commission-release.md new file mode 100644 index 0000000..07bff45 --- /dev/null +++ b/skills/prow/workflows/commission-release.md @@ -0,0 +1,46 @@ +# Commission New RHDH Release Branch Jobs + +Set up CI configuration for a new RHDH release branch. Requires a local `openshift/release` checkout. + +Read `../references/release-branch-config.md` for file paths, templates, and release-vs-main differences. + +## Steps + +1. **Get the release version**: + - If not provided, ask the user for the version (e.g. `1.11`) + - Verify the config does NOT already exist: `ls ci-operator/config/redhat-developer/rhdh/redhat-developer-rhdh-release-{version}.yaml` + +2. **Choose the source config**: + - List existing configs: `ls ci-operator/config/redhat-developer/rhdh/redhat-developer-rhdh-release-*.yaml` + - Default to the latest existing release branch (highest version number) + - Alternatively, use `main` as the source if the user prefers + +3. **Copy and adjust the CI config**: + - Copy the source file to `redhat-developer-rhdh-release-{version}.yaml` + - Read both the `main` config and the latest existing release branch config to understand the current patterns + - Apply all structural adjustments described in `references/release-branch-config.md` — compare main vs release branch to determine what to change (Slack channel, cron schedule, cleanup jobs, presubmit settings) + - Set `zz_generated_metadata.branch` to `release-{version}` + +4. **Confirm version-specific settings** with the user: + - OCP versions: which `e2e-ocp-v4-{VER}-helm-nightly` entries to include + - K8s version (`MAPT_KUBERNETES_VERSION`) + - OSD version + - `build_root` tag + - If copying from the latest release branch, these are often unchanged + +5. **Add branch protection** to `_prowconfig.yaml`: + - Read the latest existing release branch entry from `_prowconfig.yaml` to get the current structure and contexts + - Add a `release-{version}:` entry under `branch-protection.orgs.redhat-developer.repos.rhdh.branches`, copying the structure from the latest release branch + - Place the new entry in version order among existing entries + +6. **Run `make update`** to regenerate Prow job configs + +7. **Verify and summarize**: + - Confirm generated job files exist: `ls ci-operator/jobs/redhat-developer/rhdh/redhat-developer-rhdh-release-{version}-*.yaml` + - Show a summary of what was created + +## Important Notes + +- Always confirm OCP/K8s/OSD versions with the user before finalizing +- The source config determines the initial set of tests — the user may want to add or remove specific test entries after commissioning +- After the PR is merged, the actual `release-{version}` branch must exist in `redhat-developer/rhdh` for the jobs to trigger diff --git a/skills/prow/workflows/decommission-release.md b/skills/prow/workflows/decommission-release.md index 4c811ce..cb9a978 100644 --- a/skills/prow/workflows/decommission-release.md +++ b/skills/prow/workflows/decommission-release.md @@ -2,6 +2,8 @@ Remove all CI configuration for a given RHDH release branch when it reaches end-of-life. Requires a local `openshift/release` checkout. +Read `../references/release-branch-config.md` for file paths and templates. + ## Steps 1. **Get the release version**: @@ -14,18 +16,17 @@ Remove all CI configuration for a given RHDH release branch when it reaches end- 3. **Delete the CI config file** -4. **Delete the generated job files** - -5. **Remove branch protection configuration**: +4. **Remove branch protection configuration**: Edit `_prowconfig.yaml` to remove the entire `release-{version}:` block under `branch-protection.orgs.redhat-developer.repos.rhdh.branches`. Be careful to: - Only remove the block for the specified version - Preserve indentation and formatting of surrounding blocks - Not leave blank lines where the block was removed +5. **Run `make update`** to regenerate Prow job configs (this also removes the generated job files for the deleted config) + 6. **Confirm completion**: Summarize what was removed ## Important Notes -- **Do NOT run `make update`** -- only deleting files and removing branch protection - This operation is destructive -- always confirm with the user before proceeding - Always verify files exist before attempting deletion From 1cb0b2c2da00f1c7d39bfba6dbbdbffe231db6a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbyn=C4=9Bk=20Dr=C3=A1pela?= Date: Tue, 2 Jun 2026 10:52:22 +0200 Subject: [PATCH 3/7] fix(prow): fix URL encoding and IndexError in analyze_coverage.py Replace .replace(' ', '+') with urllib.parse.quote_plus() for proper URL encoding of product names in the fallback _fetch_api function. Guard api_data.get('data', [{}])[0] against empty data arrays to prevent IndexError when the API returns no results. Addresses non-blocking review items from PR #25. Assisted-by: OpenCode --- skills/prow/scripts/analyze_coverage.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/skills/prow/scripts/analyze_coverage.py b/skills/prow/scripts/analyze_coverage.py index 1b7ac27..cad9e56 100644 --- a/skills/prow/scripts/analyze_coverage.py +++ b/skills/prow/scripts/analyze_coverage.py @@ -20,6 +20,7 @@ import subprocess import sys import urllib.error +import urllib.parse import urllib.request from datetime import datetime, timezone from pathlib import Path @@ -57,7 +58,7 @@ def _fetch_lifecycle_json(script_name): def _fetch_api(product_name): """Fetch lifecycle data directly from the Red Hat API (fallback).""" - url = f"{LIFECYCLE_API_URL}?name={product_name.replace(' ', '+')}" + url = f"{LIFECYCLE_API_URL}?name={urllib.parse.quote_plus(product_name)}" req = urllib.request.Request( url, headers={"Accept": "application/json", "User-Agent": "rhdh-skill"} ) @@ -80,7 +81,8 @@ def _get_rhdh_lifecycle(): api_data = _fetch_api("Red Hat Developer Hub") if not api_data: return [] - versions_raw = api_data.get("data", [{}])[0].get("versions", []) + data = api_data.get("data", []) + versions_raw = data[0].get("versions", []) if data else [] results = [] for ver in versions_raw: ocp_compat = ver.get("openshift_compatibility", "") @@ -117,7 +119,8 @@ def _is_date(val): def _to_date(val): return val[:10] if _is_date(val) else None - versions = api_data.get("data", [{}])[0].get("versions", []) + data = api_data.get("data", []) + versions = data[0].get("versions", []) if data else [] versions = [v for v in versions if re.match(r"^\d+\.\d+$", v.get("name", ""))] versions = [v for v in versions if int(v["name"].split(".")[0]) >= 4] From 651ac4b5777a5abc28edbfc100a0c3cc5f484e46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbyn=C4=9Bk=20Dr=C3=A1pela?= Date: Tue, 2 Jun 2026 10:53:23 +0200 Subject: [PATCH 4/7] fix(prow): add --reference format validation to generate_cluster_pool.py Validate that --reference matches X.Y format before splitting, matching the existing validation in generate_test_entry.py. Previously, a malformed --reference value would crash at split('.'). Addresses non-blocking review item from PR #25. Assisted-by: OpenCode --- skills/prow/scripts/generate_cluster_pool.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/skills/prow/scripts/generate_cluster_pool.py b/skills/prow/scripts/generate_cluster_pool.py index 1454dc8..79a810c 100644 --- a/skills/prow/scripts/generate_cluster_pool.py +++ b/skills/prow/scripts/generate_cluster_pool.py @@ -63,6 +63,11 @@ def main(argv=None): print(f"ERROR: Version must be in X.Y format, got: {args.version}", file=sys.stderr) sys.exit(1) + if args.reference: + if not re.match(r"^\d+\.\d+$", args.reference): + print(f"ERROR: Reference must be in X.Y format, got: {args.reference}", file=sys.stderr) + sys.exit(1) + major, minor = args.version.split(".") next_minor = str(int(minor) + 1) dash_ver = f"{major}-{minor}" From e4b6efdedbd68aa059f010a0ecd0c98c1c2b9f6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbyn=C4=9Bk=20Dr=C3=A1pela?= Date: Tue, 2 Jun 2026 10:54:22 +0200 Subject: [PATCH 5/7] docs: add ruamel.yaml PEP 723 exception to ADR 0002 Document that prow skill scripts use ruamel.yaml via PEP 723 inline script metadata for round-trip YAML fidelity. The dependency is managed by uv run --script with no user-facing install step. Addresses non-blocking review item from PR #25. Assisted-by: OpenCode --- docs/adr/0002-stdlib-only-python-clis.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/adr/0002-stdlib-only-python-clis.md b/docs/adr/0002-stdlib-only-python-clis.md index 03f196e..7fc9109 100644 --- a/docs/adr/0002-stdlib-only-python-clis.md +++ b/docs/adr/0002-stdlib-only-python-clis.md @@ -9,3 +9,9 @@ Both CLIs (`rhdh` and `rhdh-local`) use only Python 3.9+ standard library — ze - **`uv`** as the dev tool runner (`uv run pytest`) — not shipped with the CLIs, but used for development and testing New scripts and CLI commands in this project should follow these same patterns. + +## Exceptions + +Prow skill scripts (under `skills/prow/scripts/`) use `ruamel.yaml` for round-trip YAML processing — preserving comments, key ordering, and quoting style that the stdlib `yaml` module cannot handle. These scripts declare the dependency via PEP 723 inline script metadata (`# /// script` blocks), and `uv run --script` auto-installs it in an ephemeral virtual environment. No user-facing install step is required. + +The stdlib-only rule still applies to the main CLIs and any script not run via `uv run --script`. From ff9f9b8b8762ca575ae1ed3bb5365f46ee9a4598 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbyn=C4=9Bk=20Dr=C3=A1pela?= Date: Tue, 2 Jun 2026 10:54:50 +0200 Subject: [PATCH 6/7] docs: add lifecycle, prow, and prow-trigger-nightly skills to README Add Platform Lifecycle and CI / Prow sections covering the three skills added via PRs #25 and #26 that were missing from the README. Assisted-by: OpenCode --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index 6034395..c459634 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,19 @@ Update Konflux task digests and apply `MIGRATION.md` pipeline changes in [rhdh-p npx skills add redhat-developer/rhdh-skill --skill konflux-tekton-updates ``` +### Platform Lifecycle + +Check version support status for platforms and integrations used by RHDH. + +- **[lifecycle](./skills/lifecycle/SKILL.md)** — Check version lifecycle and support status for OCP, AKS, EKS, GKE, RHDH releases, RHBK, Quay, PostgreSQL, and any Red Hat product via the Product Life Cycles API. + +### CI / Prow + +Manage Prow CI job configurations and trigger nightly E2E tests. + +- **[prow](./skills/prow/SKILL.md)** — Manage Prow CI job configurations for RHDH in the openshift/release repository. List, generate, add, and remove OCP test entries and cluster pools. List K8s platform test entries (AKS, EKS, GKE). Analyze coverage gaps. Commission new release branches and decommission end-of-life ones. +- **[prow-trigger-nightly](./skills/prow-trigger-nightly/SKILL.md)** — Trigger RHDH nightly ProwJobs on demand via the OpenShift CI Gangway REST API. Supports both rhdh and rhdh-plugin-export-overlays repos with Gangway overrides for catalog index image, chart version, and Playwright version. + ### Local Testing Test plugins in a local RHDH instance before deploying. From 1d868ead1e572f91139e0131cc138476d8ca5f8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbyn=C4=9Bk=20Dr=C3=A1pela?= Date: Tue, 2 Jun 2026 13:22:35 +0200 Subject: [PATCH 7/7] =?UTF-8?q?fix:=20review=20follow-ups=20=E2=80=94=20ve?= =?UTF-8?q?rsion=20bump,=20Slack=20alert=20setup,=20DRY=20helper?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Bump version 0.3.1 → 0.3.2 (pyproject.toml, plugin.json, marketplace.json) - Add Slack alert setup section to release-branch-config.md (channel creation, incoming webhook, Vault secret configuration) - Add Slack setup step to commission-release.md workflow - Standardize placeholder casing to {version} in release-branch-config.md - Clarify releases.latest.release field description - Extract _first_versions() helper in analyze_coverage.py to DRY up the repeated api_data.get('data', [])[0] pattern - Clarify decommission-release.md: generated jobs removed by make update - Decommission workflow now runs make update — the previous 'Do NOT run make update' guidance was incorrect; make update correctly removes generated job files for deleted configs, matching commission behavior Assisted-by: OpenCode --- .claude-plugin/marketplace.json | 4 +-- .claude-plugin/plugin.json | 2 +- pyproject.toml | 2 +- .../prow/references/release-branch-config.md | 27 ++++++++++++++----- skills/prow/scripts/analyze_coverage.py | 14 ++++++---- skills/prow/workflows/commission-release.md | 13 ++++++--- skills/prow/workflows/decommission-release.md | 2 +- uv.lock | 2 +- 8 files changed, 45 insertions(+), 21 deletions(-) diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 44bf61c..6d4c6de 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -5,14 +5,14 @@ }, "metadata": { "description": "Orchestrator skill for RHDH plugin development - onboard, update, and maintain plugins in the Extensions Catalog", - "version": "0.3.1" + "version": "0.3.2" }, "plugins": [ { "name": "rhdh", "source": "./", "description": "Skills for RHDH plugin lifecycle management", - "version": "0.3.1", + "version": "0.3.2", "strict": true } ] diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index f27dff9..3b200cf 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "rhdh", "description": "All-in-one toolkit for Red Hat Developer Hub (RHDH). Covers plugin development, overlay management, environment setup, version compatibility, CI/CD, and RHDH ecosystem navigation.", - "version": "0.3.1", + "version": "0.3.2", "author": { "name": "RHDH Store Manager" }, diff --git a/pyproject.toml b/pyproject.toml index b4cce0a..d8621af 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "rhdh-skill" -version = "0.3.1" +version = "0.3.2" description = "Claude Code skill for RHDH plugin development" readme = "README.md" license = "Apache-2.0" diff --git a/skills/prow/references/release-branch-config.md b/skills/prow/references/release-branch-config.md index aa0124a..a530088 100644 --- a/skills/prow/references/release-branch-config.md +++ b/skills/prow/references/release-branch-config.md @@ -4,12 +4,12 @@ Shared definitions for commissioning and decommissioning RHDH release branch CI ## File Paths -For a given release version `{VERSION}` (e.g. `1.10`): +For a given release version `{version}` (e.g. `1.10`): | File | Path | |------|------| -| **CI config** | `ci-operator/config/redhat-developer/rhdh/redhat-developer-rhdh-release-{VERSION}.yaml` | -| **Generated jobs** | `ci-operator/jobs/redhat-developer/rhdh/redhat-developer-rhdh-release-{VERSION}-*.yaml` | +| **CI config** | `ci-operator/config/redhat-developer/rhdh/redhat-developer-rhdh-release-{version}.yaml` | +| **Generated jobs** | `ci-operator/jobs/redhat-developer/rhdh/redhat-developer-rhdh-release-{version}-*.yaml` | | **Branch protection** | `core-services/prow/02_config/redhat-developer/rhdh/_prowconfig.yaml` | ## Branch Protection @@ -18,7 +18,7 @@ Each release branch has an entry under `branch-protection.orgs.redhat-developer. When commissioning, **read the latest existing release branch entry** from `_prowconfig.yaml` and copy its structure (keys, contexts, settings). Do not hardcode the block — the required status check contexts and protection settings change over time. -When decommissioning, remove the entire `release-{VERSION}:` block, preserving indentation and formatting of surrounding entries. +When decommissioning, remove the entire `release-{version}:` block, preserving indentation and formatting of surrounding entries. ## Release Branch vs Main Differences @@ -30,7 +30,7 @@ When creating a release branch config from `main` or another release branch, **r | **Cron schedule** | Read the latest release branch config to see the current schedule pattern. Release branches use a different schedule than `main` to spread load | | **Cleanup jobs** | Compare `main` with the latest release branch. Jobs present in `main` but absent from all release branches are main-only — remove them | | **Presubmit tests** | Compare `main` with the latest release branch. Note differences in `always_run`, `max_concurrency`, and other settings — apply the release branch pattern | -| **`zz_generated_metadata.branch`** | Set to `release-{VERSION}` | +| **`zz_generated_metadata.branch`** | Set to `release-{version}` | Version-specific settings to verify with the user: @@ -39,9 +39,24 @@ Version-specific settings to verify with the user: | **OCP versions** | Read the source config's `e2e-ocp-v4-*-helm-nightly` entries. Ask the user which OCP versions to include for the new branch | | **K8s version** (`MAPT_KUBERNETES_VERSION`) | Read from the source config. Ask the user if it should change | | **OSD version** | Read from the source config. Ask the user if it should change | -| **`releases.latest.release`** | Compare `channel` and `version` between main and release branches | +| **`releases.latest.release`** | OCP release payload used by ci-operator (`channel` + `version`). Compare main and release branches — typically the same, but may differ if the release branch targets an older OCP | | **`build_root` tag** | Read from the source config. Ask the user if it should change | +## Slack Alert Setup + +Each release branch needs its own Slack channel and webhook for E2E alert notifications. There are two alert mechanisms: + +1. **Prow `reporter_config`** — configured per-test in the CI config YAML (`reporter_config.channel`). Set to `#rhdh-e2e-alerts-{X}-{Y}` (dots replaced with hyphens). This fires on infrastructure-level errors. + +2. **`rhdh-send-alert` step** — uses a Slack incoming webhook URL from the Vault secret `rhdh-send-alert` (namespace `test-credentials`). The script auto-detects the release version from `JOB_NAME` and looks for a versioned key `SLACK_ALERTS_WEBHOOK_URL_{X}_{Y}` (dots replaced with underscores), falling back to the default `SLACK_ALERTS_WEBHOOK_URL`. + +### Setup steps + +1. **Create Slack channel** `#rhdh-e2e-alerts-{X}-{Y}` in the [Nightly Test Alerts Slack app](https://api.slack.com/apps/A08U4AP1YTY/incoming-webhooks) +2. **Create incoming webhook** for the new channel in the same Slack app +3. **Add webhook URL to Vault** secret `rhdh-send-alert` as key `SLACK_ALERTS_WEBHOOK_URL_{X}_{Y}` +4. **Set `reporter_config.channel`** to `#rhdh-e2e-alerts-{X}-{Y}` on every nightly test entry in the CI config + ## Post-Change Step After modifying any CI config files, always run: diff --git a/skills/prow/scripts/analyze_coverage.py b/skills/prow/scripts/analyze_coverage.py index cad9e56..1b9bf5b 100644 --- a/skills/prow/scripts/analyze_coverage.py +++ b/skills/prow/scripts/analyze_coverage.py @@ -56,6 +56,12 @@ def _fetch_lifecycle_json(script_name): return None +def _first_versions(api_data): + """Extract versions list from the first entry of API response data.""" + data = api_data.get("data", []) + return data[0].get("versions", []) if data else [] + + def _fetch_api(product_name): """Fetch lifecycle data directly from the Red Hat API (fallback).""" url = f"{LIFECYCLE_API_URL}?name={urllib.parse.quote_plus(product_name)}" @@ -81,8 +87,7 @@ def _get_rhdh_lifecycle(): api_data = _fetch_api("Red Hat Developer Hub") if not api_data: return [] - data = api_data.get("data", []) - versions_raw = data[0].get("versions", []) if data else [] + versions_raw = _first_versions(api_data) results = [] for ver in versions_raw: ocp_compat = ver.get("openshift_compatibility", "") @@ -119,8 +124,7 @@ def _is_date(val): def _to_date(val): return val[:10] if _is_date(val) else None - data = api_data.get("data", []) - versions = data[0].get("versions", []) if data else [] + versions = _first_versions(api_data) versions = [v for v in versions if re.match(r"^\d+\.\d+$", v.get("name", ""))] versions = [v for v in versions if int(v["name"].split(".")[0]) >= 4] @@ -153,7 +157,7 @@ def _to_date(val): if end and end >= today: current_phase = pname break - elif not _is_date(end_raw) and end_raw not in ("N/A", "", None): + elif end is None or (not _is_date(end_raw) and end_raw not in ("N/A", "")): current_phase = pname break if current_phase != "End of life": diff --git a/skills/prow/workflows/commission-release.md b/skills/prow/workflows/commission-release.md index 07bff45..5487089 100644 --- a/skills/prow/workflows/commission-release.md +++ b/skills/prow/workflows/commission-release.md @@ -18,7 +18,7 @@ Read `../references/release-branch-config.md` for file paths, templates, and rel 3. **Copy and adjust the CI config**: - Copy the source file to `redhat-developer-rhdh-release-{version}.yaml` - Read both the `main` config and the latest existing release branch config to understand the current patterns - - Apply all structural adjustments described in `references/release-branch-config.md` — compare main vs release branch to determine what to change (Slack channel, cron schedule, cleanup jobs, presubmit settings) + - Apply all structural adjustments described in `../references/release-branch-config.md` — compare main vs release branch to determine what to change (Slack channel, cron schedule, cleanup jobs, presubmit settings) - Set `zz_generated_metadata.branch` to `release-{version}` 4. **Confirm version-specific settings** with the user: @@ -28,14 +28,19 @@ Read `../references/release-branch-config.md` for file paths, templates, and rel - `build_root` tag - If copying from the latest release branch, these are often unchanged -5. **Add branch protection** to `_prowconfig.yaml`: +5. **Set up Slack alerts** (see `../references/release-branch-config.md` > Slack Alert Setup): + - Create Slack channel `#rhdh-e2e-alerts-{X}-{Y}` and incoming webhook + - Add webhook URL to Vault secret `rhdh-send-alert` as key `SLACK_ALERTS_WEBHOOK_URL_{X}_{Y}` + - Set `reporter_config.channel` to `#rhdh-e2e-alerts-{X}-{Y}` on every nightly test entry in the CI config + +6. **Add branch protection** to `_prowconfig.yaml`: - Read the latest existing release branch entry from `_prowconfig.yaml` to get the current structure and contexts - Add a `release-{version}:` entry under `branch-protection.orgs.redhat-developer.repos.rhdh.branches`, copying the structure from the latest release branch - Place the new entry in version order among existing entries -6. **Run `make update`** to regenerate Prow job configs +7. **Run `make update`** to regenerate Prow job configs -7. **Verify and summarize**: +8. **Verify and summarize**: - Confirm generated job files exist: `ls ci-operator/jobs/redhat-developer/rhdh/redhat-developer-rhdh-release-{version}-*.yaml` - Show a summary of what was created diff --git a/skills/prow/workflows/decommission-release.md b/skills/prow/workflows/decommission-release.md index cb9a978..b4f1213 100644 --- a/skills/prow/workflows/decommission-release.md +++ b/skills/prow/workflows/decommission-release.md @@ -11,7 +11,7 @@ Read `../references/release-branch-config.md` for file paths and templates. 2. **Verify files to be removed** (show the user and ask for confirmation): - **CI config**: `ci-operator/config/redhat-developer/rhdh/redhat-developer-rhdh-release-{version}.yaml` - - **Generated jobs**: `ci-operator/jobs/redhat-developer/rhdh/redhat-developer-rhdh-release-{version}-*.yaml` + - **Generated jobs** (removed by `make update`): `ci-operator/jobs/redhat-developer/rhdh/redhat-developer-rhdh-release-{version}-*.yaml` - **Branch protection**: `release-{version}:` block in `core-services/prow/02_config/redhat-developer/rhdh/_prowconfig.yaml` 3. **Delete the CI config file** diff --git a/uv.lock b/uv.lock index 69564ff..0feac8e 100644 --- a/uv.lock +++ b/uv.lock @@ -195,7 +195,7 @@ wheels = [ [[package]] name = "rhdh-skill" -version = "0.3.1" +version = "0.3.2" source = { virtual = "." } [package.optional-dependencies]