-
Notifications
You must be signed in to change notification settings - Fork 484
251 lines (224 loc) · 12.3 KB
/
Copy pathtrademark-cla-notice.yml
File metadata and controls
251 lines (224 loc) · 12.3 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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
name: Trademark CLA Notice
on:
pull_request_target:
types: [opened, edited, synchronize]
issue_comment:
types: [created]
# Set repository-level permissions
permissions: write-all
jobs:
enforce-docs-cla:
runs-on: ubuntu-latest
# Job-level permissions (inherits from above but can be more restrictive)
permissions: write-all
steps:
- name: Generate Token
id: generate-token
continue-on-error: true
uses: actions/create-github-app-token@v3
with:
app-id: "${{ secrets.WORKFLOW_AUTH_PUBLIC_APP_ID }}"
private-key: "${{ secrets.WORKFLOW_AUTH_PUBLIC_PRIVATE_KEY }}"
- name: Check out code
uses: actions/checkout@v6
with:
fetch-depth: 0
# Use the GitHub App token if available, otherwise fallback to GITHUB_TOKEN
token: ${{ steps.generate-token.outputs.token || secrets.GITHUB_TOKEN }}
# For pull_request_target, we need to fetch the PR head
ref: ${{ github.event.pull_request.head.sha }}
- name: Check if docs changed
id: docs-changed
if: github.event_name == 'pull_request_target'
uses: actions/github-script@v7
with:
github-token: ${{ steps.generate-token.outputs.token || secrets.GITHUB_TOKEN }}
script: |
// Get the list of changed files using GitHub API
const { data: files } = await github.rest.pulls.listFiles({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.payload.pull_request.number
});
// Check if any files match our patterns
const hasDocsChanges = files.some(file =>
file.filename.startsWith('docs/integrations/') &&
file.filename.startsWith('static/images')
);
console.log('Changed files:');
files.forEach(file => console.log(` ${file.filename}`));
if (hasDocsChanges) {
console.log('Found changes in docs/integrations/ or static/images - trademark addendum signature required');
core.setOutput('docs_changed', 'true');
core.setOutput('requires_cla', 'true');
} else {
console.log('No changes found in docs/integrations/ or static/images - trademark addendum signature not required');
core.setOutput('docs_changed', 'false');
core.setOutput('requires_cla', 'false');
}
- name: Get PR info for comment events
id: pr-info
if: github.event_name == 'issue_comment'
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_PAT || secrets.GITHUB_TOKEN }}
script: |
if (context.payload.issue.pull_request) {
const prNumber = context.payload.issue.number;
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber
});
const { data: files } = await github.rest.pulls.listFiles({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber
});
const hasDocsChanges = files.some(file =>
file.filename.startsWith('docs/integrations/') &&
file.filename.startsWith('static/images/')
);
// Check if PR author is a collaborator (safer alternative to org membership)
let isClickHouseMember = false;
try {
const { data: collaboration } = await github.rest.repos.getCollaboratorPermissionLevel({
owner: context.repo.owner,
repo: context.repo.repo,
username: pr.user.login
});
// Consider admin, maintain, or write permissions as "member"
isClickHouseMember = ['admin', 'maintain', 'write'].includes(collaboration.permission);
} catch (error) {
console.log(`Could not determine collaboration status for ${pr.user.login}: ${error.message}`);
isClickHouseMember = false;
}
core.setOutput('pr_number', prNumber);
core.setOutput('has_docs_changes', hasDocsChanges);
core.setOutput('pr_head_sha', pr.head.sha);
core.setOutput('pr_author', pr.user.login);
core.setOutput('isClickHouseMember', isClickHouseMember);
return { prNumber, hasDocsChanges, headSha: pr.head.sha, author: pr.user.login, isClickHouseMember };
}
return null;
- name: Post CLA comment and block merge
if: github.event_name == 'pull_request_target' && steps.docs-changed.outputs.requires_cla == 'true'
uses: actions/github-script@v7
with:
github-token: ${{ steps.generate-token.outputs.token || secrets.GITHUB_TOKEN }}
script: |
let prNumber, prAuthor;
if (context.eventName == 'pull_request_target') {
prNumber = context.issue.number;
prAuthor = '${{ github.event.pull_request.user.login }}';
}
if (!prNumber || !prAuthor) {
return;
}
try {
// Check if user is in @ClickHouse/everyone team
let isClickHouseMember = false;
try {
await github.rest.teams.getMembershipForUserInOrg({
org: 'ClickHouse',
team_slug: 'everyone',
username: prAuthor
});
isClickHouseMember = true;
} catch (error) {
// User is not in the team or team doesn't exist
isClickHouseMember = false;
}
// Skip CLA requirement for ClickHouse team members
if (isClickHouseMember) {
return;
}
// Check if CLA comment already exists
const comments = await github.rest.issues.listComments({
issue_number: prNumber,
owner: context.repo.owner,
repo: context.repo.repo,
});
const existingClaComment = comments.data.find(comment =>
(comment.user.login === 'github-actions[bot]' || comment.user.type === 'Bot') &&
comment.body.includes('CLA Agreement Required - MERGE BLOCKED')
);
if (!existingClaComment && context.eventName === 'pull_request_target') {
const claText = '# Trademark License Addendum\n\n' +
'Merging of this pull request is temporarily blocked as it potentially ' +
'contains a contribution containing a trademark. Please \n' +
'read and agree to the Trademark License Addendum below to \n' +
'unblock merging of this pull request.\n\n' +
'<details>\n' +
'<summary>Click to see Trademark License Addendum</summary>\n\n' +
'This Trademark License Addendum ("Addendum") shall, if You have opted \n' +
'in by replying to the comment that references this Addendum that you\n' +
'have read and agree to theContributor License Agreement Addendum,\n' +
'supplement the terms of the Individual Contributor License Agreement\n' +
'between You and the Company ("Agreement"). Capitalized terms not\n' +
'defined herein shall have the meanings ascribed to them in the \n' +
'Agreement.\n\n' +
'1. Grant of Trademark License. Subject to the terms and conditions \n' +
'of this Addendum, You grant to the Company a revocable, worldwide,\n' +
'non-exclusive, non-sublicensable (except for contractors or agents\n' +
'acting on the Company\'s behalf, for whose compliance with this \n' +
'Addendum Company agrees to be responsible), royalty-free, and non-transferable\n' +
'right to display the Partner Trademarks, solely for the purpose of\n' +
'marketing and promoting your Contribution (i) on the Company\'s website\n' +
'and in any Company in-product integrations page; and (ii) in marketing, sales,\n' +
'and product materials for Company products. "Partner Trademarks" mean Your \n' +
'employer\'s name and any employer brand features (e.g., logo) You submit now or \n' +
'in the future to the Company in connection with your Contributions.\n' +
'2. Legal authority. You represent that you are legally entitled to\n' +
'grant the above license. If your employer(s) has rights to \n' +
'intellectual property in the Partner Trademarks, you represent that\n' +
'you have received permission to grant the above license on behalf \n' +
'of that employer, or that your employer has executed a separate \n' +
'agreement with the Company concerning the subject matter of this \n' +
'Addendum.\n' +
'3. Conditions. The license in Section 1 is subject to the following\n' +
'conditions:\n' +
'i. The Company shall use the Partner Trademarks in accordance with\n' +
' any reasonable trademark usage guidelines You provide;\n' +
'ii. You may revoke this license at any time upon thirty (30) days\'\n' +
' written notice to the Company, after which the Company shall use\n' +
' commercially reasonable efforts to cease all further public\n' +
' use of the Partner Trademarks (but may maintain uses in archived\n' +
' web pages, changelogs, and previously distributed materials).\n' +
'iii. The Company acknowledges and agrees that it does not own the \n' +
' Partner Trademarks and that all goodwill derived from the use \n' +
' of the Partner Trademarks inures solely to benefit of the \n' +
' Partner Trademarks\' owner(s).\n' +
'iv. The Company shall use the Partner Trademarks in a professional\n' +
' manner consistent with industry standards and shall not use \n' +
' them in any way that would reasonably be expected to diminish \n' +
' their value or harm the reputation of the Partner Trademarks\' \n' +
' owner(s). The Company\'s use of Partner Trademarks shall not \n' +
' imply endorsement, sponsorship, or affiliation beyond the \n' +
' existence of the Contribution in the Company\'s integration program.\n' +
'v. The Company will not use the Partner Trademarks in connection \n' +
' with search engine rankings, ad word purchases, or as part of a\n' +
' trade name, business name, or Internet domain name.\n\n' +
'</details>\n\n' +
'**To unblock this PR, reply with exactly:**\n' +
'```\n' +
'I agree to the Trademark License Addendum\n' +
'CLA-SIGNATURE: ' + prAuthor + '\n' +
'```';
await github.rest.issues.createComment({
issue_number: prNumber,
owner: context.repo.owner,
repo: context.repo.repo,
body: claText
});
await github.rest.issues.addLabels({
issue_number: prNumber,
owner: context.repo.owner,
repo: context.repo.repo,
labels: ['trademark-addendum-required', 'integrations-with-image-change']
});
}
} catch (error) {
console.error('Error in CLA comment step:', error);
throw error;
}