-
Notifications
You must be signed in to change notification settings - Fork 349
132 lines (119 loc) · 5.06 KB
/
redirect-pull-requests.yml
File metadata and controls
132 lines (119 loc) · 5.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
name: Redirect Pull Requests
on:
pull_request_target:
types: [opened]
permissions:
pull-requests: write
jobs:
redirect:
runs-on: ubuntu-latest
steps:
- name: Check org membership and redirect
uses: actions/github-script@v7
with:
script: |
const pr = context.payload.pull_request;
const author = pr.user.login;
// Allow PRs from trusted automation bots (e.g., repo sync)
const allowedBots = ['foundry-samples-repo-sync[bot]'];
if (allowedBots.includes(author)) {
console.log(`Skipping redirect for allowed bot: ${author}`);
return;
}
// Check if author is a Microsoft contributor using multiple signals.
// The GITHUB_TOKEN can only see *public* members of the 'microsoft' org
// (since this repo is in the 'microsoft-foundry' org), so we cascade
// through several checks to catch contributors with private membership.
let isInternal = false;
let matchedSignal = null;
// Signal 1: Check microsoft-foundry org membership (full visibility via GITHUB_TOKEN)
try {
const res = await github.rest.orgs.checkMembershipForUser({
org: 'microsoft-foundry',
username: author,
});
if (res.status === 204) {
isInternal = true;
matchedSignal = 'microsoft-foundry org member';
}
} catch {
// 404 or 302 means not a member
}
// Signal 2: Check if author is a collaborator on this repo
if (!isInternal) {
try {
const res = await github.rest.repos.checkCollaborator({
owner: context.repo.owner,
repo: context.repo.repo,
username: author,
});
if (res.status === 204) {
isInternal = true;
matchedSignal = 'repo collaborator';
}
} catch {
// 404 means not a collaborator
}
}
// Signal 3: Check microsoft org membership (catches public members only)
if (!isInternal) {
try {
const res = await github.rest.orgs.checkMembershipForUser({
org: 'microsoft',
username: author,
});
if (res.status === 204) {
isInternal = true;
matchedSignal = 'microsoft org member (public)';
}
} catch {
// 404 or 302 means not a member (or private membership not visible)
}
}
console.log(`Author: ${author}, isInternal: ${isInternal}, signal: ${matchedSignal || 'none'}`);
let body;
if (isInternal) {
body = [
`👋 Thanks for your contribution, @${author}!`,
'',
'This repository is read-only. As a Microsoft contributor, please submit your PR to the private staging repository instead:',
'',
'👉 **[foundry-samples-pr](https://github.com/microsoft-foundry/foundry-samples-pr)**',
'',
'See [CONTRIBUTING.md](https://github.com/microsoft-foundry/foundry-samples/blob/main/CONTRIBUTING.md) for full instructions.',
].join('\n');
} else {
body = [
`👋 Thanks for your interest in contributing, @${author}!`,
'',
'This repository does not accept pull requests directly. If you\'d like to report a bug, suggest an improvement, or propose a new sample, please **[open an issue](https://github.com/microsoft-foundry/foundry-samples/issues/new)** instead.',
'',
'See [CONTRIBUTING.md](https://github.com/microsoft-foundry/foundry-samples/blob/main/CONTRIBUTING.md) for more details.',
].join('\n');
}
// Skip if the bot already commented (idempotent on re-runs)
const comments = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
});
const alreadyCommented = comments.data.some(c =>
c.user.login === 'github-actions[bot]' &&
c.body.includes('This repository')
);
if (alreadyCommented) {
console.log('Bot already commented on this PR, skipping.');
return;
}
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
body,
});
await github.rest.pulls.update({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pr.number,
state: 'closed',
});