Skip to content

Add matomo workspace to commit 3e2c0cf for backstage 1.41.1 on branch main #1150

Add matomo workspace to commit 3e2c0cf for backstage 1.41.1 on branch main

Add matomo workspace to commit 3e2c0cf for backstage 1.41.1 on branch main #1150

Workflow file for this run

name: Pull Request Actions
on:
issue_comment:
types: [created, edited]
jobs:
parse:
runs-on: ubuntu-latest
name: Parse PR Comment
if: github.event.issue.pull_request
outputs:
command_name: ${{ steps.extract.outputs.command_name }}
error_message: ${{ steps.extract.outputs.error_message }}
steps:
- name: Extract command from comment
id: extract
uses: actions/github-script@v7
with:
script: |
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', '/test']);
const matchingCommands = lines.filter(l => allowed.has(l));
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('error_message', '');
add_error_comment:
needs:
- parse
concurrency:
group: add_error_comment-${{ github.ref_name }}-${{ github.event.issue.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@v7
env:
INPUT_ERROR_MESSAGE: ${{ needs.parse.outputs.error_message }}
with:
script: |
const errorMessage = core.getInput('error_message');
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- \`/test\` - Run integration tests`;
await github.rest.issues.createComment({
issue_number: context.issue.number,
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 }}-${{ github.event.issue.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 }}
permissions:
statuses: write
steps:
- name: Get PR branch data
id: get-branch
uses: actions/github-script@v7
env:
INPUT_COMMAND_NAME: ${{ needs.parse.outputs.command_name }}
with:
script: |
const currentPullRequest = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number
});
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);
const prNumber = currentPullRequest.data.number;
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: context.issue.number
});
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')
});
export:
name: Publish PR Dynamic Plugin Images
needs:
- parse
- prepare
- checkPRUpToDate
concurrency:
group: export-${{ github.ref_name }}-${{ github.event.issue.number }}
cancel-in-progress: true
if: needs.parse.outputs.command_name == 'publish' && needs.prepare.outputs.overlay-branch != '' && needs.prepare.outputs.workspace != ''
uses: redhat-developer/rhdh-plugin-export-utils/.github/workflows/export-workspaces-as-dynamic.yaml@main
with:
overlay-branch: ${{ needs.prepare.outputs.overlay-branch }}
overlay-repo: ${{ needs.prepare.outputs.overlay-repo }}
workspace-path: ${{ needs.prepare.outputs.workspace }}
publish-container: true
image-repository-prefix: ${{ format('ghcr.io/{0}', github.repository) }}
image-tag-prefix: ${{ format('pr_{0}__', needs.prepare.outputs.pr-number) }}
image-registry-user: ${{ github.actor }}
secrets:
image-registry-password: ${{ secrets.GITHUB_TOKEN }}
permissions:
contents: write
attestations: write
packages: write
id-token: write
uploadPublishedExportsArtifact:
name: Upload published-exports artifact
needs:
- parse
- prepare
- export
concurrency:
group: uploadPublishedExportsArtifact-${{ github.ref_name }}-${{ github.event.issue.number }}
cancel-in-progress: false
if: needs.parse.outputs.command_name == 'publish' && needs.prepare.outputs.overlay-branch != '' && needs.prepare.outputs.workspace != '' && needs.export.outputs.published-exports != ''
runs-on: ubuntu-latest
steps:
- name: Write and stage meta.json
env:
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: ${{ needs.prepare.outputs.pr-number }}
run: |
mkdir -p published-exports
cat > published-exports/meta.json <<EOF
{"workspace":"${WORKSPACE}","overlayBranch":"${OVERLAY_BRANCH}","overlayRepo":"${OVERLAY_REPO}","overlayCommit":"${OVERLAY_COMMIT}","pr":${PR_NUMBER}}
EOF
- name: Stage published exports content
env:
PUBLISHED_EXPORTS: ${{ needs.export.outputs.published-exports }}
run: |
printf "%s\n" "$PUBLISHED_EXPORTS" > published-exports/published-exports.txt
- name: Upload published-exports artifact
uses: actions/upload-artifact@v4
with:
name: published-exports
path: published-exports/
if-no-files-found: error
retention-days: 7
- name: Upload context artifact
uses: actions/upload-artifact@v4
with:
name: context-${{ github.run_id }}
path: published-exports/meta.json
if-no-files-found: error
retention-days: 1
create_test_context:
name: Create Test Context
needs:
- parse
- prepare
if: needs.parse.outputs.command_name == 'test' && needs.prepare.outputs.pr-number != ''
runs-on: ubuntu-latest
steps:
- name: Write meta.json for test context
env:
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: ${{ needs.prepare.outputs.pr-number }}
run: |
mkdir -p context
cat > context/meta.json <<EOF
{"workspace":"${WORKSPACE}","overlayBranch":"${OVERLAY_BRANCH}","overlayRepo":"${OVERLAY_REPO}","overlayCommit":"${OVERLAY_COMMIT}","pr":${PR_NUMBER}}
EOF
- name: Upload test-context artifact
uses: actions/upload-artifact@v4
with:
name: context-${{ github.run_id }}
path: context/meta.json
if-no-files-found: error
retention-days: 1
checkBackstageCompatibility:
name: Check workspace backstage compatibility
needs:
- parse
- prepare
concurrency:
group: checkBackstageCompatibility-${{ github.ref_name }}-${{ github.event.issue.number }}
cancel-in-progress: true
if: needs.parse.outputs.command_name == 'publish' && needs.prepare.outputs.overlay-branch != '' && needs.prepare.outputs.workspace != ''
uses: redhat-developer/rhdh-plugin-export-utils/.github/workflows/check-backstage-compatibility.yaml@main
with:
overlay-branch: ${{ needs.prepare.outputs.overlay-branch }}
overlay-repo: ${{ needs.prepare.outputs.overlay-repo }}
workspace-path: ${{ needs.prepare.outputs.workspace }}
add_publish_completion_comment:
needs:
- parse
- prepare
- checkPRUpToDate
- export
- checkBackstageCompatibility
concurrency:
group: add_publish_completion_comment-${{ github.ref_name }}-${{ github.event.issue.number }}
cancel-in-progress: false
permissions:
statuses: write
pull-requests: write
if: always() && needs.parse.outputs.command_name == 'publish' && needs.prepare.outputs.overlay-branch != '' && needs.prepare.outputs.workspace != ''
runs-on: ubuntu-latest
steps:
- name: Download compatibility report
uses: actions/download-artifact@v4
continue-on-error: true
with:
name: backstage-compatibility-report
path: ./
- name: Add completion comment
uses: actions/github-script@v7
env:
INPUT_OVERLAY_COMMIT: ${{ needs.prepare.outputs.overlay-commit }}
INPUT_PUBLISHED_EXPORTS: ${{ needs.export.outputs.published-exports }}
INPUT_FAILED_EXPORTS: ${{ needs.export.outputs.failed-exports }}
INPUT_COMMAND_NAME: ${{ needs.parse.outputs.command_name }}
with:
script: |
const fs = require('fs');
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('Publish') || j.name.startsWith('export') || j.name.startsWith('Export') || j.name.startsWith('Check'))
.every(j => j.conclusion === 'success');
await github.rest.repos.createCommitStatus({
owner: context.repo.owner,
repo: context.repo.repo,
sha: core.getInput('overlay_commit'),
description: '${{ github.workflow }}',
state: success ? 'success' : 'failure',
target_url: workflowRun.data.html_url,
context: core.getInput('command_name'),
});
let body = `[Publish workflow](${workflowRun.data.html_url}) has completed with ${ success ? 'success' : 'failure' }.`;
// Check for compatibility report
const reportPath = 'backstage-compatibility-report.md';
if (fs.existsSync(reportPath)) {
const reportContent = fs.readFileSync(reportPath, 'utf8');
body = `${body}\n\n${reportContent}`;
}
const publishedExports = core.getMultilineInput('published_exports');
if (publishedExports.length > 0) {
body = `${body}\n- Published container images:`;
publishedExports.forEach(line => {
body = `${body}\n - ${line}`;
});
}
const failedExports = core.getMultilineInput('failed_exports');
if (failedExports.length > 0) {
body = `${body}\n- Plugins failed during export or container image publishing:`;
failedExports.forEach(line => {
body = `${body}\n - ${line}`;
});
}
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: body
})
add_no_workspace_comment:
needs:
- parse
- prepare
concurrency:
group: add_no_workspace_comment-${{ github.ref_name }}-${{ github.event.issue.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: Add success comment
uses: actions/github-script@v7
env:
INPUT_OVERLAY_COMMIT: ${{ needs.prepare.outputs.overlay-commit }}
INPUT_COMMAND_NAME: ${{ needs.parse.outputs.command_name }}
with:
script: |
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: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: body
})
checkPRUpToDate:
name: Checks whether the PR is up-to-date with versions.json
needs:
- parse
- prepare
concurrency:
group: checkPRUpToDate-${{ github.ref_name }}-${{ github.event.issue.number }}
cancel-in-progress: false
permissions:
statuses: write
pull-requests: write
if: always() && needs.parse.outputs.command_name == 'publish' && needs.prepare.outputs.overlay-branch != '' && needs.prepare.outputs.workspace != ''
runs-on: ubuntu-latest
steps:
- name: Add update check comment
uses: actions/github-script@v7
env:
INPUT_TARGET_BRANCH: ${{ needs.prepare.outputs.target-branch }}
INPUT_OVERLAY_BRANCH: ${{ needs.prepare.outputs.overlay-branch }}
INPUT_OVERLAY_REPO: ${{ needs.prepare.outputs.overlay-repo }}
with:
script: |
const path = 'versions.json';
const releaseBranch = core.getInput('target_branch');
if (! releaseBranch?.startsWith('release-') && ! releaseBranch?.startsWith('main') ) {
core.notice(`Current PR is not based on a release branch.`);
return;
}
const { data: sourceFile } = await github.rest.repos.getContent({
owner: context.repo.owner,
repo: context.repo.repo,
path,
ref: releaseBranch,
});
if (!('type' in sourceFile) || sourceFile.type !== 'file') {
core.setFailed(`\`${path}\` is not a file on branch \`${releaseBranch}\``);
return;
}
const sourceContent = Buffer.from(
sourceFile.content,
(Buffer.isEncoding(sourceFile.encoding) ? sourceFile.encoding : 'utf-8')
).toString('utf-8');
const prRepository = core.getInput('overlay_repo');
const prBranch = core.getInput('overlay_branch');
const owner = prRepository.split('/')[0];
const repo = prRepository.split('/')[1];
const { data: targetFile } = await github.rest.repos.getContent({
owner,
repo,
path,
ref: prBranch,
});
if (!('type' in targetFile) || targetFile.type !== 'file') {
core.warning(`\`${path}\` is not a file on branch ${prBranch}`);
return;
}
const targetContent = Buffer.from(
targetFile.content,
(Buffer.isEncoding(targetFile.encoding) ? targetFile.encoding : 'utf-8')
).toString('utf-8');
if (sourceContent !== targetContent) {
core.setFailed(`PR not up-to-date with the release branch`);
const body = `The \`versions.json\` file in your PR doesn't match the one in release branch #${prBranch}\nTry updating it by adding the \`/update-versions\` PR comment.`;
await github.rest.issues.createComment({
issue_number: context.issue.number,
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 }}-${{ github.event.issue.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: ${{ github.event.issue.number }}
release-branch: ${{ needs.prepare.outputs.target-branch }}
permissions:
contents: write
pull-requests: write
add_update_versions_completion_comment:
needs:
- parse
- prepare
- updatePRWithVersions
concurrency:
group: add_update_versions_completion_comment-${{ github.ref_name }}-${{ github.event.issue.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@v7
env:
INPUT_OVERLAY_COMMIT: ${{ needs.prepare.outputs.overlay-commit }}
INPUT_COMMAND_NAME: ${{ needs.parse.outputs.command_name }}
with:
script: |
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: core.getInput('overlay_commit'),
description: '${{ github.workflow }}',
state: success ? 'success' : 'failure',
target_url: workflowRun.data.html_url,
context: core.getInput('command_name'),
});
let body = `[Update Versions workflow](${workflowRun.data.html_url}) has completed with ${ success ? 'success' : 'failure' }.`;
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: body
})
updatePRWithCommit:
name: Update commit on PR from automatic discovery
needs:
- parse
- prepare
concurrency:
group: updatePRWithCommit-${{ github.ref_name }}-${{ github.event.issue.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:
contents: write
pull-requests: write
add_update_commit_completion_comment:
needs:
- parse
- prepare
- updatePRWithCommit
concurrency:
group: add_update_commit_completion_comment-${{ github.ref_name }}-${{ github.event.issue.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@v7
env:
INPUT_OVERLAY_COMMIT: ${{ needs.prepare.outputs.overlay-commit }}
INPUT_COMMAND_NAME: ${{ needs.parse.outputs.command_name }}
with:
script: |
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: core.getInput('overlay_commit'),
description: '${{ github.workflow }}',
state: success ? 'success' : 'failure',
target_url: workflowRun.data.html_url,
context: core.getInput('command_name'),
});
let body = `[Update Commit workflow](${workflowRun.data.html_url}) has completed with ${ success ? 'success' : 'failure' }.`;
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: body
})