Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions .github/workflows/mu-pr-validation-pending.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Posts an immediate "pending" notification on a pull request
# indicating that QEMU validation is waiting for CI to complete.
#
# Note: This is triggered by pull_request_target so the comment
# appears immediately when a PR is pushed, rather than waiting
# for CI to complete.
#
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: BSD-2-Clause-Patent
##
name: Mu QEMU PR Validation Pending

on:
pull_request_target:
types:
- opened
- reopened
- synchronize
branches:
- release/202511

permissions:
contents: read

concurrency:
group: mu-qemu-pending-${{ github.event.pull_request.number }}
cancel-in-progress: true

jobs:
notify-pending:
name: Post Pending Notification
runs-on: ubuntu-latest
steps:
- name: Generate GitHub App Token
id: app-token
uses: actions/create-github-app-token@v3
with:
app-id: ${{ vars.MU_ACCESS_APP_ID }}
private-key: ${{ secrets.MU_ACCESS_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}

- name: Update PR Comment to Pending
uses: actions/github-script@v8
with:
github-token: ${{ steps.app-token.outputs.token }}
script: |
const issue_number = context.issue.number;
const hiddenMarker = '<!-- mu-qemu-validation-result -->';
const marker = '*This comment was automatically generated by the Mu QEMU PR Validation workflow.*';

const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number,
});

const existingComment = comments.data.find((c) =>
c.body.includes(hiddenMarker)
);

const body = [
hiddenMarker,
'## :hourglass: QEMU Validation Pending',
'',
'QEMU validation is pending on successful CI completion.',
'',
'> **Note:** Any previous results are available in this comment\'s edit history.',
'',
marker,
].join('\n');

if (existingComment) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existingComment.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number,
body,
});
}

- name: Set Pending Commit Status
uses: actions/github-script@v8
with:
github-token: ${{ steps.app-token.outputs.token }}
script: |
await github.rest.repos.createCommitStatus({
owner: context.repo.owner,
repo: context.repo.repo,
sha: '${{ github.event.pull_request.head.sha }}',
state: 'pending',
description: 'Waiting for CI to complete',
context: 'Mu QEMU PR Validation',
});
30 changes: 30 additions & 0 deletions .github/workflows/mu-pr-validation-post.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Posts final results after the Mu QEMU PR Validation
# workflow completes. Downloads metadata and updates
# the PR comment and commit status with the final
# outcome.
#
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: BSD-2-Clause-Patent
##
name: Mu QEMU PR Validation Post

on:
workflow_run:
workflows: ["Mu QEMU PR Validation"]
types: ["completed"]

permissions:
contents: read
actions: read

jobs:
post-results:
name: Post Validation Results
uses: microsoft/mu_devops/.github/workflows/MuPrValidationPost.yml@add_mu_pr_val_workflow_e2e_val
with:
app-id: ${{ vars.MU_ACCESS_APP_ID }}
conclusion: ${{ github.event.workflow_run.conclusion }}
head-sha: ${{ github.event.workflow_run.head_sha }}
triggering-run-id: ${{ github.event.workflow_run.id }}
secrets:
private-key: ${{ secrets.MU_ACCESS_APP_PRIVATE_KEY }}
132 changes: 132 additions & 0 deletions .github/workflows/mu-pr-validation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# Runs QEMU-based platform validation on pull requests.
#
# Triggered by the completion of the "CLANGPDB Package CI" workflow.
#
# Gathers PR metadata and calls the reusable MuPrValidation workflow in
# mu_devops to build and boot mu_basecore changes on QEMU Q35 and SBSA.
#
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: BSD-2-Clause-Patent
##
name: Mu QEMU PR Validation

on:
workflow_run:
workflows: ["CLANGPDB Package CI"]
types: ["completed"]

concurrency:
group: mu-qemu-pr-${{ github.event.workflow_run.head_branch }}
cancel-in-progress: true

permissions:
actions: read
contents: read
pull-requests: read

jobs:
prepare:
runs-on: ubuntu-latest
name: Gather PR Metadata
if: |
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event == 'pull_request'
outputs:
pr_number: ${{ steps.pr-info.outputs.pr_number }}
skip: ${{ steps.pr-info.outputs.skip }}
skip_reason: ${{ steps.pr-info.outputs.skip_reason }}
steps:
- name: Get PR Information
id: pr-info
shell: bash
env:
GH_TOKEN: ${{ github.token }}
HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
HEAD_REF: ${{ github.event.workflow_run.head_branch }}
HEAD_REPO: ${{ github.event.workflow_run.head_repository.full_name }}
run: |
owner="${HEAD_REPO%%/*}"
pr_number=$(gh api "repos/${GITHUB_REPOSITORY}/pulls" \
--method GET -f state=open -f head="${owner}:${HEAD_REF}" \
--jq '.[0].number')

if [[ -z "$pr_number" || "$pr_number" == "null" ]]; then
echo "::notice::No open PR found for head $owner:$HEAD_REF."
echo "skip=true" >> "$GITHUB_OUTPUT"

closed_pr_json=$(gh api "repos/${GITHUB_REPOSITORY}/pulls" \
--method GET -f state=closed -f head="${owner}:${HEAD_REF}" \
-f sort=updated -f direction=desc -f per_page=1 \
--jq '.[0] | select(. != null) | {number, merged: (.merged_at != null)}')

if [[ -n "$closed_pr_json" ]]; then
closed_pr_number=$(echo "$closed_pr_json" | jq -r '.number')
closed_pr_merged=$(echo "$closed_pr_json" | jq -r '.merged')

echo "pr_number=$closed_pr_number" >> "$GITHUB_OUTPUT"

if [[ "$closed_pr_merged" == "true" ]]; then
echo "::notice::PR #$closed_pr_number was merged before validation started."
echo "skip_reason=merged" >> "$GITHUB_OUTPUT"
else
echo "::notice::PR #$closed_pr_number was closed before validation started."
echo "skip_reason=closed" >> "$GITHUB_OUTPUT"
fi
else
echo "::notice::No PR (open or closed) found for head $owner:$HEAD_REF."
echo "skip_reason=branch_unavailable" >> "$GITHUB_OUTPUT"
fi

exit 0
fi

echo "skip=false" >> "$GITHUB_OUTPUT"

echo "::group::PR Information"
echo " - PR Number: $pr_number"
echo " - Head SHA: $HEAD_SHA"
echo " - Head Ref: $HEAD_REF"
echo " - Source: $HEAD_REPO"
echo "::endgroup::"

echo "pr_number=$pr_number" >> "$GITHUB_OUTPUT"

upload-skip-metadata:
name: Upload Skip Metadata
runs-on: ubuntu-latest
needs: [prepare]
if: needs.prepare.outputs.skip == 'true' && needs.prepare.outputs.pr_number != ''
steps:
- name: Create Skip Metadata
shell: bash
run: |
mkdir -p metadata
cat > metadata/pr-metadata.json <<EOF
{
"pr_number": ${{ needs.prepare.outputs.pr_number }},
"skipped": true,
"skip_reason": "${{ needs.prepare.outputs.skip_reason }}"
}
EOF

- name: Upload PR Metadata
uses: actions/upload-artifact@v7
with:
name: mu-qemu-pr-metadata
path: metadata/pr-metadata.json

qemu-pr-validation:
name: Run Mu QEMU Validation
needs: [prepare]
if: needs.prepare.result == 'success' && needs.prepare.outputs.skip != 'true'
uses: microsoft/mu_devops/.github/workflows/MuPrValidation.yml@add_mu_pr_val_workflow_e2e_val
with:
app-id: ${{ vars.MU_ACCESS_APP_ID }}
caller-ref: ${{ github.event.workflow_run.head_sha }}
caller-repo: ${{ github.repository }}
caller-repo-name: mu_basecore
head-sha: ${{ github.event.workflow_run.head_sha }}
pr-number: ${{ fromJSON(needs.prepare.outputs.pr_number) }}
submodule-path: MU_BASECORE
secrets:
private-key: ${{ secrets.MU_ACCESS_APP_PRIVATE_KEY }}
Loading