Skip to content

Extension blocks are not foldable #38

Extension blocks are not foldable

Extension blocks are not foldable #38

Workflow file for this run

name: PR Validation
on:
issue_comment:
types: [created]
permissions:
pull-requests: write
id-token: write # Required to fetch an OIDC token for Azure authentication
jobs:
validate-and-trigger:
name: Validate and Trigger Azure Pipeline
if: |
github.event.issue.pull_request &&
(contains(github.event.comment.body, '/dart') || contains(github.event.comment.body, '/pr-val'))
runs-on: ubuntu-latest
environment: roslyn_perf
steps:
- name: Check if command invoker has write access
id: check-invoker-access
uses: actions/github-script@v7
with:
script: |
const { data: permission } = await github.rest.repos.getCollaboratorPermissionLevel({
owner: context.repo.owner,
repo: context.repo.repo,
username: context.actor
});
const hasWriteAccess = ['admin', 'write', 'maintain'].includes(permission.permission);
console.log(`Command invoker ${context.actor} has permission: ${permission.permission}`);
core.setOutput('has-access', hasWriteAccess);
return hasWriteAccess;
- name: Check if command invoker is Microsoft org member
id: check-invoker-org
if: steps.check-invoker-access.outputs.has-access == 'true'
uses: actions/github-script@v7
with:
script: |
try {
await github.rest.orgs.checkMembershipForUser({
org: 'microsoft',
username: context.actor
});
console.log(`Command invoker ${context.actor} is a member of Microsoft org`);
core.setOutput('is-member', 'true');
return true;
} catch (error) {
console.log(`Command invoker ${context.actor} is not a member of Microsoft org`);
core.setOutput('is-member', 'false');
return false;
}
- name: Block unauthorized users
if: steps.check-invoker-access.outputs.has-access != 'true' || steps.check-invoker-org.outputs.is-member != 'true'
uses: actions/github-script@v7
with:
script: |
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: 'You do not have permission to trigger this workflow. Only Microsoft employees who are contributors to the roslyn repository can run pipelines.'
});
core.setFailed('Unauthorized user');
- name: Get PR author details
id: pr-author
uses: actions/github-script@v7
with:
script: |
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number
});
const prAuthor = pr.user.login;
console.log(`PR author: ${prAuthor}`);
core.setOutput('username', prAuthor);
// Check if PR author has write access
try {
const { data: permission } = await github.rest.repos.getCollaboratorPermissionLevel({
owner: context.repo.owner,
repo: context.repo.repo,
username: prAuthor
});
const hasWriteAccess = ['admin', 'write', 'maintain'].includes(permission.permission);
console.log(`PR author ${prAuthor} has permission: ${permission.permission}`);
core.setOutput('has-access', hasWriteAccess);
} catch (error) {
console.log(`PR author ${prAuthor} does not have write access`);
core.setOutput('has-access', 'false');
}
- name: Check if PR author is Microsoft org member
id: pr-author-org
uses: actions/github-script@v7
with:
script: |
const prAuthor = '${{ steps.pr-author.outputs.username }}';
try {
await github.rest.orgs.checkMembershipForUser({
org: 'microsoft',
username: prAuthor
});
console.log(`PR author ${prAuthor} is a member of Microsoft org`);
core.setOutput('is-member', 'true');
return true;
} catch (error) {
console.log(`PR author ${prAuthor} is not a member of Microsoft org`);
core.setOutput('is-member', 'false');
return false;
}
- name: Parse commit hash from comment
id: parse-commit
uses: actions/github-script@v7
with:
script: |
const commentBody = context.payload.comment.body;
// Extract commit hash after /dart or /pr-val
const match = commentBody.match(/\/(dart|pr-val)\s+([a-f0-9]{7,40})/i);
if (!match || !match[2]) {
console.log('No commit hash found in comment');
core.setOutput('has-commit', 'false');
return false;
}
const commitHash = match[2];
console.log(`Extracted commit hash: ${commitHash}`);
core.setOutput('has-commit', 'true');
core.setOutput('commit-hash', commitHash);
return true;
- name: Require commit hash for external PR authors
if: |
(steps.pr-author.outputs.has-access != 'true' || steps.pr-author-org.outputs.is-member != 'true') &&
steps.parse-commit.outputs.has-commit != 'true'
uses: actions/github-script@v7
with:
script: |
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: 'This PR is from an external author. You must specify a commit hash to trigger this workflow. Please use the format `/dart <commit-hash>` or `/pr-val <commit-hash>`.'
});
core.setFailed('Commit hash required for external PR author');
- name: Get PR branch details
id: pr-details
uses: actions/github-script@v7
with:
script: |
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number
});
core.setOutput('ref', pr.head.ref);
core.setOutput('repo', pr.head.repo.full_name);
core.setOutput('sha', pr.head.sha);
console.log(`PR #${context.issue.number}: ${pr.head.repo.full_name}@${pr.head.ref} (${pr.head.sha})`);
- name: Determine commit SHA to use
id: commit-sha
uses: actions/github-script@v7
with:
script: |
const parseCommitOutput = '${{ steps.parse-commit.outputs.has-commit }}';
const providedCommit = '${{ steps.parse-commit.outputs.commit-hash }}';
const prHeadSha = '${{ steps.pr-details.outputs.sha }}';
let commitSha;
if (parseCommitOutput === 'true' && providedCommit) {
// Use the commit hash provided in the comment
commitSha = providedCommit;
console.log(`Using commit hash from comment: ${commitSha}`);
} else {
// Use the PR head SHA
commitSha = prHeadSha;
console.log(`Using PR head SHA: ${commitSha}`);
}
core.setOutput('sha', commitSha);
- name: Validate commit exists in PR
if: steps.parse-commit.outputs.has-commit == 'true'
uses: actions/github-script@v7
with:
script: |
const commitSha = '${{ steps.commit-sha.outputs.sha }}';
const { data: commits } = await github.rest.pulls.listCommits({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number
});
const commitExists = commits.some(commit => commit.sha.startsWith(commitSha));
if (!commitExists) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `The specified commit hash \`${commitSha}\` was not found in this PR. Please ensure you are using a valid commit hash from this PR.`
});
core.setFailed(`Commit ${commitSha} not found in PR`);
} else {
console.log(`Validated commit ${commitSha} exists in PR`);
}
- name: Azure Login with OpenID Connect
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Determine validation type and pipeline ID
id: validation-type
run: |
COMMENT_BODY="${{ github.event.comment.body }}"
if echo "$COMMENT_BODY" | grep -q "/dart"; then
echo "type=dart" >> $GITHUB_OUTPUT
echo "pipeline-id=15324" >> $GITHUB_OUTPUT
elif echo "$COMMENT_BODY" | grep -q "/pr-val"; then
echo "type=pr-val" >> $GITHUB_OUTPUT
echo "pipeline-id=8972" >> $GITHUB_OUTPUT
fi
- name: Trigger Pipeline
id: trigger-pipeline
run: |
# Get Azure DevOps access token
AZDO_TOKEN=$(az account get-access-token --resource 499b84ac-1321-427f-aa17-267ca6975798 --query accessToken -o tsv)
VALIDATION_TYPE="${{ steps.validation-type.outputs.type }}"
PIPELINE_ID="${{ steps.validation-type.outputs.pipeline-id }}"
DEVDIV_ORG="devdiv"
DEVDIV_PROJECT="DevDiv"
# Determine if commit was explicitly provided (EnforceLatestCommit should be false if commit was provided)
HAS_COMMIT="${{ steps.parse-commit.outputs.has-commit }}"
if [ "$HAS_COMMIT" = "true" ]; then
ENFORCE_LATEST="false"
else
ENFORCE_LATEST="true"
fi
echo "Triggering DevDiv $VALIDATION_TYPE pipeline (ID: $PIPELINE_ID)..."
echo "EnforceLatestCommit: $ENFORCE_LATEST"
# Build request body based on validation type
if [ "$VALIDATION_TYPE" = "dart" ]; then
# DART pipeline uses prNumber and sha parameters
REQUEST_BODY=$(cat <<EOF
{
"templateParameters": {
"prNumber": "${{ github.event.issue.number }}",
"sha": "${{ steps.commit-sha.outputs.sha }}",
"EnforceLatestCommit": "$ENFORCE_LATEST"
}
}
EOF
)
else
# PR-Val pipeline uses PRNumber and CommitSHA parameters
REQUEST_BODY=$(cat <<EOF
{
"templateParameters": {
"PRNumber": ${{ github.event.issue.number }},
"CommitSHA": "${{ steps.commit-sha.outputs.sha }}",
"EnforceLatestCommit": "$ENFORCE_LATEST"
}
}
EOF
)
fi
echo "Request body: $REQUEST_BODY"
# Trigger the pipeline
RESPONSE=$(curl -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $AZDO_TOKEN" \
-d "$REQUEST_BODY" \
"https://dev.azure.com/$DEVDIV_ORG/$DEVDIV_PROJECT/_apis/pipelines/$PIPELINE_ID/runs?api-version=7.0")
echo "Response: $RESPONSE"
# Extract pipeline run information
BUILD_ID=$(echo $RESPONSE | jq -r '.id // empty')
if [ -z "$BUILD_ID" ]; then
echo "Failed to trigger pipeline"
echo "Error details: $(echo $RESPONSE | jq -r '.message // "Unknown error"')"
exit 1
fi
WEB_URL="https://dev.azure.com/$DEVDIV_ORG/$DEVDIV_PROJECT/_build/results?buildId=$BUILD_ID"
echo "pipeline-url=$WEB_URL" >> $GITHUB_OUTPUT
echo "build-id=$BUILD_ID" >> $GITHUB_OUTPUT
echo "Successfully triggered pipeline: $WEB_URL"
- name: Comment pipeline link
if: success()
uses: actions/github-script@v7
with:
script: |
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `Pipeline triggered by @${context.actor}\n\n[View Pipeline Run](${{ steps.trigger-pipeline.outputs.pipeline-url }})\n\n**Parameters:**\n- Validation Type: \`${{ steps.validation-type.outputs.type }}\`\n- Pipeline ID: \`${{ steps.validation-type.outputs.pipeline-id }}\`\n- PR Number: \`${{ github.event.issue.number }}\`\n- Commit SHA: \`${{ steps.commit-sha.outputs.sha }}\`\n- Source Branch: \`${{ steps.pr-details.outputs.ref }}\`\n- Build ID: \`${{ steps.trigger-pipeline.outputs.build-id }}\``
});
- name: Comment on failure
if: failure()
uses: actions/github-script@v7
with:
script: |
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: 'Failed to trigger the pipeline. Please check the workflow logs for details.'
});