Skip to content

Update description for WireMock Runner section #13

Update description for WireMock Runner section

Update description for WireMock Runner section #13

name: Auto-merge .NET docs PRs
on:
issue_comment:
types: [created]
pull_request_target:
types: [opened, synchronize, reopened]
permissions:
contents: write
pull-requests: write
jobs:
auto-merge:
runs-on: ubuntu-latest
# Only run on PRs (not regular issues) and non-draft PRs
if: |
(github.event_name == 'pull_request_target' && github.event.pull_request.draft == false) ||
(github.event_name == 'issue_comment' && github.event.issue.pull_request != null)
steps:
- name: Get PR details
id: pr-details
uses: actions/github-script@v7
with:
script: |
let prNumber;
if (context.eventName === 'pull_request_target') {
prNumber = context.payload.pull_request.number;
} else if (context.eventName === 'issue_comment') {
prNumber = context.payload.issue.number;
}
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber,
});
console.log(`PR #${prNumber}: ${pr.title}`);
console.log(`Head SHA: ${pr.head.sha}`);
console.log(`Base SHA: ${pr.base.sha}`);
console.log(`Draft: ${pr.draft}`);
return {
number: prNumber,
head_sha: pr.head.sha,
base_sha: pr.base.sha,
draft: pr.draft
};
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ fromJson(steps.pr-details.outputs.result).head_sha }}
fetch-depth: 0
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v45
with:
base_sha: ${{ fromJson(steps.pr-details.outputs.result).base_sha }}
sha: ${{ fromJson(steps.pr-details.outputs.result).head_sha }}
- name: Check if PR only affects dotnet paths
id: check-files
run: |
echo "Extracting dotnet-related paths from CODEOWNERS"
# Get all paths from CODEOWNERS that contain 'dotnet' (excluding the default owner line)
DOTNET_PATHS=$(grep -E '^\s*/.*dotnet.*/' .github/CODEOWNERS | awk '{print $1}')
echo "Dotnet paths found in CODEOWNERS:"
echo "$DOTNET_PATHS"
echo "Checking if all changed files match dotnet paths..."
ALL_DOTNET=true
MATCHED_PATHS=""
for file in ${{ steps.changed-files.outputs.all_changed_files }}; do
echo "Checking file: $file"
FILE_MATCHED=false
# Check if file matches any dotnet path
while IFS= read -r path; do
# Remove leading slash and trailing slash for pattern matching
pattern="${path#/}"
if [[ "$file" =~ ^${pattern} ]]; then
echo " ✓ Matches path: $path"
FILE_MATCHED=true
# Add to matched paths if not already there
if [[ ! "$MATCHED_PATHS" =~ "$path" ]]; then
MATCHED_PATHS="$MATCHED_PATHS$path"$'\n'
fi
break
fi
done <<< "$DOTNET_PATHS"
if [ "$FILE_MATCHED" = "false" ]; then
echo " ✗ File $file does not match any dotnet path"
ALL_DOTNET=false
break
fi
done
echo "all_dotnet_docs=$ALL_DOTNET" >> $GITHUB_OUTPUT
if [ "$ALL_DOTNET" = "true" ]; then
echo "✅ All changed files match dotnet paths"
echo "Matched paths:"
echo "$MATCHED_PATHS"
# Extract all unique code owners from matched paths
ALL_OWNERS=""
while IFS= read -r path; do
if [ -n "$path" ]; then
# Get owners for this specific path
OWNERS=$(grep "^$path" .github/CODEOWNERS | sed "s|^$path||" | sed 's/@//g')
ALL_OWNERS="$ALL_OWNERS $OWNERS"
fi
done <<< "$MATCHED_PATHS"
# Remove duplicates and convert to JSON array
UNIQUE_OWNERS=$(echo "$ALL_OWNERS" | tr ' ' '\n' | grep -v '^$' | sort -u)
OWNERS_JSON=$(echo "$UNIQUE_OWNERS" | jq -R -s -c 'split("\n") | map(select(length > 0))')
echo "Code owners: $OWNERS_JSON"
echo "owners=$OWNERS_JSON" >> $GITHUB_OUTPUT
else
echo "❌ Some files are outside dotnet paths"
fi
- name: Check for code owner thumbs-up comment
id: check-approval
if: steps.check-files.outputs.all_dotnet_docs == 'true'
uses: actions/github-script@v7
with:
script: |
const codeOwners = ${{ steps.check-files.outputs.owners }};
const prNumber = ${{ fromJson(steps.pr-details.outputs.result).number }};
console.log(`Code owners for affected dotnet paths: ${codeOwners.join(', ')}`);
// Get all comments on the PR
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
});
console.log(`Found ${comments.length} comments on PR #${prNumber}`);
// Check for a comment containing only a thumbs-up emoji from a code owner
let approvedBy = null;
for (const comment of comments) {
const commentBody = comment.body.trim();
console.log(`Checking comment ${comment.id} by ${comment.user.login}: "${commentBody}"`);
// Check if comment is just a thumbs-up emoji and from a code owner
if (commentBody === '👍' && codeOwners.includes(comment.user.login)) {
approvedBy = comment.user.login;
console.log(`✅ Found thumbs-up comment from code owner: ${approvedBy}`);
break;
}
}
if (approvedBy) {
console.log(`✅ Approved by code owner: ${approvedBy}`);
return { approved: true, approver: approvedBy };
} else {
console.log(`⏳ No thumbs-up comment from code owners yet. Waiting for comment from: ${codeOwners.join(', ')}`);
return { approved: false, approver: null };
}
- name: Enable auto-merge
if: |
steps.check-files.outputs.all_dotnet_docs == 'true' &&
fromJson(steps.check-approval.outputs.result).approved == true
env:
GH_TOKEN: ${{ github.token }}
run: |
gh pr merge ${{ fromJson(steps.pr-details.outputs.result).number }} --squash --auto
echo '✅ Auto-merge enabled successfully!'
- name: Add comment on success
if: |
steps.check-files.outputs.all_dotnet_docs == 'true' &&
fromJson(steps.check-approval.outputs.result).approved == true
uses: actions/github-script@v7
with:
script: |
const prNumber = ${{ fromJson(steps.pr-details.outputs.result).number }};
const approvalResult = ${{ steps.check-approval.outputs.result }};
const approver = approvalResult.approver;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: `✅ Auto-merge enabled: This PR only affects .NET-related paths and was approved by @${approver} with a 👍 comment. The PR will be merged automatically once all checks pass.`
});
- name: Add comment if not eligible
if: |
steps.check-files.outputs.all_dotnet_docs == 'false' ||
(steps.check-files.outputs.all_dotnet_docs == 'true' && fromJson(steps.check-approval.outputs.result).approved == false)
uses: actions/github-script@v7
with:
script: |
const prNumber = ${{ fromJson(steps.pr-details.outputs.result).number }};
let reason = '';
if ('${{ steps.check-files.outputs.all_dotnet_docs }}' !== 'true') {
reason = '❌ This PR includes files outside of .NET-related paths and cannot be auto-merged.';
} else {
const approvalResult = ${{ steps.check-approval.outputs.result }};
if (!approvalResult.approved) {
const codeOwners = ${{ steps.check-files.outputs.owners }};
const ownerMentions = codeOwners.map(owner => `@${owner}`).join(', ');
reason = `⏳ Waiting for a 👍 comment from a code owner (${ownerMentions}) for auto-merge.`;
}
}
if (reason) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: reason
});
}