Auto-start Cosmos emulator via Testcontainers #908
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # This workflow automatically closes PRs from external contributors (those without push permissions) | |
| # that target release/* branches. It posts a comment asking them to resubmit with the correct target branch. | |
| # | |
| # External contributors should not target release/* branches per our contribution guidelines. | |
| # Internal contributors (with push permissions) can target any branch as needed. | |
| name: Validate PR Target Branch | |
| on: | |
| pull_request_target: | |
| types: [opened, edited, reopened] | |
| permissions: | |
| pull-requests: write | |
| issues: write | |
| jobs: | |
| validate: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check PR target branch and author permissions | |
| uses: actions/github-script@v8 | |
| with: | |
| script: | | |
| const pr = context.payload.pull_request; | |
| const targetBranch = pr.base.ref; | |
| const prNumber = pr.number; | |
| const prAuthor = pr.user.login; | |
| const action = context.payload.action; | |
| const triggeredBy = context.actor; | |
| console.log(`PR #${prNumber} by ${prAuthor} targets branch: ${targetBranch}`); | |
| console.log(`Action: ${action}, triggered by: ${triggeredBy}`); | |
| // Helper function to check if a user is a bot | |
| const isBot = (username) => { | |
| const lower = username.toLowerCase(); | |
| return lower === 'copilot' || | |
| lower === 'dotnet-bot' || | |
| lower.startsWith('app/') || | |
| lower.includes('[bot]'); | |
| }; | |
| // If action is 'edited', check if the base branch was actually changed | |
| if (action === 'edited' && !context.payload.changes?.base) { | |
| console.log('PR was edited but base branch was not changed - skipping'); | |
| return; | |
| } | |
| // Skip if triggered by a bot or PR is authored by a bot | |
| if (isBot(triggeredBy) || isBot(prAuthor)) { | |
| console.log('Bot detected - skipping'); | |
| return; | |
| } | |
| // If the PR is from a branch (not a fork), it must be from an internal contributor | |
| if (pr.head.repo && pr.head.repo.id === pr.base.repo.id) { | |
| console.log('PR is from a branch in the same repo - skipping validation'); | |
| return; | |
| } | |
| // Check if the user who triggered the action has push permissions | |
| let hasWriteAccess = false; | |
| try { | |
| const { data: permissions } = await github.rest.repos.getCollaboratorPermissionLevel({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| username: triggeredBy | |
| }); | |
| hasWriteAccess = ['admin', 'write'].includes(permissions.permission); | |
| console.log(`User ${triggeredBy} has permission level: ${permissions.permission}`); | |
| } catch (error) { | |
| // If the user cannot be found (e.g. non-user accounts like Copilot), skip | |
| if (error.status === 404) { | |
| console.log(`User ${triggeredBy} not found - skipping`); | |
| return; | |
| } | |
| console.error('Error checking permissions:', error); | |
| // If we can't determine permissions for other reasons, skip to avoid false positives | |
| return; | |
| } | |
| // Check if target branch is a release branch | |
| if (!targetBranch.startsWith('release/')) { | |
| // For new PRs by external contributors, add community-contribution label | |
| if (action === 'opened' && !hasWriteAccess) { | |
| try { | |
| console.log('Adding community-contribution label'); | |
| await github.rest.issues.addLabels({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: prNumber, | |
| labels: ['community-contribution'] | |
| }); | |
| } catch (error) { | |
| console.error('Error adding label:', error); | |
| } | |
| } | |
| console.log('PR does not target a release branch - allowed'); | |
| return; | |
| } | |
| // If user has write access, allow PR to release branch | |
| if (hasWriteAccess) { | |
| console.log('User has write access - allowed'); | |
| return; | |
| } | |
| // External contributor targeting release branch - close and comment | |
| console.log('External contributor targeting release branch - closing PR'); | |
| try { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: prNumber, | |
| body: `Thank you for your contribution! However, this PR targets the \`${targetBranch}\` branch.\n\nExternal contributions should not target release branches. This pull request has been closed automatically; please open a new pull request targeting \`main\` or another non-release branch.\n\nFor more information, see our [contribution guidelines](https://github.com/${context.repo.owner}/${context.repo.repo}/blob/main/.github/CONTRIBUTING.md).` | |
| }); | |
| await github.rest.pulls.update({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| pull_number: prNumber, | |
| state: 'closed' | |
| }); | |
| console.log('PR closed successfully'); | |
| } catch (error) { | |
| console.error('Error closing PR:', error); | |
| } |