Restore ability to build Containerfile(s) on PR#645
Restore ability to build Containerfile(s) on PR#645tarilabs wants to merge 13 commits intotrustyai-explainability:mainfrom
Conversation
…bility#631)" This reverts commit 67f38fc. Signed-off-by: tarilabs <matteo.mortari@gmail.com>
Signed-off-by: tarilabs <matteo.mortari@gmail.com>
Signed-off-by: tarilabs <matteo.mortari@gmail.com>
Reviewer's GuideAdds a conditional GitHub Actions workflow that, when specific labels are present on a PR, builds and pushes CI-scoped container images for the operator, LMES driver/job, and guardrails orchestrator to Quay, tagging them with the PR head SHA and posting a status comment back to the PR. Sequence diagram for PR-triggered CI image build and Quay publish workflowsequenceDiagram
actor Developer
participant GitHub
participant Workflow_build_images_on_PR
participant DockerEngine
participant Quay
participant PR_comment
Developer->>GitHub: Open PR or update PR
Developer->>GitHub: Apply labels needs-build and ok-to-test or lgtm or approved
GitHub-->>Workflow_build_images_on_PR: Trigger pull_request event
Workflow_build_images_on_PR-->>Workflow_build_images_on_PR: Check repository and label conditions
alt Conditions satisfied
Workflow_build_images_on_PR->>Workflow_build_images_on_PR: Set default env variables
opt LMES build requested (label needs-lmes-build)
Workflow_build_images_on_PR->>Workflow_build_images_on_PR: Override LMES env vars
end
opt Orchestrator build requested (label needs-orchestrator-build)
Workflow_build_images_on_PR->>Workflow_build_images_on_PR: Override orchestrator env vars
end
Workflow_build_images_on_PR->>Workflow_build_images_on_PR: Patch Dockerfile labels with expiry
Workflow_build_images_on_PR->>DockerEngine: docker login to Quay
Workflow_build_images_on_PR->>DockerEngine: docker build operator image (tag=PR head sha)
DockerEngine->>Quay: Push operator image
opt LMES build requested
Workflow_build_images_on_PR->>DockerEngine: docker build LMES driver image
DockerEngine->>Quay: Push LMES driver image
Workflow_build_images_on_PR->>DockerEngine: docker build LMES job image
DockerEngine->>Quay: Push LMES job image
end
opt Orchestrator build requested
Workflow_build_images_on_PR->>DockerEngine: docker build orchestrator image
DockerEngine->>Quay: Push orchestrator image
end
Workflow_build_images_on_PR->>PR_comment: Find existing status comment
Workflow_build_images_on_PR->>PR_comment: Create or update comment with image links
else Conditions not satisfied
Workflow_build_images_on_PR-->>GitHub: Job skipped
end
Flow diagram for conditional image builds based on PR labelsflowchart TD
A[PR event\nopened, labeled, synchronize, reopened] --> B{Repository is trustyai-service-operator?}
B -- No --> Z[Skip workflow]
B -- Yes --> C{PR has label needs-build?}
C -- No --> Z
C -- Yes --> D{PR has label ok-to-test or lgtm or approved?}
D -- No --> Z
D -- Yes --> E[Set default operator, LMES, orchestrator env vars]
E --> F{Label needs-lmes-build present?}
F -- Yes --> G[Override LMES tags and image names for CI]
F -- No --> H
G --> H{Label needs-orchestrator-build present?}
E --> H
H -- Yes --> I[Override orchestrator tag and image name for CI]
H -- No --> J
I --> J[Build and push operator image]
J --> K{Label needs-lmes-build present?}
K -- Yes --> L[Build and push LMES driver image]
L --> M[Build and push LMES job image]
M --> N
K -- No --> N[Build and push orchestrator image if requested]
N --> O[Create or update PR comment with image references]
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📝 WalkthroughWalkthroughAdds a new GitHub Actions workflow to build and push operator, LMES driver/job, and orchestrator container images on pull request events, with label gating, conditional builds, Quay authentication, and PR comments containing image links. (49 words) Changes
Sequence Diagram(s)sequenceDiagram
participant Dev as Developer
participant GH as GitHub (PR)
participant Actions as GitHub Actions Runner
participant Quay as Quay Registry
participant API as GitHub API (PR comments)
Dev->>GH: Open/Update PR (with labels)
GH->>Actions: Trigger workflow (build-images-on-pr)
Actions->>Actions: Determine build scope, set image tags (operator SHA), set env
Actions->>Quay: Authenticate
Actions->>Quay: Build & push operator image
alt needs-lmes-build
Actions->>Quay: Build & push LMES driver & job images
end
alt needs-orchestrator-build
Actions->>Quay: Build & push orchestrator image
end
Actions->>API: Create or update PR comment with image links
API->>GH: Display comment on PR
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Signed-off-by: tarilabs <matteo.mortari@gmail.com>
There was a problem hiding this comment.
Hey - I've found 4 issues, and left some high level feedback:
- The environment variable used for the image name is inconsistent (you set
IMAGE_NAMEbut later referenceOPERATOR_IMAGE_NAMEin logs and build/push steps), which will result in empty or incorrect tags; align these to a single variable. - Several docker-related steps (login/build/push) are not guarded by
if: env.BUILD_CONTEXT == 'ci', so they may execute with unset environment variables whenBUILD_CONTEXTis not defined; consider adding the same condition or explicitly initializingBUILD_CONTEXT. - The LMES/orchestrator steps check for
env.BUILD_CONTEXT == 'main'or'tag', but these contexts are never set in this workflow, and the PR comment useshttps://${{ env.* }}URLs that won’t produce valid links for quay images; you may want to simplify the conditions and adjust the links to plain text or correct quay repository URLs.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The environment variable used for the image name is inconsistent (you set `IMAGE_NAME` but later reference `OPERATOR_IMAGE_NAME` in logs and build/push steps), which will result in empty or incorrect tags; align these to a single variable.
- Several docker-related steps (login/build/push) are not guarded by `if: env.BUILD_CONTEXT == 'ci'`, so they may execute with unset environment variables when `BUILD_CONTEXT` is not defined; consider adding the same condition or explicitly initializing `BUILD_CONTEXT`.
- The LMES/orchestrator steps check for `env.BUILD_CONTEXT == 'main'` or `'tag'`, but these contexts are never set in this workflow, and the PR comment uses `https://${{ env.* }}` URLs that won’t produce valid links for quay images; you may want to simplify the conditions and adjust the links to plain text or correct quay repository URLs.
## Individual Comments
### Comment 1
<location> `.github/workflows/build-images-on-PR.yaml:42` </location>
<code_context>
+ if: env.BUILD_CONTEXT == 'ci'
+ run: |
+ echo "OPERATOR_TAG=${{ github.event.pull_request.head.sha }}" >> $GITHUB_ENV
+ echo "IMAGE_NAME=quay.io/trustyai/trustyai-service-operator-ci" >> $GITHUB_ENV
+
+ - name: Set CI environment - LMES
</code_context>
<issue_to_address>
**issue (bug_risk):** Environment variable name used for the operator image is inconsistent and will result in an empty tag reference.
The workflow sets `IMAGE_NAME`, but later steps reference `OPERATOR_IMAGE_NAME` (e.g., in the log and `docker build -t ${{ env.OPERATOR_IMAGE_NAME }}:${{ env.OPERATOR_TAG }}`). Because `OPERATOR_IMAGE_NAME` is never defined, those steps will use an empty image name and fail. Align the variable usage by either exporting `OPERATOR_IMAGE_NAME` here or updating later steps to use `IMAGE_NAME` consistently.
</issue_to_address>
### Comment 2
<location> `.github/workflows/build-images-on-PR.yaml:74-75` </location>
<code_context>
+ - name: Put expiry date on CI-tagged image
+ if: env.BUILD_CONTEXT == 'ci'
+ run: sed -i 's#summary="odh-trustyai-service-operator\"#summary="odh-trustyai-service-operator" \\ \n quay.expires-after=7d#' Dockerfile
+ - name: Log in to Quay
+ run: docker login -u ${{ secrets.QUAY_ROBOT_USERNAME }} -p ${{ secrets.QUAY_ROBOT_SECRET }} quay.io
+ - name: Build main image
+ run: docker build -t ${{ env.OPERATOR_IMAGE_NAME }}:${{ env.OPERATOR_TAG }} .
</code_context>
<issue_to_address>
**issue (bug_risk):** Docker login and image build/push steps should be gated on the CI context to avoid failures on PRs without secrets.
The Quay login and main image build/push steps are not conditioned on `env.BUILD_CONTEXT == 'ci'`, so they can still run on PRs without the necessary secrets or env vars and cause CI failures. Please gate these steps with the same CI-context condition (or equivalent) so they only execute when the required secrets are available.
</issue_to_address>
### Comment 3
<location> `.github/workflows/build-images-on-PR.yaml:124-130` </location>
<code_context>
+ body: |
+ PR image build and manifest generation completed successfully!
+
+ 📦 [PR image](https://${{ env.OPERATOR_IMAGE_NAME }}:${{ env.OPERATOR_TAG }}): `${{ env.OPERATOR_IMAGE_NAME }}:${{ env.OPERATOR_TAG }}`
+
+ 📦 [LMES driver image](https://${{ env.LMES_DRIVER_IMAGE_NAME }}:${{ env.LMES_DRIVER_TAG }}): `${{ env.LMES_DRIVER_IMAGE_NAME }}:${{ env.LMES_DRIVER_TAG }}`
+
+ 📦 [LMES job image](https://${{ env.LMES_JOB_IMAGE_NAME }}:${{ env.LMES_JOB_TAG }}): `${{ env.LMES_JOB_IMAGE_NAME }}:${{ env.LMES_JOB_TAG }}`
+
+ 📦 [Guardrails orchestrator image](https://${{ env.ORCH_IMAGE_NAME }}:${{ env.ORCH_TAG }}): `${{ env.ORCH_IMAGE_NAME }}:${{ env.ORCH_TAG }}`
</code_context>
<issue_to_address>
**suggestion (bug_risk):** The Quay image links use an invalid URL format and likely won’t be clickable.
These URLs use the `image:tag` form as a hostname and will not resolve. Keep `image:tag` in the inline code, but point the markdown links to real Quay web URLs instead (for example, `https://quay.io/repository/<org>/<repo>?tab=tags` or a tag-specific page) while still rendering `${{ env.* }}:${{ env.* }}` as the visible text.
</issue_to_address>
### Comment 4
<location> `.github/workflows/build-images-on-PR.yaml:82-91` </location>
<code_context>
+ - name: Build LMES driver image
</code_context>
<issue_to_address>
**suggestion:** Conditions referencing `BUILD_CONTEXT == 'main'` and `'tag'` appear unused in this PR-focused workflow.
In this workflow `BUILD_CONTEXT` is only ever set to `'ci'`, so any `if:` conditions checking for `'main'` or `'tag'` will never be true and act as dead code. If main/tag builds are handled elsewhere, consider dropping those checks and relying on the label-based conditions. If this workflow should handle main/tag as well, make sure `BUILD_CONTEXT` is actually set to those values somewhere in this file.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In @.github/workflows/build-images-on-PR.yaml:
- Around line 121-130: The PR comment always lists all four images causing
broken links when LMES/orchestrator weren't built; update the workflow to only
emit the LMES and orchestrator lines when their corresponding build labels are
present by checking the same conditions used to set the env vars (e.g.,
needs-lmes-build, needs-orchestrator-build) or by guarding the comment
generation step with conditional logic; specifically, modify the step that
constructs the comment body to omit the LMES lines referencing
LMES_DRIVER_IMAGE_NAME and LMES_JOB_IMAGE_NAME unless needs-lmes-build is true,
and omit the Guardrails line referencing ORCH_IMAGE_NAME unless
needs-orchestrator-build is true (leave the OPERATOR_IMAGE_NAME line unchanged).
- Around line 38-42: The workflow sets IMAGE_NAME but later references
OPERATOR_IMAGE_NAME, causing an undefined env var; update the "Set CI
environment" step to export OPERATOR_IMAGE_NAME instead (or export both
IMAGE_NAME and OPERATOR_IMAGE_NAME) so the referenced env.OPERATOR_IMAGE_NAME
used by steps referencing OPERATOR_IMAGE_NAME (seen in subsequent build/push
steps) is defined and contains the same
quay.io/trustyai/trustyai-service-operator-ci value (and keep
OPERATOR_TAG/OPERATOR_TAG usage unchanged).
- Around line 59-68: The "Log reference variables" step is injecting
github.head_ref directly into the inline run script (github.head_ref) which is
attacker-controlled; change the step to pass github.head_ref via an environment
variable (e.g., HEAD_REF: ${{ github.head_ref }}) or set it with echoing from
the env and then reference the env var inside run (e.g., echo "$HEAD_REF")
instead of interpolating ${{ github.head_ref }} directly; update the step that
logs variables (step name "Log reference variables") to use the environment
variable for github.head_ref and any other user-controllable refs before
echoing.
🧹 Nitpick comments (3)
.github/workflows/build-images-on-PR.yaml (3)
74-79: Build/push steps for the main operator image lack aBUILD_CONTEXTguard.Lines 74–79 run unconditionally (no
if), unlike the checkout and env-setting steps. Per the comment on Line 19, the intent is to guard against futureon:additions—but these steps would run with emptyOPERATOR_IMAGE_NAME/OPERATOR_TAGifBUILD_CONTEXTis not set. Consider adding the sameif: env.BUILD_CONTEXT == 'ci'guard for consistency.
81-103: Dead conditions:BUILD_CONTEXT == 'main'andBUILD_CONTEXT == 'tag'are unreachable.Since this workflow only triggers on
pull_requestevents andBUILD_CONTEXTis only ever set to'ci', theenv.BUILD_CONTEXT == 'main'andenv.BUILD_CONTEXT == 'tag'branches in these conditionals will never be true. This looks like a leftover from the original multi-trigger workflow. Consider removing these dead branches to avoid confusion.
74-75: Use--password-stdinfordocker logininstead of passing the password via CLI argument.Passing the password with
-pcan expose it in process listings. Prefer piping it via stdin.🔒 Proposed fix
- name: Log in to Quay - run: docker login -u ${{ secrets.QUAY_ROBOT_USERNAME }} -p ${{ secrets.QUAY_ROBOT_SECRET }} quay.io + run: echo "${{ secrets.QUAY_ROBOT_SECRET }}" | docker login -u ${{ secrets.QUAY_ROBOT_USERNAME }} --password-stdin quay.io
Signed-off-by: tarilabs <matteo.mortari@gmail.com>
Signed-off-by: tarilabs <matteo.mortari@gmail.com>
Signed-off-by: tarilabs <matteo.mortari@gmail.com>
Signed-off-by: tarilabs <matteo.mortari@gmail.com>
Signed-off-by: tarilabs <matteo.mortari@gmail.com>
Signed-off-by: tarilabs <matteo.mortari@gmail.com>
Signed-off-by: tarilabs <matteo.mortari@gmail.com>
Signed-off-by: tarilabs <matteo.mortari@gmail.com>
There was a problem hiding this comment.
Hey - I've found 2 issues, and left some high level feedback:
- The
sedreplacement used to injectquay.expires-after=7dintoDockerfilerelies on a very specificsummaryline format and may be brittle to future edits; consider using a dedicatedLABELline or build-arg/ENV to add the expiry label in a less fragile way. - The PR comment builds image links as
https://${{ env.OPERATOR_IMAGE_NAME }}:${{ env.OPERATOR_TAG }}which is not a valid Quay URL; it would be more useful to construct proper repository URLs (e.g.https://quay.io/repository/...) so they are clickable and point to the image page. - For
docker login, using--password-stdin(e.g.echo ${{ secrets.QUAY_ROBOT_SECRET }} | docker login -u ... --password-stdin) is generally safer and avoids putting the password directly on the command line.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The `sed` replacement used to inject `quay.expires-after=7d` into `Dockerfile` relies on a very specific `summary` line format and may be brittle to future edits; consider using a dedicated `LABEL` line or build-arg/ENV to add the expiry label in a less fragile way.
- The PR comment builds image links as `https://${{ env.OPERATOR_IMAGE_NAME }}:${{ env.OPERATOR_TAG }}` which is not a valid Quay URL; it would be more useful to construct proper repository URLs (e.g. `https://quay.io/repository/...`) so they are clickable and point to the image page.
- For `docker login`, using `--password-stdin` (e.g. `echo ${{ secrets.QUAY_ROBOT_SECRET }} | docker login -u ... --password-stdin`) is generally safer and avoids putting the password directly on the command line.
## Individual Comments
### Comment 1
<location> `.github/workflows/build-images-on-PR.yaml:69-73` </location>
<code_context>
+ echo "GUARDRAILS ORCH IMAGE AT: ${{ env.ORCH_IMAGE_NAME }}:${{ env.ORCH_TAG }}"
+
+ # Run docker commands
+ - name: Put expiry date on CI-tagged image
+ run: sed -i 's#summary="odh-trustyai-service-operator\"#summary="odh-trustyai-service-operator" \\ \n quay.expires-after=7d#' Dockerfile
+ - name: Log in to Quay
+ run: docker login -u ${{ secrets.QUAY_ROBOT_USERNAME }} -p ${{ secrets.QUAY_ROBOT_SECRET }} quay.io
</code_context>
<issue_to_address>
**suggestion (bug_risk):** The `sed` replacement is brittle and may be error-prone across Dockerfile changes.
This command depends on an exact string match (including the escaped quote) and injects a newline and extra content into that same line. Small Dockerfile changes (whitespace, label order, quote style) will cause it to do nothing without failing, so the expiry label may be missing. Consider either adding a separate `LABEL quay.expires-after=7d` via a small patch/append step, or matching on the label key instead of the full value to make this more resilient to future edits.
```suggestion
# Run docker commands
- name: Put expiry date on CI-tagged image
run: echo 'LABEL quay.expires-after=7d' >> Dockerfile
- name: Log in to Quay
run: docker login -u ${{ secrets.QUAY_ROBOT_USERNAME }} -p ${{ secrets.QUAY_ROBOT_SECRET }} quay.io
```
</issue_to_address>
### Comment 2
<location> `.github/workflows/build-images-on-PR.yaml:72-73` </location>
<code_context>
+ # Run docker commands
+ - name: Put expiry date on CI-tagged image
+ run: sed -i 's#summary="odh-trustyai-service-operator\"#summary="odh-trustyai-service-operator" \\ \n quay.expires-after=7d#' Dockerfile
+ - name: Log in to Quay
+ run: docker login -u ${{ secrets.QUAY_ROBOT_USERNAME }} -p ${{ secrets.QUAY_ROBOT_SECRET }} quay.io
+ - name: Build main image
+ run: docker build -t ${{ env.OPERATOR_IMAGE_NAME }}:${{ env.OPERATOR_TAG }} .
</code_context>
<issue_to_address>
**🚨 suggestion (security):** Consider using `--password-stdin` for `docker login` to reduce secret exposure risk.
Using `-p` exposes the password on the process command line, which can be visible via process inspection or logs. Prefer piping the secret instead, e.g.: `echo "$QUAY_ROBOT_SECRET" | docker login -u "$QUAY_ROBOT_USERNAME" --password-stdin quay.io`, which matches Docker’s recommended practice and keeps the secret out of the argument list.
```suggestion
- name: Log in to Quay
run: echo "${{ secrets.QUAY_ROBOT_SECRET }}" | docker login -u "${{ secrets.QUAY_ROBOT_USERNAME }}" --password-stdin quay.io
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
Signed-off-by: tarilabs <matteo.mortari@gmail.com> Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In @.github/workflows/build-images-on-PR.yaml:
- Around line 126-135: The PR comment links use the invalid "https://...:tag"
form; update the notification body (the `body` template) to build Quay web URLs
using the repository path with a query tag parameter instead: for each image
replace `https://${{ env.<IMAGE_NAME> }}:${{ env.<TAG> }}` with
`https://quay.io/repository/${{ env.<IMAGE_NAME> }}?tag=${{ env.<TAG> }}` (apply
for OPERATOR_IMAGE_NAME/OPERATOR_TAG, LMES_DRIVER_IMAGE_NAME/LMES_DRIVER_TAG,
LMES_JOB_IMAGE_NAME/LMES_JOB_TAG, ORCH_IMAGE_NAME/ORCH_TAG) while keeping the
displayed inline text `${{ env.<IMAGE_NAME> }}:${{ env.<TAG> }}` unchanged.
Ensure the substitutions are made in the `body` block where the 📦 links are
defined.
🧹 Nitpick comments (2)
.github/workflows/build-images-on-PR.yaml (2)
72-73: Use--password-stdinfordocker loginto avoid exposing the secret in the process argument list.Even though GitHub Actions masks secrets in logs, passing
-pexposes the value in/proc/<pid>/cmdlineon the runner.🔒 Proposed fix
- name: Log in to Quay - run: docker login -u ${{ secrets.QUAY_ROBOT_USERNAME }} -p ${{ secrets.QUAY_ROBOT_SECRET }} quay.io + run: echo "${{ secrets.QUAY_ROBOT_ROBOT_SECRET }}" | docker login -u ${{ secrets.QUAY_ROBOT_USERNAME }} --password-stdin quay.ioNote: double-check the secret name — I kept the original
QUAY_ROBOT_SECRET.Corrected version:
- name: Log in to Quay - run: docker login -u ${{ secrets.QUAY_ROBOT_USERNAME }} -p ${{ secrets.QUAY_ROBOT_SECRET }} quay.io + run: echo "${{ secrets.QUAY_ROBOT_SECRET }}" | docker login -u ${{ secrets.QUAY_ROBOT_USERNAME }} --password-stdin quay.io
70-71: Fragilesedpattern — silently no-ops if the Dockerfile LABEL line changes.The match string is tightly coupled to the exact quoting and whitespace in the Dockerfile. If the
LABELline is reformatted, the expiry annotation won't be injected and the CI image will persist indefinitely. Consider appending the label instead (like the LMES/orchestrator steps do withecho >> Dockerfile) or at minimum adding a guard that fails if the substitution didn't apply.💡 Alternative: append the label, consistent with the other Dockerfiles
- name: Put expiry date on CI-tagged image - run: sed -i 's#summary="odh-trustyai-service-operator\"#summary="odh-trustyai-service-operator" \\ \n quay.expires-after=7d#' Dockerfile + run: echo 'LABEL quay.expires-after=7d' >> DockerfileThis mirrors lines 82, 93, and 104 and is immune to upstream Dockerfile formatting changes.
|
@tarilabs: The following test failed, say
Full PR test history. Your PR dashboard. DetailsInstructions 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. |
Helps when developing on Mac and testing against an usual Amd64 cluster
Kept commit history so the operations to restore can be better identified
Will need that github repo contains:
secrets.QUAY_ROBOT_USERNAMEsecrets.QUAY_ROBOT_SECRETwhich appears to be still existing
Summary by Sourcery
Add a GitHub Actions workflow to build and push CI container images for pull requests based on labels and post the resulting image references as a PR comment.
Build:
CI:
Summary by CodeRabbit