Skip to content

chore(backstage): enable E2E coverage (e2e-test-utils 2.1.0) #13435

chore(backstage): enable E2E coverage (e2e-test-utils 2.1.0)

chore(backstage): enable E2E coverage (e2e-test-utils 2.1.0) #13435

Workflow file for this run

name: Pull Request Actions
on:
issue_comment:
types: [created, edited]
workflow_dispatch:
inputs:
pr-number:
description: PR number to act on
type: string
required: true
command-name:
description: Command to execute (publish, update-versions, update-commit, smoketest, override-backstage)
type: string
required: true
smoketest-tag:
description: Optional RHDH tag override for `/smoketest <tag>`
type: string
required: false
jobs:
parse:
runs-on: ubuntu-latest
name: Parse PR Comment
if: >
github.event_name == 'workflow_dispatch' || (
github.triggering_actor != 'openshift-ci[bot]' &&
github.triggering_actor != 'sonarqubecloud[bot]' &&
github.event.issue.pull_request && (
contains(github.event.comment.body, '/publish') ||
contains(github.event.comment.body, '/update-versions') ||
contains(github.event.comment.body, '/update-commit') ||
contains(github.event.comment.body, '/smoketest') ||
contains(github.event.comment.body, '/override-backstage')))
outputs:
command-name: ${{ steps.extract.outputs.command-name }}
error-message: ${{ steps.extract.outputs.error-message }}
pr-number: ${{ steps.extract.outputs.pr-number }}
smoketest-tag: ${{ steps.extract.outputs.smoketest-tag }}
steps:
- name: Extract command from comment
id: extract
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const SMOKETEST_TAG_RE = /^(?:pr-[0-9]+(?:-[0-9a-f]{7,40})?|next(?:-[0-9]+\.[0-9]+-[0-9a-f]{7,40}|-[0-9a-f]{7,40})?)$/;
const SMOKETEST_HELP = 'Use /smoketest or /smoketest <tag>. Allowed tags: pr-<digits>, pr-<digits>-<hash>, next, next-<major>.<minor>-<hash>, next-<hash>.';
core.setOutput('smoketest-tag', '');
if (context.eventName === 'workflow_dispatch') {
const commandName = '${{ inputs.command-name }}';
const allowed = new Set(['publish', 'update-versions', 'update-commit', 'smoketest', 'override-backstage']);
if (!allowed.has(commandName)) {
const errorMsg = `Invalid command: ${commandName}`;
core.setOutput('error-message', errorMsg);
core.setOutput('command-name', '');
core.setFailed(errorMsg);
return;
}
core.setOutput('command-name', commandName);
core.setOutput('error-message', '');
core.setOutput('pr-number', '${{ inputs.pr-number }}');
const smoketestTag = String('${{ inputs.smoketest-tag }}').trim();
if (smoketestTag !== '' && commandName !== 'smoketest') {
const errorMsg = 'Input smoketest-tag is only valid with command-name=smoketest.';
core.setOutput('error-message', errorMsg);
core.setOutput('command-name', '');
core.setFailed(errorMsg);
return;
}
if (commandName === 'smoketest') {
if (smoketestTag !== '' && !SMOKETEST_TAG_RE.test(smoketestTag)) {
const errorMsg = `Invalid smoketest tag: ${smoketestTag}. ${SMOKETEST_HELP}`;
core.setOutput('error-message', errorMsg);
core.setOutput('command-name', '');
core.setFailed(errorMsg);
return;
}
core.setOutput('smoketest-tag', smoketestTag);
}
return;
}
core.setOutput('pr-number', String(context.issue.number));
const raw = context.payload.comment?.body ?? '';
const lines = String(raw)
.split(/\r?\n/)
.map(l => l.trim())
.filter(l => l.length > 0);
const allowed = new Set(['/publish', '/update-versions', '/update-commit', '/override-backstage']);
const matchingCommands = [];
let smoketestTag = '';
let malformedSmoketestCommand = '';
for (const line of lines) {
if (allowed.has(line)) {
matchingCommands.push(line);
continue;
}
if (line.startsWith('/smoketest')) {
const smoketestMatch = line.match(/^\/smoketest(?:\s+(\S+))?$/);
if (!smoketestMatch) {
malformedSmoketestCommand = line;
break;
}
const parsedTag = smoketestMatch[1] ?? '';
if (parsedTag !== '' && !SMOKETEST_TAG_RE.test(parsedTag)) {
malformedSmoketestCommand = line;
break;
}
matchingCommands.push('/smoketest');
smoketestTag = parsedTag;
}
}
if (malformedSmoketestCommand) {
const errorMsg = `Invalid smoketest command: "${malformedSmoketestCommand}". ${SMOKETEST_HELP}`;
core.setOutput('error-message', errorMsg);
core.setOutput('command-name', '');
core.setFailed(errorMsg);
return;
}
if (matchingCommands.length > 1) {
const errorMsg = `Multiple commands found in comment: ${matchingCommands.join(', ')}. Please use only one command per comment.`;
core.setOutput('error-message', errorMsg);
core.setOutput('command-name', '');
core.setFailed(errorMsg);
return;
}
if (matchingCommands.length === 0) {
core.notice('No command found in comment – cancelling workflow run');
await github.rest.actions.cancelWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.runId,
});
return;
}
const firstMatching = matchingCommands[0] || '';
core.setOutput('command-name', firstMatching.startsWith('/') ? firstMatching.slice(1) : firstMatching);
core.setOutput('smoketest-tag', firstMatching === '/smoketest' ? smoketestTag : '');
core.setOutput('error-message', '');
add_error_comment:
needs:
- parse
concurrency:
group: add_error_comment-${{ github.ref_name }}-${{ needs.parse.outputs.pr-number }}
cancel-in-progress: false
permissions:
pull-requests: write
if: always() && needs.parse.outputs.error-message != ''
runs-on: ubuntu-latest
steps:
- name: Add error comment
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
INPUT_ERROR_MESSAGE: ${{ needs.parse.outputs.error-message }}
INPUT_PR_NUMBER: ${{ needs.parse.outputs.pr-number }}
with:
script: |
const errorMessage = core.getInput('error_message');
const prNumber = Number(core.getInput('pr_number'));
const body = `**Error**: ${errorMessage}\n\nValid commands are:\n- \`/publish\` - Publish dynamic plugin images\n- \`/update-versions\` - Update versions from release branch\n- \`/update-commit\` - Update commit from automatic discovery\n- \`/override-backstage\` - Override Backstage version compatibility\n- \`/smoketest\` - Run smoke tests with default image\n- \`/smoketest <tag>\` - Run smoke tests with \`quay.io/rhdh-community/rhdh:<tag>\`\n - Allowed tags: \`pr-4907\`, \`pr-4929-90eff067\`, \`next\`, \`next-1.10-244a2755\`, \`next-8a0d43e7\``;
await github.rest.issues.createComment({
issue_number: prNumber,
owner: context.repo.owner,
repo: context.repo.repo,
body: body
});
prepare:
runs-on: ubuntu-latest
name: Prepare
needs:
- parse
concurrency:
group: prepare-${{ github.ref_name }}-${{ needs.parse.outputs.pr-number }}
cancel-in-progress: false
if: needs.parse.outputs.command-name != ''
outputs:
target-branch: ${{ steps.get-branch.outputs.target-branch }}
overlay-branch: ${{ steps.get-branch.outputs.overlay-branch }}
overlay-repo: ${{ steps.get-branch.outputs.overlay-repo }}
overlay-commit: ${{ steps.get-branch.outputs.overlay-commit }}
workspace: ${{ steps.get-branch.outputs.workspace }}
pr-number: ${{ steps.get-branch.outputs.pr-number }}
rhdh-tag: ${{ needs.parse.outputs.smoketest-tag }}
permissions:
statuses: write
steps:
- name: Get PR branch data
id: get-branch
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
INPUT_COMMAND_NAME: ${{ needs.parse.outputs.command-name }}
INPUT_PR_NUMBER: ${{ needs.parse.outputs.pr-number }}
with:
script: |
const prNumber = Number(core.getInput('pr_number'));
const currentPullRequest = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber
});
const targetBranch = currentPullRequest.data.base.ref;
core.setOutput('target-branch', targetBranch);
const prBranch = currentPullRequest.data.head.ref;
core.setOutput('overlay-branch', prBranch);
const prRepo = currentPullRequest.data.head.repo.full_name;
core.setOutput('overlay-repo', prRepo);
core.setOutput('pr-number', prNumber);
const prCommit = currentPullRequest.data.head.sha;
core.setOutput('overlay-commit', prCommit);
let workspace = '';
const matches = prBranch.match(/^workspaces\/release-.+__(.+)$/);
if (matches && matches.length == 2) {
workspace = `workspaces/${matches[1]}`;
} else {
const prFiles = await github.rest.pulls.listFiles({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber
});
const workspaces = [ ... new Set(prFiles.data
.map(f => f.filename.match(/^workspaces\/([^\/]+)\/.*/))
.filter(match => match)
.map(match => match[1])
)];
if (workspaces.length === 1) {
workspace =`workspaces/${workspaces[0]}`;
}
}
core.setOutput('workspace', workspace);
if (workspace === '') {
return;
}
const workflowRun = await github.rest.actions.getWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: '${{ github.run_id }}',
});
await github.rest.repos.createCommitStatus({
owner: context.repo.owner,
repo: context.repo.repo,
sha: prCommit,
description: '${{ github.workflow }}',
state: 'pending',
target_url: workflowRun.data.html_url,
context: core.getInput('command_name')
});
publish:
name: Publish PR
needs:
- parse
- prepare
concurrency:
group: publish-${{ github.ref_name }}-${{ needs.parse.outputs.pr-number }}
cancel-in-progress: true
if: |
needs.parse.outputs.command-name == 'publish' &&
needs.prepare.outputs.workspace != ''
uses: ./.github/workflows/auto-publish-pr.yaml
with:
pr-number: ${{ needs.prepare.outputs.pr-number }}
permissions:
contents: write
attestations: write
packages: write
id-token: write
statuses: write
pull-requests: write
triggerSmokeTests:
name: Trigger Smoke Tests
needs:
- parse
- prepare
- publish
if: >
always() &&
needs.prepare.outputs.workspace != '' &&
((needs.parse.outputs.command-name == 'publish' && needs.publish.result == 'success') ||
needs.parse.outputs.command-name == 'smoketest')
runs-on: ubuntu-latest
permissions:
actions: write
steps:
- name: Dispatch workspace smoke tests
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
await github.rest.actions.createWorkflowDispatch({
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: 'workspace-tests.yaml',
ref: '${{ github.ref_name }}',
inputs: {
'workspace': '${{ needs.prepare.outputs.workspace }}',
'overlay-branch': '${{ needs.prepare.outputs.overlay-branch }}',
'overlay-repo': '${{ needs.prepare.outputs.overlay-repo }}',
'overlay-commit': '${{ needs.prepare.outputs.overlay-commit }}',
'pr-number': String(${{ needs.prepare.outputs.pr-number }}),
'target-branch': '${{ needs.prepare.outputs.target-branch }}',
'rhdh-tag': '${{ needs.prepare.outputs.rhdh-tag }}',
},
});
add_no_workspace_comment:
needs:
- parse
- prepare
concurrency:
group: add_no_workspace_comment-${{ github.ref_name }}-${{ needs.parse.outputs.pr-number }}
cancel-in-progress: false
permissions:
statuses: write
pull-requests: write
if: always() && needs.prepare.outputs.overlay-branch != '' && needs.prepare.outputs.workspace == ''
runs-on: ubuntu-latest
steps:
- name: Report skipped command
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
INPUT_OVERLAY_COMMIT: ${{ needs.prepare.outputs.overlay-commit }}
INPUT_COMMAND_NAME: ${{ needs.parse.outputs.command-name }}
INPUT_PR_NUMBER: ${{ needs.prepare.outputs.pr-number }}
with:
script: |
const prNumber = Number(core.getInput('pr_number'));
const workflowRun = await github.rest.actions.getWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: '${{ github.run_id }}'
});
await github.rest.repos.createCommitStatus({
owner: context.repo.owner,
repo: context.repo.repo,
sha: core.getInput('overlay_commit'),
description: '${{ github.workflow }}',
state: 'success',
target_url: workflowRun.data.html_url,
context: core.getInput('command_name'),
});
const body = `[PR action (\`/${core.getInput('command_name')}\`)](${workflowRun.data.html_url}) cancelled: PR doesn't touch only 1 workspace.`;
await github.rest.issues.createComment({
issue_number: prNumber,
owner: context.repo.owner,
repo: context.repo.repo,
body: body
})
updatePRWithVersions:
name: Update versions on PR from release branch
needs:
- parse
- prepare
concurrency:
group: updatePRWithVersions-${{ github.ref_name }}-${{ needs.parse.outputs.pr-number }}
cancel-in-progress: true
if: needs.parse.outputs.command-name == 'update-versions'
uses: ./.github/workflows/update-prs-with-release-branch-commits.yaml
with:
force: true
pr: ${{ needs.prepare.outputs.pr-number }}
release-branch: ${{ needs.prepare.outputs.target-branch }}
permissions:
actions: write
contents: write
pull-requests: write
attestations: write
packages: write
id-token: write
statuses: write
updatePRWithCommit:
name: Update commit on PR from automatic discovery
needs:
- parse
- prepare
concurrency:
group: updatePRWithCommit-${{ github.ref_name }}-${{ needs.parse.outputs.pr-number }}
cancel-in-progress: true
if: needs.parse.outputs.command-name == 'update-commit'
uses: ./.github/workflows/update-plugins-repo-refs.yaml
with:
single-branch: ${{ needs.prepare.outputs.target-branch }}
allow-workspace-addition: false
pr-to-update: ${{ needs.prepare.outputs.pr-number }}
workspace-path: ${{ needs.prepare.outputs.workspace }}
permissions:
actions: write
contents: write
pull-requests: write
issues: read
attestations: write
packages: write
id-token: write
statuses: write
add_update_versions_completion_comment:
needs:
- parse
- prepare
- updatePRWithVersions
concurrency:
group: add_update_versions_completion_comment-${{ github.ref_name }}-${{ needs.parse.outputs.pr-number }}
cancel-in-progress: false
permissions:
statuses: write
pull-requests: write
if: always() && needs.parse.outputs.command-name == 'update-versions' && needs.prepare.outputs.overlay-branch != '' && needs.prepare.outputs.workspace != ''
runs-on: ubuntu-latest
steps:
- name: Add completion comment
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
INPUT_COMMAND_NAME: ${{ needs.parse.outputs.command-name }}
INPUT_PR_NUMBER: ${{ needs.prepare.outputs.pr-number }}
with:
script: |
const prNumber = Number(core.getInput('pr_number'));
const pr = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber,
});
const overlayCommit = pr.data.head.sha;
const workflowRun = await github.rest.actions.getWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: '${{ github.run_id }}'
});
const jobs = await github.rest.actions.listJobsForWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: '${{ github.run_id }}',
filter: 'latest',
});
const success = jobs.data.jobs
.filter(j => j.name.startsWith('Update versions on PR'))
.every(j => j.conclusion === 'success');
await github.rest.repos.createCommitStatus({
owner: context.repo.owner,
repo: context.repo.repo,
sha: overlayCommit,
description: '${{ github.workflow }}',
state: success ? 'success' : 'failure',
target_url: workflowRun.data.html_url,
context: core.getInput('command_name'),
});
const body = `[Update Versions workflow](${workflowRun.data.html_url}) has completed with ${ success ? 'success' : 'failure' }.`;
await github.rest.issues.createComment({
issue_number: prNumber,
owner: context.repo.owner,
repo: context.repo.repo,
body: body
})
add_update_commit_completion_comment:
needs:
- parse
- prepare
- updatePRWithCommit
concurrency:
group: add_update_commit_completion_comment-${{ github.ref_name }}-${{ needs.parse.outputs.pr-number }}
cancel-in-progress: false
permissions:
statuses: write
pull-requests: write
if: |
always() &&
needs.parse.outputs.command-name == 'update-commit' &&
needs.prepare.outputs.overlay-branch != '' &&
needs.prepare.outputs.workspace != ''
runs-on: ubuntu-latest
steps:
- name: Add completion comment
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
INPUT_COMMAND_NAME: ${{ needs.parse.outputs.command-name }}
INPUT_PR_NUMBER: ${{ needs.prepare.outputs.pr-number }}
with:
script: |
const prNumber = Number(core.getInput('pr_number'));
const pr = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber,
});
const overlayCommit = pr.data.head.sha;
const workflowRun = await github.rest.actions.getWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: '${{ github.run_id }}'
});
const jobs = await github.rest.actions.listJobsForWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: '${{ github.run_id }}',
filter: 'latest',
});
const success = jobs.data.jobs
.filter(j => j.name.startsWith('Update commit on PR'))
.every(j => j.conclusion === 'success' || j.conclusion === 'skipped');
await github.rest.repos.createCommitStatus({
owner: context.repo.owner,
repo: context.repo.repo,
sha: overlayCommit,
description: '${{ github.workflow }}',
state: success ? 'success' : 'failure',
target_url: workflowRun.data.html_url,
context: core.getInput('command_name'),
});
const body = `[Update Commit workflow](${workflowRun.data.html_url}) has completed with ${ success ? 'success' : 'failure' }.`;
await github.rest.issues.createComment({
issue_number: prNumber,
owner: context.repo.owner,
repo: context.repo.repo,
body: body
})
overrideBackstage:
name: Override Backstage compatibility
needs:
- parse
- prepare
concurrency:
group: overrideBackstage-${{ github.ref_name }}-${{ needs.parse.outputs.pr-number }}
cancel-in-progress: true
if: |
needs.parse.outputs.command-name == 'override-backstage' &&
needs.prepare.outputs.workspace != ''
runs-on: ubuntu-latest
permissions:
contents: write
outputs:
target-version: ${{ steps.override.outputs.target-version }}
source-version: ${{ steps.override.outputs.source-version }}
commit-sha: ${{ steps.override.outputs.commit-sha }}
fork: ${{ steps.override.outputs.fork }}
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Override Backstage compatibility
id: override
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
INPUT_WORKSPACE: ${{ needs.prepare.outputs.workspace }}
INPUT_OVERLAY_BRANCH: ${{ needs.prepare.outputs.overlay-branch }}
INPUT_OVERLAY_REPO: ${{ needs.prepare.outputs.overlay-repo }}
INPUT_TARGET_BRANCH: ${{ needs.prepare.outputs.target-branch }}
with:
script: |
const script = require('./.github/workflows/github-script/override-backstage-compatibility.js');
await script({github, context, core});
overrideBackstageMetadataRefresh:
name: Override Backstage metadata refresh
needs:
- parse
- prepare
- overrideBackstage
concurrency:
group: overrideBackstageMetadataRefresh-${{ github.ref_name }}-${{ needs.parse.outputs.pr-number }}
cancel-in-progress: true
if: |
needs.overrideBackstage.result == 'success' &&
needs.overrideBackstage.outputs.fork != 'true'
uses: ./.github/workflows/update-plugins-repo-refs.yaml
with:
single-branch: ${{ needs.prepare.outputs.target-branch }}
workspace-path: ${{ needs.prepare.outputs.workspace }}
pr-to-update: ${{ needs.prepare.outputs.pr-number }}
force: true
permissions:
actions: write
contents: write
pull-requests: write
issues: read
attestations: write
packages: write
id-token: write
statuses: write
add_override_backstage_completion_comment:
needs:
- parse
- prepare
- overrideBackstage
- overrideBackstageMetadataRefresh
concurrency:
group: add_override_backstage_completion_comment-${{ github.ref_name }}-${{ needs.parse.outputs.pr-number }}
cancel-in-progress: false
permissions:
statuses: write
pull-requests: write
if: |
always() &&
needs.parse.outputs.command-name == 'override-backstage' &&
needs.prepare.outputs.overlay-branch != '' &&
needs.prepare.outputs.workspace != ''
runs-on: ubuntu-latest
steps:
- name: Add completion comment
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
INPUT_COMMAND_NAME: ${{ needs.parse.outputs.command-name }}
INPUT_PR_NUMBER: ${{ needs.prepare.outputs.pr-number }}
INPUT_TARGET_VERSION: ${{ needs.overrideBackstage.outputs.target-version }}
INPUT_SOURCE_VERSION: ${{ needs.overrideBackstage.outputs.source-version }}
INPUT_COMMIT_SHA: ${{ needs.overrideBackstage.outputs.commit-sha }}
INPUT_FORK: ${{ needs.overrideBackstage.outputs.fork }}
INPUT_OVERRIDE_RESULT: ${{ needs.overrideBackstage.result }}
INPUT_METADATA_REFRESH_RESULT: ${{ needs.overrideBackstageMetadataRefresh.result }}
with:
script: |
const prNumber = Number(core.getInput('pr_number'));
const pr = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber,
});
const overlayCommit = pr.data.head.sha;
const workflowRun = await github.rest.actions.getWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: '${{ github.run_id }}'
});
const overrideResult = core.getInput('override_result');
const metadataRefreshResult = core.getInput('metadata_refresh_result');
const overrideSuccess = overrideResult === 'success';
const refreshSuccess = metadataRefreshResult === 'success';
const fork = core.getInput('fork') === 'true';
const allSuccess = overrideSuccess && (refreshSuccess || fork);
await github.rest.repos.createCommitStatus({
owner: context.repo.owner,
repo: context.repo.repo,
sha: overlayCommit,
description: '${{ github.workflow }}',
state: allSuccess ? 'success' : 'failure',
target_url: workflowRun.data.html_url,
context: core.getInput('command_name'),
});
let body;
if (fork) {
const targetVersion = core.getInput('target_version');
body = `[Override Backstage workflow](${workflowRun.data.html_url}) — skipped: PR is from a fork.\n\nPlease manually:\n1. Create \`backstage.json\` with \`{"version": "${targetVersion}"}\`\n2. Update all \`metadata/*.yaml\` OCI tags from \`bs_<old>__\` to \`bs_${targetVersion}__\`\n3. Update \`supportedVersions\` in all \`metadata/*.yaml\` to \`${targetVersion}\``;
} else if (overrideSuccess && refreshSuccess) {
const targetVersion = core.getInput('target_version');
const sourceVersion = core.getInput('source_version');
const commitSha = core.getInput('commit_sha');
body = `[Override Backstage workflow](${workflowRun.data.html_url}) completed successfully.\n\n`;
body += `#### Backstage Version Override\n`;
body += `- Source version: \`${sourceVersion}\`\n`;
body += `- Target version: \`${targetVersion}\`\n`;
body += `- \`backstage.json\` created/updated (commit: ${commitSha})\n`;
body += `- [Metadata refresh](${workflowRun.data.html_url}) completed (OCI tags + \`supportedVersions\`)\n\n`;
body += `You can now run \`/publish\` to build and publish the plugin images.`;
} else if (overrideSuccess && !refreshSuccess) {
const targetVersion = core.getInput('target_version');
const commitSha = core.getInput('commit_sha');
body = `[Override Backstage workflow](${workflowRun.data.html_url}) partially completed.\n\n`;
body += `- \`backstage.json\` created/updated (commit: ${commitSha})\n`;
body += `- Metadata refresh **failed** — [see workflow run](${workflowRun.data.html_url})\n\n`;
body += `The \`backstage.json\` override to \`${targetVersion}\` was applied, but metadata files (OCI tags, \`supportedVersions\`) were not updated automatically. `;
body += `You can retry with \`/override-backstage\` or manually update the metadata files.`;
} else {
body = `[Override Backstage workflow](${workflowRun.data.html_url}) has completed with failure.`;
}
await github.rest.issues.createComment({
issue_number: prNumber,
owner: context.repo.owner,
repo: context.repo.repo,
body: body
});