Skip to content

ART-19443: Add gen-assembly-lp and prepare-release-lp pipelines for Layered Products#2989

Open
ashwindasr wants to merge 4 commits into
openshift-eng:mainfrom
ashwindasr:cursor-lp-asm-abcd
Open

ART-19443: Add gen-assembly-lp and prepare-release-lp pipelines for Layered Products#2989
ashwindasr wants to merge 4 commits into
openshift-eng:mainfrom
ashwindasr:cursor-lp-asm-abcd

Conversation

@ashwindasr

@ashwindasr ashwindasr commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds gen-assembly-lp pipeline: extracts operand NVRs from FBC images, supports --include for swapping specific operand builds, --basis-assembly for lightweight inherited assemblies, and creates a PR to ocp-build-data with the assembly definition in releases.yml
  • Adds prepare-release-lp pipeline: reads a named assembly, checks for existing bundles before rebuilding (only builds missing ones), triggers FBC builds, and creates shipment MRs with release notes
  • Extracts shared FBC validation utilities into pyartcd/pyartcd/fbc_util.py (from release_from_fbc.py)
  • Registers both as artcd CLI commands (artcd gen-assembly-lp, artcd prepare-release-lp)
  • Updates doozer beta:fbc:rebase-and-build to return pullspecs alongside NVRs (needed for FBC consistency validation)
  • Adds olm_operator_nvrs to elliott find-builds --all-image-types JSON output (needed to scope bundle builds to assembly-pinned operators)
  • Disables strict assembly mode for non-openshift groups in doozer runtime (LP groups don't use brew events)
  • Moves STANDARD assembly check before major.minor extraction in get_release_name (LP group names don't match openshift-X.Y)

Context

ACM and MCE need the same two-phase assembly workflow that OCP has (gen-assembly -> prepare-release), adapted for FBC-driven Layered Product releases. This separates "what goes into the release" from "ship the release", enabling operand pinning, build swapping, and reproducible releases.

Test Runs

Changes to existing files

All changes to existing files are scoped to LP groups only and do not affect OCP pipelines:

  • doozer/doozerlib/cli/fbc.py: _rebase_and_build_fbc returns (nvr, pullspec) tuple; JSON output gains pullspecs key. Existing consumers use .get("nvrs") defensively — no breakage.
  • doozer/doozerlib/runtime.py: strict_mode = False for non-openshift-X.Y groups. For OCP groups, is_openshift_group = True so the new condition is or False — zero behavioral change.
  • doozer/doozerlib/util.py: STANDARD assembly check moved before isolate_major_minor_in_group. All existing callers pass openshift-X.Y groups where major/minor are always valid — no change in behavior.
  • elliott/elliottlib/cli/find_builds_cli.py: Adds olm_operator_nvrs key to return dict. Adding a key to a dict is backward compatible.
  • pyartcd/pyartcd/pipelines/release_from_fbc.py: Delegates extract_fbc_labels and validate_fbc_related_images to shared fbc_util.py. API surface preserved.

Test plan

  • pytest pyartcd/tests/pipelines/test_gen_assembly_lp.py — 25 tests pass
  • pytest pyartcd/tests/pipelines/test_prepare_release_lp.py — 26 tests pass
  • pytest pyartcd/tests/test_fbc_util.py — 8 tests pass
  • pytest doozer/tests/cli/test_fbc.py — 13 tests pass (updated mocks for new return type)
  • Manual dry-run with a real ACM FBC pullspec
  • Verify assembly YAML output matches expected format
  • Verify inherited assembly only records delta from parent

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Added Layered Product pipeline entrypoints to generate assembly definitions and prepare LP release artifacts from a named assembly (including optional MR creation and release-note generation).
    • Enhanced FBC build handling to reuse existing successful results more effectively and capture image pull information.
  • Bug Fixes

    • Improved release naming/initialization for non–OpenShift-style group names.
    • Added stronger validation for FBC-related images to detect mismatches earlier and fail fast.

@coderabbitai

coderabbitai Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds LP assembly and release pipelines, shared FBC helpers, and supporting updates to build outputs, runtime behavior, and tests.

Changes

LP release pipeline updates

Layer / File(s) Summary
Shared FBC helpers
pyartcd/pyartcd/fbc_util.py, pyartcd/pyartcd/pipelines/release_from_fbc.py, pyartcd/tests/test_fbc_util.py
Adds shared FBC label, version, and related-image helpers; replaces inline release pipeline FBC logic with delegation; adds helper tests.
Assembly generation pipeline
pyartcd/pyartcd/pipelines/gen_assembly_lp.py, pyartcd/tests/pipelines/test_gen_assembly_lp.py
Adds the LP assembly generator, including operand extraction, inheritance-aware assembly output, PR creation, CLI wiring, and tests.
Release preparation pipeline
pyartcd/pyartcd/pipelines/prepare_release_lp.py, pyartcd/tests/pipelines/test_prepare_release_lp.py
Adds the LP release-preparation pipeline, including bundle/FBC builds, snapshots, shipment config generation, MR workflow, CLI wiring, and tests.
Build-tooling outputs and runtime
doozer/doozerlib/cli/fbc.py, doozer/doozerlib/runtime.py, doozer/doozerlib/util.py, doozer/tests/cli/test_fbc.py, elliott/elliottlib/cli/find_builds_cli.py, pyartcd/pyartcd/__main__.py
Updates FBC build outputs to include pullspecs, adjusts runtime and release-name handling, extends build listings, and exports the new pipeline entrypoints.

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • thegreyd

Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 2 warnings)

Check name Status Explanation Resolution
No-Sensitive-Data-In-Logs ❌ Error New logs print raw FBC pullspecs and GitLab MR/pipeline URLs, which can expose internal hostnames. Redact hostnames/URLs or log sanitized IDs only; avoid logging raw pullspecs and full URLs.
Docstring Coverage ⚠️ Warning Docstring coverage is 52.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Ai-Attribution ⚠️ Warning HEAD commit uses Co-Authored-By: Claude Opus 4.6, but no Assisted-by/Generated-by Red Hat trailer is present. Replace the AI Co-Authored-By trailer with an Assisted-by or Generated-by trailer, or add the required Red Hat attribution.
✅ Passed checks (8 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: adding the two Layered Products pipelines.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
No-Weak-Crypto ✅ Passed No MD5/SHA1/DES/RC4/3DES/Blowfish/ECB or custom crypto was added; secret usage is limited to GitLab token injection, with no token comparison logic.
Container-Privileges ✅ Passed No changed manifest files or diff hunks add privileged/root pod settings; scans of all modified files found no allowPrivilegeEscalation/privileged/hostPID/hostNetwork/hostIPC/SYS_ADMIN/runAsUser:0/...
No-Hardcoded-Secrets ✅ Passed Touched files only use env-derived tokens (GITLAB_TOKEN/QUAY_AUTH_FILE); no hardcoded keys/passwords, embedded creds, or long base64 literals found in the diff.
No-Injection-Vectors ✅ Passed No injection vectors found: commands use arg lists (no shell=True), untrusted YAML uses safe_load, and yaml.load is via ruamel round-trip handler.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@ashwindasr
ashwindasr marked this pull request as draft June 3, 2026 02:02
@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 Jun 3, 2026
@ashwindasr ashwindasr changed the title Add gen-assembly-lp and prepare-release-lp pipelines for Layered Products Add gen-assembly-lp and prepare-release-lp pipelines for Layered Products (ART-19443) Jun 3, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
pyartcd/tests/pipelines/test_gen_assembly_lp.py (1)

216-216: 💤 Low value

Consider using asyncio.run() instead of deprecated get_event_loop().run_until_complete().

asyncio.get_event_loop() is deprecated since Python 3.10. While this works in tests, using asyncio.run() is the modern approach.

♻️ Suggested refactor
-        result = asyncio.get_event_loop().run_until_complete(pipeline.run())
+        result = asyncio.run(pipeline.run())

Also applies to: 239-239

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pyartcd/tests/pipelines/test_gen_assembly_lp.py` at line 216, Replace
deprecated asyncio.get_event_loop().run_until_complete(...) calls with
asyncio.run(...) in the test; specifically change the line assigning result from
asyncio.get_event_loop().run_until_complete(pipeline.run()) to use
asyncio.run(pipeline.run()) (and the similar occurrence at the later instance),
so the test invokes pipeline.run() with asyncio.run for modern, non-deprecated
event loop usage.
pyartcd/pyartcd/pipelines/prepare_release_lp.py (1)

444-456: ⚡ Quick win

Add exception chaining for better traceability.

Line 456 raises a new ValueError but doesn't chain the original GithubException. This loses the original traceback, making debugging harder.

Proposed fix
         except GithubException as e:
-            raise ValueError(f"Failed to fetch {filename} from {data_path} branch {branch}: {e}")
+            raise ValueError(f"Failed to fetch {filename} from {data_path} branch {branch}: {e}") from e
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pyartcd/pyartcd/pipelines/prepare_release_lp.py` around lines 444 - 456, The
except block in get_file_from_branch catches GithubException and raises a new
ValueError without chaining the original exception, losing the original
traceback; modify the raise to chain the original exception (use "raise
ValueError(... ) from e") so the original GithubException is preserved for
debugging while keeping the descriptive message about failing to fetch the file.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pyartcd/pyartcd/pipelines/gen_assembly_lp.py`:
- Around line 205-206: The code uses an undefined Model symbol and creates an
unused releases_model, which will raise a NameError; remove the dead
instantiation or import and use Model properly. Fix by deleting the
releases_model assignment (the releases_config from
yaml.load(releases_yaml_path) is the only value used later), or if a Model is
intended, add the proper import (e.g., from artcommonlib import Model) and
replace downstream uses to reference releases_model. Ensure the lines
referencing Model and releases_model are either removed or backed by a correct
import so no NameError occurs.

---

Nitpick comments:
In `@pyartcd/pyartcd/pipelines/prepare_release_lp.py`:
- Around line 444-456: The except block in get_file_from_branch catches
GithubException and raises a new ValueError without chaining the original
exception, losing the original traceback; modify the raise to chain the original
exception (use "raise ValueError(... ) from e") so the original GithubException
is preserved for debugging while keeping the descriptive message about failing
to fetch the file.

In `@pyartcd/tests/pipelines/test_gen_assembly_lp.py`:
- Line 216: Replace deprecated asyncio.get_event_loop().run_until_complete(...)
calls with asyncio.run(...) in the test; specifically change the line assigning
result from asyncio.get_event_loop().run_until_complete(pipeline.run()) to use
asyncio.run(pipeline.run()) (and the similar occurrence at the later instance),
so the test invokes pipeline.run() with asyncio.run for modern, non-deprecated
event loop usage.
🪄 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: Organization UI

Review profile: CHILL

Plan: Enterprise

Run ID: c053fe81-a603-4b73-b6be-48003606ee0b

📥 Commits

Reviewing files that changed from the base of the PR and between 6002b0e and 0c471d1.

📒 Files selected for processing (5)
  • pyartcd/pyartcd/__main__.py
  • pyartcd/pyartcd/pipelines/gen_assembly_lp.py
  • pyartcd/pyartcd/pipelines/prepare_release_lp.py
  • pyartcd/tests/pipelines/test_gen_assembly_lp.py
  • pyartcd/tests/pipelines/test_prepare_release_lp.py

Comment thread pyartcd/pyartcd/pipelines/gen_assembly_lp.py Outdated
@ashwindasr
ashwindasr force-pushed the cursor-lp-asm-abcd branch from 61ccf62 to f78cb2a Compare June 4, 2026 17:31
@ashwindasr
ashwindasr force-pushed the cursor-lp-asm-abcd branch 2 times, most recently from 2fe4c1f to efd9db5 Compare June 5, 2026 18:43
@ashwindasr
ashwindasr marked this pull request as ready for review June 5, 2026 19:45
@openshift-ci openshift-ci Bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jun 5, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🧹 Nitpick comments (1)
doozer/tests/cli/test_fbc.py (1)

151-161: ⚡ Quick win

Assert the JSON pullspecs payload, not just the mocked inputs.

These updated tests feed the new PipelineRun fields, but they never verify that run() actually emits the derived pullspecs in its JSON output. Capturing click.echo in one happy-path case would lock down the new CLI contract and catch regressions in pullspec reuse/parsing.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@doozer/tests/cli/test_fbc.py` around lines 151 - 161, The test currently
mocks mock_builder.build to return PipelineRun-like status results but never
asserts that run() actually emits the derived JSON "pullspecs" payload; update
the happy-path test to capture click.echo output from invoking run(), parse the
echoed JSON, and assert the "pullspecs" field equals the expected list (e.g.,
the image URL and image digest derived from mock_builder.build's status
results). Locate the test that calls run() and uses mock_builder.build (the
block returning "test-pipelinerun" and the status results) and add an assertion
comparing the parsed JSON payload's "pullspecs" to the expected values to lock
down the CLI contract.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@doozer/doozerlib/cli/fbc.py`:
- Around line 665-666: The code currently returns an empty pullspec string for
reused or newly-created KonfluxFbcBuildRecord, which hides errors; update the
reuse branch (where existing_fbc_build is returned) and the fresh-build branch
(the code around where a new KonfluxFbcBuildRecord is produced) to check
existing_fbc_build.image_pullspec (and the equivalent new_record.image_pullspec)
and if it's falsy and self.force is not set, raise a clear exception (e.g.,
click.ClickException or RuntimeError) asking the user to re-run with --force or
handle the missing pullspec; if self.force is true allow returning the record as
before. Ensure you adjust both the return site that currently does
"existing_fbc_build.nvr, existing_fbc_build.image_pullspec or ''" and the
corresponding return for the fresh-build path so they do not silently return an
empty string.
- Around line 679-682: When building the digest pullspec replace
image_url.split(':')[0] with logic that strips only the tag part (the last
colon) so registry ports are preserved; update the pullspec construction that
uses image_url and image_digest (variables image_url, image_digest, pullspec) to
derive the name-without-tag via image_url.rsplit(':', 1)[0] (or equivalent) and
then combine that with @{image_digest} only when both values exist.

In `@doozer/doozerlib/runtime.py`:
- Line 96: Runtime.extra_vars is typed as dict[str, str] but get_replace_vars()
and the loop that processes CLI-style KEY=VALUE strings (see iteration near
lines 398-407) expect an iterable of "KEY=VALUE" strings; change the
Runtime.extra_vars declaration and initialization in class Runtime to a list of
strings (e.g., extra_vars: list[str] = []) so callers can pass CLI-style entries
and the existing parsing logic in get_replace_vars()/the loop continues to work
without raising "Invalid --var format" errors.

In `@pyartcd/pyartcd/fbc_util.py`:
- Around line 98-128: The current logic in the operator-extraction block of
fbc_util.py assigns a per-pullspec UNKNOWN-... value when it cannot determine an
operator (using fbc_pullspec, labels, nvr and tag), which allows same-operator
FBCs to be split; instead, change both the "else" branch and the except block to
raise an exception (e.g., ValueError or RuntimeError) with a clear message
including fbc_pullspec and nvr/tag rather than assigning operator =
f"UNKNOWN-..."; keep the existing warning/error logs but follow them by raising
so caller code fails the validation when operator identity cannot be
established.

In `@pyartcd/pyartcd/pipelines/gen_assembly_lp.py`:
- Around line 219-251: _resolve_parent_operands currently only reads
members_images from the single basis_assembly and misses inherited operands;
change it to recursively walk the basis/parent chain in releases_config (use
releases_config.get('releases') to lookup ancestors), merging each ancestor's
assembly.members.images into operand_map so that descendant overrides win (child
entries override parent entries), and guard against cycles/too-deep recursion;
preserve existing logging and return operand_map as before.

In `@pyartcd/pyartcd/pipelines/prepare_release_lp.py`:
- Around line 201-233: The _load_assembly/_extract_operand_nvrs flow currently
reads only the assembly block's members.images, which misses inherited entries
from a chain of basis.assembly (LP generated delta assemblies); update
_load_assembly to resolve the full effective assembly by following the
basis.assembly chain (reading parent assemblies from releases.yml until no
basis), merge each parent's members.images into the child (preserving override
semantics), then pass that expanded assembly to _extract_operand_nvrs so it
iterates the full effective members.images list; reference the functions
_load_assembly, _extract_operand_nvrs and the basis.assembly / members.images
keys when implementing the merge.

In `@pyartcd/tests/pipelines/test_gen_assembly_lp.py`:
- Around line 293-305: The test currently patches
GenAssemblyLPPipeline._extract_nvrs_from_fbc so the single-pullspec branch is
never exercised; remove that patch and instead patch the lower-level extractor
function that _extract_nvrs_from_fbc calls (i.e., the downstream extractor used
inside GenAssemblyLPPipeline._extract_nvrs_from_fbc), then call
pipeline._extract_nvrs_from_fbc() directly and assert it returns the expected
mapping and that validate_fbc_related_images (patched as mock_validate) was not
called; ensure the test still uses the
fbc_pullspecs=["quay.io/test/fbc@sha256:single"] input and keeps
mock_validate.assert_not_called().

---

Nitpick comments:
In `@doozer/tests/cli/test_fbc.py`:
- Around line 151-161: The test currently mocks mock_builder.build to return
PipelineRun-like status results but never asserts that run() actually emits the
derived JSON "pullspecs" payload; update the happy-path test to capture
click.echo output from invoking run(), parse the echoed JSON, and assert the
"pullspecs" field equals the expected list (e.g., the image URL and image digest
derived from mock_builder.build's status results). Locate the test that calls
run() and uses mock_builder.build (the block returning "test-pipelinerun" and
the status results) and add an assertion comparing the parsed JSON payload's
"pullspecs" to the expected values to lock down the CLI contract.
🪄 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: Organization UI

Review profile: CHILL

Plan: Enterprise

Run ID: 5e34b1e2-18b6-4321-a54d-c17d21653d6a

📥 Commits

Reviewing files that changed from the base of the PR and between 0c471d1 and efd9db5.

📒 Files selected for processing (13)
  • doozer/doozerlib/cli/fbc.py
  • doozer/doozerlib/runtime.py
  • doozer/doozerlib/util.py
  • doozer/tests/cli/test_fbc.py
  • elliott/elliottlib/cli/find_builds_cli.py
  • pyartcd/pyartcd/__main__.py
  • pyartcd/pyartcd/fbc_util.py
  • pyartcd/pyartcd/pipelines/gen_assembly_lp.py
  • pyartcd/pyartcd/pipelines/prepare_release_lp.py
  • pyartcd/pyartcd/pipelines/release_from_fbc.py
  • pyartcd/tests/pipelines/test_gen_assembly_lp.py
  • pyartcd/tests/pipelines/test_prepare_release_lp.py
  • pyartcd/tests/test_fbc_util.py
✅ Files skipped from review due to trivial changes (1)
  • pyartcd/pyartcd/main.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 7

🧹 Nitpick comments (1)
doozer/tests/cli/test_fbc.py (1)

151-161: ⚡ Quick win

Assert the JSON pullspecs payload, not just the mocked inputs.

These updated tests feed the new PipelineRun fields, but they never verify that run() actually emits the derived pullspecs in its JSON output. Capturing click.echo in one happy-path case would lock down the new CLI contract and catch regressions in pullspec reuse/parsing.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@doozer/tests/cli/test_fbc.py` around lines 151 - 161, The test currently
mocks mock_builder.build to return PipelineRun-like status results but never
asserts that run() actually emits the derived JSON "pullspecs" payload; update
the happy-path test to capture click.echo output from invoking run(), parse the
echoed JSON, and assert the "pullspecs" field equals the expected list (e.g.,
the image URL and image digest derived from mock_builder.build's status
results). Locate the test that calls run() and uses mock_builder.build (the
block returning "test-pipelinerun" and the status results) and add an assertion
comparing the parsed JSON payload's "pullspecs" to the expected values to lock
down the CLI contract.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@doozer/doozerlib/cli/fbc.py`:
- Around line 665-666: The code currently returns an empty pullspec string for
reused or newly-created KonfluxFbcBuildRecord, which hides errors; update the
reuse branch (where existing_fbc_build is returned) and the fresh-build branch
(the code around where a new KonfluxFbcBuildRecord is produced) to check
existing_fbc_build.image_pullspec (and the equivalent new_record.image_pullspec)
and if it's falsy and self.force is not set, raise a clear exception (e.g.,
click.ClickException or RuntimeError) asking the user to re-run with --force or
handle the missing pullspec; if self.force is true allow returning the record as
before. Ensure you adjust both the return site that currently does
"existing_fbc_build.nvr, existing_fbc_build.image_pullspec or ''" and the
corresponding return for the fresh-build path so they do not silently return an
empty string.
- Around line 679-682: When building the digest pullspec replace
image_url.split(':')[0] with logic that strips only the tag part (the last
colon) so registry ports are preserved; update the pullspec construction that
uses image_url and image_digest (variables image_url, image_digest, pullspec) to
derive the name-without-tag via image_url.rsplit(':', 1)[0] (or equivalent) and
then combine that with @{image_digest} only when both values exist.

In `@doozer/doozerlib/runtime.py`:
- Line 96: Runtime.extra_vars is typed as dict[str, str] but get_replace_vars()
and the loop that processes CLI-style KEY=VALUE strings (see iteration near
lines 398-407) expect an iterable of "KEY=VALUE" strings; change the
Runtime.extra_vars declaration and initialization in class Runtime to a list of
strings (e.g., extra_vars: list[str] = []) so callers can pass CLI-style entries
and the existing parsing logic in get_replace_vars()/the loop continues to work
without raising "Invalid --var format" errors.

In `@pyartcd/pyartcd/fbc_util.py`:
- Around line 98-128: The current logic in the operator-extraction block of
fbc_util.py assigns a per-pullspec UNKNOWN-... value when it cannot determine an
operator (using fbc_pullspec, labels, nvr and tag), which allows same-operator
FBCs to be split; instead, change both the "else" branch and the except block to
raise an exception (e.g., ValueError or RuntimeError) with a clear message
including fbc_pullspec and nvr/tag rather than assigning operator =
f"UNKNOWN-..."; keep the existing warning/error logs but follow them by raising
so caller code fails the validation when operator identity cannot be
established.

In `@pyartcd/pyartcd/pipelines/gen_assembly_lp.py`:
- Around line 219-251: _resolve_parent_operands currently only reads
members_images from the single basis_assembly and misses inherited operands;
change it to recursively walk the basis/parent chain in releases_config (use
releases_config.get('releases') to lookup ancestors), merging each ancestor's
assembly.members.images into operand_map so that descendant overrides win (child
entries override parent entries), and guard against cycles/too-deep recursion;
preserve existing logging and return operand_map as before.

In `@pyartcd/pyartcd/pipelines/prepare_release_lp.py`:
- Around line 201-233: The _load_assembly/_extract_operand_nvrs flow currently
reads only the assembly block's members.images, which misses inherited entries
from a chain of basis.assembly (LP generated delta assemblies); update
_load_assembly to resolve the full effective assembly by following the
basis.assembly chain (reading parent assemblies from releases.yml until no
basis), merge each parent's members.images into the child (preserving override
semantics), then pass that expanded assembly to _extract_operand_nvrs so it
iterates the full effective members.images list; reference the functions
_load_assembly, _extract_operand_nvrs and the basis.assembly / members.images
keys when implementing the merge.

In `@pyartcd/tests/pipelines/test_gen_assembly_lp.py`:
- Around line 293-305: The test currently patches
GenAssemblyLPPipeline._extract_nvrs_from_fbc so the single-pullspec branch is
never exercised; remove that patch and instead patch the lower-level extractor
function that _extract_nvrs_from_fbc calls (i.e., the downstream extractor used
inside GenAssemblyLPPipeline._extract_nvrs_from_fbc), then call
pipeline._extract_nvrs_from_fbc() directly and assert it returns the expected
mapping and that validate_fbc_related_images (patched as mock_validate) was not
called; ensure the test still uses the
fbc_pullspecs=["quay.io/test/fbc@sha256:single"] input and keeps
mock_validate.assert_not_called().

---

Nitpick comments:
In `@doozer/tests/cli/test_fbc.py`:
- Around line 151-161: The test currently mocks mock_builder.build to return
PipelineRun-like status results but never asserts that run() actually emits the
derived JSON "pullspecs" payload; update the happy-path test to capture
click.echo output from invoking run(), parse the echoed JSON, and assert the
"pullspecs" field equals the expected list (e.g., the image URL and image digest
derived from mock_builder.build's status results). Locate the test that calls
run() and uses mock_builder.build (the block returning "test-pipelinerun" and
the status results) and add an assertion comparing the parsed JSON payload's
"pullspecs" to the expected values to lock down the CLI contract.
🪄 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: Organization UI

Review profile: CHILL

Plan: Enterprise

Run ID: 5e34b1e2-18b6-4321-a54d-c17d21653d6a

📥 Commits

Reviewing files that changed from the base of the PR and between 0c471d1 and efd9db5.

📒 Files selected for processing (13)
  • doozer/doozerlib/cli/fbc.py
  • doozer/doozerlib/runtime.py
  • doozer/doozerlib/util.py
  • doozer/tests/cli/test_fbc.py
  • elliott/elliottlib/cli/find_builds_cli.py
  • pyartcd/pyartcd/__main__.py
  • pyartcd/pyartcd/fbc_util.py
  • pyartcd/pyartcd/pipelines/gen_assembly_lp.py
  • pyartcd/pyartcd/pipelines/prepare_release_lp.py
  • pyartcd/pyartcd/pipelines/release_from_fbc.py
  • pyartcd/tests/pipelines/test_gen_assembly_lp.py
  • pyartcd/tests/pipelines/test_prepare_release_lp.py
  • pyartcd/tests/test_fbc_util.py
✅ Files skipped from review due to trivial changes (1)
  • pyartcd/pyartcd/main.py
🛑 Comments failed to post (7)
doozer/doozerlib/cli/fbc.py (2)

665-666: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't report success when the pullspec is unknown.

Both the reuse path and the fresh-build path currently collapse a missing pullspec to "". Since this command now publishes pullspecs as part of its success output, that turns an unusable result into a reported success and can break downstream LP validation in hard-to-diagnose ways. Please fail fast here, or require --force when the reused KonfluxFbcBuildRecord has no image_pullspec.

Also applies to: 682-685

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@doozer/doozerlib/cli/fbc.py` around lines 665 - 666, The code currently
returns an empty pullspec string for reused or newly-created
KonfluxFbcBuildRecord, which hides errors; update the reuse branch (where
existing_fbc_build is returned) and the fresh-build branch (the code around
where a new KonfluxFbcBuildRecord is produced) to check
existing_fbc_build.image_pullspec (and the equivalent new_record.image_pullspec)
and if it's falsy and self.force is not set, raise a clear exception (e.g.,
click.ClickException or RuntimeError) asking the user to re-run with --force or
handle the missing pullspec; if self.force is true allow returning the record as
before. Ensure you adjust both the return site that currently does
"existing_fbc_build.nvr, existing_fbc_build.image_pullspec or ''" and the
corresponding return for the fresh-build path so they do not silently return an
empty string.

679-682: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve registry ports when deriving the digest pullspec.

image_url.split(':')[0] truncates refs like registry:5000/ns/fbc:test-fbc-1.0.0-1 to just registry, so the emitted pullspec becomes invalid as soon as --image-repo points at a registry with a port.

Suggested fix
-        image_url = next((r['value'] for r in results if r['name'] == 'IMAGE_URL'), None)
-        image_digest = next((r['value'] for r in results if r['name'] == 'IMAGE_DIGEST'), None)
-        pullspec = f"{image_url.split(':')[0]}@{image_digest}" if image_url and image_digest else ""
+        image_url = next((r['value'] for r in results if r['name'] == 'IMAGE_URL'), None)
+        image_digest = next((r['value'] for r in results if r['name'] == 'IMAGE_DIGEST'), None)
+        if image_url and image_digest:
+            repo, _, name_with_tag = image_url.rpartition("/")
+            name = name_with_tag.split(":", 1)[0]
+            repository = f"{repo}/{name}" if repo else name
+            pullspec = f"{repository}@{image_digest}"
+        else:
+            pullspec = ""
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@doozer/doozerlib/cli/fbc.py` around lines 679 - 682, When building the digest
pullspec replace image_url.split(':')[0] with logic that strips only the tag
part (the last colon) so registry ports are preserved; update the pullspec
construction that uses image_url and image_digest (variables image_url,
image_digest, pullspec) to derive the name-without-tag via image_url.rsplit(':',
1)[0] (or equivalent) and then combine that with @{image_digest} only when both
values exist.
doozer/doozerlib/runtime.py (1)

96-96: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Align extra_vars with the format get_replace_vars() actually accepts.

Line 96 declares Runtime.extra_vars as dict[str, str], but Lines 398-407 iterate it as CLI-style KEY=VALUE strings. Any caller that follows the new annotation and passes {"FOO": "bar"} will now fail with Invalid --var format 'FOO' instead of overriding FOO.

💡 Suggested fix
-        self.extra_vars: dict[str, str] = {}
+        self.extra_vars: list[str] = []

Also applies to: 398-407

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@doozer/doozerlib/runtime.py` at line 96, Runtime.extra_vars is typed as
dict[str, str] but get_replace_vars() and the loop that processes CLI-style
KEY=VALUE strings (see iteration near lines 398-407) expect an iterable of
"KEY=VALUE" strings; change the Runtime.extra_vars declaration and
initialization in class Runtime to a list of strings (e.g., extra_vars:
list[str] = []) so callers can pass CLI-style entries and the existing parsing
logic in get_replace_vars()/the loop continues to work without raising "Invalid
--var format" errors.
pyartcd/pyartcd/fbc_util.py (1)

98-128: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't fail open when operator identity can't be determined.

If label extraction fails for digest pullspecs, this path assigns a different UNKNOWN-* value per pullspec, so same-operator FBCs land in separate groups and the related-image consistency check is skipped entirely. That turns a validation failure into a pass on exactly the safety gate this helper is supposed to enforce. Raise here once operator identity can't be established instead of generating unique placeholders.

🧰 Tools
🪛 Ruff (0.15.15)

[warning] 126-126: Do not catch blind exception: Exception

(BLE001)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pyartcd/pyartcd/fbc_util.py` around lines 98 - 128, The current logic in the
operator-extraction block of fbc_util.py assigns a per-pullspec UNKNOWN-...
value when it cannot determine an operator (using fbc_pullspec, labels, nvr and
tag), which allows same-operator FBCs to be split; instead, change both the
"else" branch and the except block to raise an exception (e.g., ValueError or
RuntimeError) with a clear message including fbc_pullspec and nvr/tag rather
than assigning operator = f"UNKNOWN-..."; keep the existing warning/error logs
but follow them by raising so caller code fails the validation when operator
identity cannot be established.
pyartcd/pyartcd/pipelines/gen_assembly_lp.py (1)

219-251: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Resolve the full basis chain before diffing against the parent assembly.

This only reads members.images from self.basis_assembly, but lightweight LP assemblies store delta-only overrides there. If the parent already inherits from another assembly, parent_operand_map is incomplete: --include can't swap inherited operands, and fresh FBC extraction will treat most inherited pins as new deltas. _resolve_parent_operands() needs to recursively merge basis.assembly ancestors into the full effective operand set first.

🧰 Tools
🪛 OpenGrep (1.22.0)

[ERROR] 232-232: yaml.load() without SafeLoader can execute arbitrary Python code. Use yaml.safe_load() or yaml.load(..., Loader=SafeLoader) instead.

(coderabbit.deserialization.python-yaml-unsafe-load)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pyartcd/pyartcd/pipelines/gen_assembly_lp.py` around lines 219 - 251,
_resolve_parent_operands currently only reads members_images from the single
basis_assembly and misses inherited operands; change it to recursively walk the
basis/parent chain in releases_config (use releases_config.get('releases') to
lookup ancestors), merging each ancestor's assembly.members.images into
operand_map so that descendant overrides win (child entries override parent
entries), and guard against cycles/too-deep recursion; preserve existing logging
and return operand_map as before.
pyartcd/pyartcd/pipelines/prepare_release_lp.py (1)

201-233: ⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Expand inherited assemblies before extracting operand NVRs.

This reads only the current assembly block, but LP inherited assemblies generated by gen-assembly-lp store just the delta in members.images. On those assemblies, prepare-release-lp will rebuild bundles/FBCs and create shipments for the override set only, silently dropping every inherited operand from the release. Resolve the basis.assembly chain into a full effective member list before _extract_operand_nvrs() runs.

🧰 Tools
🪛 OpenGrep (1.22.0)

[ERROR] 214-214: yaml.load() without SafeLoader can execute arbitrary Python code. Use yaml.safe_load() or yaml.load(..., Loader=SafeLoader) instead.

(coderabbit.deserialization.python-yaml-unsafe-load)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pyartcd/pyartcd/pipelines/prepare_release_lp.py` around lines 201 - 233, The
_load_assembly/_extract_operand_nvrs flow currently reads only the assembly
block's members.images, which misses inherited entries from a chain of
basis.assembly (LP generated delta assemblies); update _load_assembly to resolve
the full effective assembly by following the basis.assembly chain (reading
parent assemblies from releases.yml until no basis), merge each parent's
members.images into the child (preserving override semantics), then pass that
expanded assembly to _extract_operand_nvrs so it iterates the full effective
members.images list; reference the functions _load_assembly,
_extract_operand_nvrs and the basis.assembly / members.images keys when
implementing the merge.
pyartcd/tests/pipelines/test_gen_assembly_lp.py (1)

293-305: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

This test never exercises the single-pullspec code path.

_extract_nvrs_from_fbc() is patched out here, so the branch under test never runs; the only assertion is that the method object is callable. A regression that starts calling validate_fbc_related_images() for a single FBC would still pass. Patch the downstream extractor instead and actually invoke pipeline._extract_nvrs_from_fbc().

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pyartcd/tests/pipelines/test_gen_assembly_lp.py` around lines 293 - 305, The
test currently patches GenAssemblyLPPipeline._extract_nvrs_from_fbc so the
single-pullspec branch is never exercised; remove that patch and instead patch
the lower-level extractor function that _extract_nvrs_from_fbc calls (i.e., the
downstream extractor used inside GenAssemblyLPPipeline._extract_nvrs_from_fbc),
then call pipeline._extract_nvrs_from_fbc() directly and assert it returns the
expected mapping and that validate_fbc_related_images (patched as mock_validate)
was not called; ensure the test still uses the
fbc_pullspecs=["quay.io/test/fbc@sha256:single"] input and keeps
mock_validate.assert_not_called().

@ashwindasr
ashwindasr marked this pull request as draft June 5, 2026 20:15
@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 Jun 5, 2026
@ashwindasr ashwindasr added the tide/merge-method-squash Denotes a PR that should be squashed by tide when it merges. label Jun 24, 2026
@ashwindasr
ashwindasr force-pushed the cursor-lp-asm-abcd branch from 4197f22 to 76de4c3 Compare June 24, 2026 18:28
@openshift-ci

openshift-ci Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign thegreyd 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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pyartcd/pyartcd/pipelines/prepare_release_lp.py`:
- Line 660: The path normalization in prepare_release_lp.py is incorrectly using
rstrip(".git"), which strips any trailing combination of those characters
instead of only the .git suffix. Update the data_path handling in the release
preparation logic to use a suffix-only removal approach (such as removesuffix)
so repo URLs ending in characters like g, i, t, or . are not truncated
accidentally. Keep the fix localized to the data_path assignment near the
existing repository URL cleanup.
- Around line 556-559: The snapshot parsing logic in prepare_release_lp
currently assigns sorted(builds) to every Snapshot, which mixes NVRs across
Konflux applications. Update the loop over yaml.load_all(stdout) so each
Snapshot gets NVRs derived from that document’s own components or per-app build
set instead of the full builds input, using the existing Snapshot and
SnapshotSpec construction as the anchor for the fix.
🪄 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: openshift-eng/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 5c61eea3-5074-476b-8ab0-58ea0ae74926

📥 Commits

Reviewing files that changed from the base of the PR and between 4197f22 and 76de4c3.

📒 Files selected for processing (13)
  • doozer/doozerlib/cli/fbc.py
  • doozer/doozerlib/runtime.py
  • doozer/doozerlib/util.py
  • doozer/tests/cli/test_fbc.py
  • elliott/elliottlib/cli/find_builds_cli.py
  • pyartcd/pyartcd/__main__.py
  • pyartcd/pyartcd/fbc_util.py
  • pyartcd/pyartcd/pipelines/gen_assembly_lp.py
  • pyartcd/pyartcd/pipelines/prepare_release_lp.py
  • pyartcd/pyartcd/pipelines/release_from_fbc.py
  • pyartcd/tests/pipelines/test_gen_assembly_lp.py
  • pyartcd/tests/pipelines/test_prepare_release_lp.py
  • pyartcd/tests/test_fbc_util.py
🚧 Files skipped from review as they are similar to previous changes (7)
  • pyartcd/tests/test_fbc_util.py
  • pyartcd/pyartcd/main.py
  • doozer/doozerlib/runtime.py
  • doozer/tests/cli/test_fbc.py
  • doozer/doozerlib/util.py
  • pyartcd/tests/pipelines/test_gen_assembly_lp.py
  • doozer/doozerlib/cli/fbc.py

Comment thread pyartcd/pyartcd/pipelines/prepare_release_lp.py
Comment thread pyartcd/pyartcd/pipelines/prepare_release_lp.py Outdated
@ashwindasr ashwindasr changed the title Add gen-assembly-lp and prepare-release-lp pipelines for Layered Products (ART-19443) ART-19443: Add gen-assembly-lp and prepare-release-lp pipelines for Layered Products Jun 24, 2026
@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jun 24, 2026
@openshift-ci-robot

openshift-ci-robot commented Jun 24, 2026

Copy link
Copy Markdown

@ashwindasr: This pull request references ART-19443 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "5.0.0" version, but no target version was set.

Details

In response to this:

Summary

  • Adds gen-assembly-lp pipeline: extracts operand NVRs from FBC images, supports --include for swapping specific operand builds, --basis-assembly for lightweight inherited assemblies, and creates a PR to ocp-build-data with the assembly definition in releases.yml
  • Adds prepare-release-lp pipeline: reads a named assembly, checks for existing bundles before rebuilding (only builds missing ones), triggers FBC builds, and creates shipment MRs with release notes
  • Extracts shared FBC validation utilities into pyartcd/pyartcd/fbc_util.py (from release_from_fbc.py)
  • Registers both as artcd CLI commands (artcd gen-assembly-lp, artcd prepare-release-lp)
  • Updates doozer beta:fbc:rebase-and-build to return pullspecs alongside NVRs (needed for FBC consistency validation)
  • Adds olm_operator_nvrs to elliott find-builds --all-image-types JSON output (needed to scope bundle builds to assembly-pinned operators)
  • Disables strict assembly mode for non-openshift groups in doozer runtime (LP groups don't use brew events)
  • Moves STANDARD assembly check before major.minor extraction in get_release_name (LP group names don't match openshift-X.Y)

Context

ACM and MCE need the same two-phase assembly workflow that OCP has (gen-assembly -> prepare-release), adapted for FBC-driven Layered Product releases. This separates "what goes into the release" from "ship the release", enabling operand pinning, build swapping, and reproducible releases.

Test Runs

Normal Path: layered-products-gen-assembly -> openshift-eng/ocp-build-data#11426 -> layered-products-prepare-release

Changes to existing files

All changes to existing files are scoped to LP groups only and do not affect OCP pipelines:

  • doozer/doozerlib/cli/fbc.py: _rebase_and_build_fbc returns (nvr, pullspec) tuple; JSON output gains pullspecs key. Existing consumers use .get("nvrs") defensively — no breakage.
  • doozer/doozerlib/runtime.py: strict_mode = False for non-openshift-X.Y groups. For OCP groups, is_openshift_group = True so the new condition is or False — zero behavioral change.
  • doozer/doozerlib/util.py: STANDARD assembly check moved before isolate_major_minor_in_group. All existing callers pass openshift-X.Y groups where major/minor are always valid — no change in behavior.
  • elliott/elliottlib/cli/find_builds_cli.py: Adds olm_operator_nvrs key to return dict. Adding a key to a dict is backward compatible.
  • pyartcd/pyartcd/pipelines/release_from_fbc.py: Delegates extract_fbc_labels and validate_fbc_related_images to shared fbc_util.py. API surface preserved.

Test plan

  • pytest pyartcd/tests/pipelines/test_gen_assembly_lp.py — 25 tests pass
  • pytest pyartcd/tests/pipelines/test_prepare_release_lp.py — 26 tests pass
  • pytest pyartcd/tests/test_fbc_util.py — 8 tests pass
  • pytest doozer/tests/cli/test_fbc.py — 13 tests pass (updated mocks for new return type)
  • Manual dry-run with a real ACM FBC pullspec
  • Verify assembly YAML output matches expected format
  • Verify inherited assembly only records delta from parent

Summary by CodeRabbit

  • New Features

  • Added support for Layered Product release workflows, including generating assembly definitions and preparing release artifacts from named assemblies.

  • Improved FBC handling so release builds can reuse existing results and report image pull information more reliably.

  • Bug Fixes

  • Better support for non-OpenShift-style group names in release naming and initialization logic.

  • Added stronger validation for FBC inputs and related images to catch mismatches earlier.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@ashwindasr
ashwindasr marked this pull request as ready for review June 24, 2026 19:48
@openshift-ci openshift-ci Bot added needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. and removed do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. labels Jun 24, 2026
…ucts

Implements two new pipelines for ACM/MCE assembly-based releases:

- gen-assembly-lp: Extracts operand NVRs from FBC images, supports
  --include for swapping specific builds, and --basis-assembly for
  lightweight inherited assemblies. Creates a PR to ocp-build-data.

- prepare-release-lp: Reads a named assembly from releases.yml,
  checks for existing bundles before rebuilding, triggers FBC builds,
  and creates shipment MRs. Uses named assembly (not stream) for
  deterministic builds.

Includes unit tests (24 passing) and CLI registration.

Co-authored-by: Cursor <cursoragent@cursor.com>

rh-pre-commit.version: 2.3.2
rh-pre-commit.check-secrets: ENABLED
- Fix pullspec parsing to preserve registry ports (rsplit vs split)
- Raise RuntimeError on unknown operator identity in FBC validation
  instead of silently skipping the consistency check
- Fix test_extract_nvrs_skips_validation_for_single_pullspec to
  actually exercise the single-pullspec code path
- Document single-level inheritance limitation in docstrings

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

rh-pre-commit.version: 2.3.2
rh-pre-commit.check-secrets: ENABLED
rstrip(".git") strips any trailing combination of characters in the set
{'.', 'g', 'i', 't'}, which can mangle repo URLs whose names end in
those characters. removesuffix(".git") correctly removes only the exact
suffix.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

rh-pre-commit.version: 2.3.2
rh-pre-commit.check-secrets: ENABLED
When an operand image is swapped in an LP assembly, the existing bundle
still references the old image. The pipeline was reusing these stale
bundles because it only checked operator NVR existence, not operand
content. Now find-builds returns each bundle's operand_nvrs, and the
pipeline validates them against the assembly's pins before reusing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

rh-pre-commit.version: 2.3.2
rh-pre-commit.check-secrets: ENABLED
@ashwindasr
ashwindasr force-pushed the cursor-lp-asm-abcd branch from 719aecd to 2ecd07d Compare July 14, 2026 19:55
@openshift-ci openshift-ci Bot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jul 14, 2026
@openshift-ci

openshift-ci Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

@ashwindasr: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/security 2ecd07d link false /test security

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. tide/merge-method-squash Denotes a PR that should be squashed by tide when it merges.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants