Skip to content

Add inline dynamic plugins configuration to Backstage CR #7795

Add inline dynamic plugins configuration to Backstage CR

Add inline dynamic plugins configuration to Backstage CR #7795

name: Build PR Images (Slash Command)
on:
issue_comment:
types: [created]
permissions:
contents: read
pull-requests: write
statuses: write
concurrency:
group: build-images-${{ github.event.issue.number }}
# Must be false: the issue_comment trigger fires on ALL comments (not just /build-images),
# but the /build-images filter is only at the job level. With cancel-in-progress: true,
# any unrelated comment (e.g. from SonarQube, Renovate) on the same PR would cancel a
# running build, then skip the job because the comment doesn't match /build-images.
cancel-in-progress: false
env:
REGISTRY: ${{ vars.REGISTRY }}
jobs:
build-images:
if: |
github.event.issue.pull_request &&
startsWith(github.event.comment.body, '/build-images') &&
(github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER' || github.event.comment.author_association == 'COLLABORATOR')
name: Build and Push PR Images
runs-on: ubuntu-latest
steps:
- name: React to comment
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
with:
script: |
await github.rest.reactions.createForIssueComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: context.payload.comment.id,
content: 'rocket'
});
- name: Get PR details
id: pr
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
with:
script: |
const pr = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number
});
core.setOutput('sha', pr.data.head.sha);
core.setOutput('repo', pr.data.head.repo.full_name);
core.setOutput('number', context.issue.number);
- name: Checkout PR code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
fetch-depth: 0
repository: ${{ steps.pr.outputs.repo }}
ref: ${{ steps.pr.outputs.sha }}
# 2. PRIVILEGE PROTECTION: Do not persist credentials to disk
persist-credentials: false
- name: Setup Go
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7
with:
go-version-file: 'go.mod'
- name: Get version and SHA
# 3. ANTI-INJECTION: Map context to env vars before processing
env:
PR_SHA: ${{ steps.pr.outputs.sha }}
run: |
SHORT_SHA=$(git rev-parse --short "$PR_SHA")
echo "SHORT_SHA=$SHORT_SHA" >> $GITHUB_ENV
BASE_VERSION=$(grep -E "^VERSION \?=" Makefile | sed -r -e "s/.+= //")
echo "BASE_VERSION=$BASE_VERSION" >> $GITHUB_ENV
- name: Login to registry
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ vars.QUAY_USERNAME }}
password: ${{ secrets.QUAY_TOKEN }}
- name: Build operator image (hermetic)
uses: ./.github/actions/docker-build
with:
imageName: ${{ env.REGISTRY }}/${{ vars.REGISTRY_ORG }}/${{ vars.OPERATOR_IMAGE_NAME }}
imageTags: type=raw,value=${{ env.BASE_VERSION }}-pr-${{ steps.pr.outputs.number }}-${{ env.SHORT_SHA }}
platform: linux/amd64
skipArtifactUpload: 'true'
- name: Build bundle and catalog images, then push all
# We explicitly do NOT pass GH_TOKEN or RHDH_BOT_TOKEN here.
env:
REGISTRY_ORG: ${{ vars.REGISTRY_ORG }}
OPERATOR_IMAGE_NAME: ${{ vars.OPERATOR_IMAGE_NAME }}
CONTAINER_TOOL: podman
VERSION: ${{ env.BASE_VERSION }}-pr-${{ steps.pr.outputs.number }}-${{ env.SHORT_SHA }}
run: |
sudo apt-get -y update; sudo apt-get -y install skopeo podman
export REGISTRY_WITH_ORG=${REGISTRY}/${REGISTRY_ORG}
export IMAGE_TAG_BASE=${REGISTRY_WITH_ORG}/${OPERATOR_IMAGE_NAME}
set -ex
# Build bundle and catalog (operator was built hermetically above)
make bundle bundle-build
# Push operator and bundle images before catalog-build — opm render
# needs to pull the bundle image from the registry
for image in ${OPERATOR_IMAGE_NAME} ${OPERATOR_IMAGE_NAME}-bundle; do
podman push -q ${REGISTRY_WITH_ORG}/${image}:${VERSION} docker://${REGISTRY_WITH_ORG}/${image}:${VERSION}
done
BUNDLE_IMGS="${REGISTRY_WITH_ORG}/${OPERATOR_IMAGE_NAME}-bundle:${VERSION}" make -o bundle-push catalog-build
# Push catalog image and create PR-number tags for all images
podman push -q ${REGISTRY_WITH_ORG}/${OPERATOR_IMAGE_NAME}-catalog:${VERSION} docker://${REGISTRY_WITH_ORG}/${OPERATOR_IMAGE_NAME}-catalog:${VERSION}
for image in ${OPERATOR_IMAGE_NAME} ${OPERATOR_IMAGE_NAME}-bundle ${OPERATOR_IMAGE_NAME}-catalog; do
skopeo --insecure-policy copy --all docker://${REGISTRY_WITH_ORG}/${image}:${VERSION} docker://${REGISTRY_WITH_ORG}/${image}:${VERSION%-*}
done
- name: Comment image links in PR
if: success()
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
# 5. SCRIPT HARDENING: Pass data as environment variables
env:
BASE_VERSION: ${{ env.BASE_VERSION }}
PR_NUMBER: ${{ steps.pr.outputs.number }}
SHORT_SHA: ${{ env.SHORT_SHA }}
USER_LOGIN: ${{ github.event.comment.user.login }}
with:
script: |
const { BASE_VERSION, PR_NUMBER, SHORT_SHA, USER_LOGIN } = process.env;
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `✅ **PR images built successfully!**
Images are available for testing:
1. **Operator:** \`quay.io/rhdh-community/operator:${BASE_VERSION}-pr-${PR_NUMBER}-${SHORT_SHA}\`
2. **Bundle:** \`quay.io/rhdh-community/operator-bundle:${BASE_VERSION}-pr-${PR_NUMBER}-${SHORT_SHA}\`
3. **Catalog:** \`quay.io/rhdh-community/operator-catalog:${BASE_VERSION}-pr-${PR_NUMBER}-${SHORT_SHA}\`
Also available with PR number tag:
- \`quay.io/rhdh-community/operator:${BASE_VERSION}-pr-${PR_NUMBER}\`
- \`quay.io/rhdh-community/operator-bundle:${BASE_VERSION}-pr-${PR_NUMBER}\`
- \`quay.io/rhdh-community/operator-catalog:${BASE_VERSION}-pr-${PR_NUMBER}\`
<sub>Triggered by @${USER_LOGIN}</sub>`
});
- name: Comment on failure
if: failure()
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
env:
USER_LOGIN: ${{ github.event.comment.user.login }}
with:
script: |
const { USER_LOGIN } = process.env;
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `❌ **Image build failed**\n\nSee workflow run for details: ${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}\n\nTriggered by @${USER_LOGIN}`
});