forked from ClickHouse/clickhouse-docs
-
Notifications
You must be signed in to change notification settings - Fork 0
288 lines (236 loc) · 11.7 KB
/
trademark-cla-approval.yml
File metadata and controls
288 lines (236 loc) · 11.7 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
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
name: CLA Approval Handler
on:
issue_comment:
types: [created]
permissions: write-all
jobs:
process-cla-comment:
runs-on: ubuntu-latest
if: github.event_name == 'issue_comment' && github.actor != 'workflow-authentication-public[bot]'
steps:
- name: Generate Token
id: generate-token
continue-on-error: true
uses: actions/create-github-app-token@v2
with:
app-id: "${{ secrets.WORKFLOW_AUTH_PUBLIC_APP_ID }}"
private-key: "${{ secrets.WORKFLOW_AUTH_PUBLIC_PRIVATE_KEY }}"
- name: Process CLA Agreement Comment
id: process-comment
uses: actions/github-script@v7
with:
github-token: ${{ steps.generate-token.outputs.token || secrets.GITHUB_TOKEN }}
script: |
// Only process comments on pull requests
if (!context.payload.issue.pull_request) {
console.log('Comment is not on a pull request, skipping...');
return;
}
const prNumber = context.payload.issue.number;
const commentBody = context.payload.comment.body;
const commenter = context.payload.comment.user.login;
console.log(`Processing comment on PR #${prNumber} from ${commenter}`);
// Check if this is a CLA agreement comment
const isClaAgreement = commentBody.includes('I agree to the Trademark License Addendum') &&
commentBody.includes('CLA-SIGNATURE:');
if (!isClaAgreement) {
console.log('Comment is not a CLA agreement, skipping...');
return;
}
console.log('Found CLA agreement comment, validating...');
// Extract the signature from the comment
const signatureMatch = commentBody.match(/CLA-SIGNATURE:\s*(\S+)/);
if (!signatureMatch) {
console.log('CLA signature format is invalid');
return;
}
const signatureUser = signatureMatch[1];
// Get PR details to verify the commenter is the PR author
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber
});
const prAuthor = pr.user.login;
console.log(`PR author: ${prAuthor}, commenter: ${commenter}, signature: ${signatureUser}`);
// If someone other than PR author is trying to sign, silently ignore
if (commenter !== prAuthor) {
console.log(`Comment with CLA text from ${commenter} (not PR author ${prAuthor}), ignoring silently`);
return;
}
// If PR author is signing but signature doesn't match their username, silently ignore
if (signatureUser !== commenter) {
console.log(`PR author ${commenter} used incorrect signature '${signatureUser}', ignoring silently`);
return;
}
// Check if PR has trademark-addendum-required label
const { data: labels } = await github.rest.issues.listLabelsOnIssue({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber
});
const hasTrademarkRequired = labels.some(label => label.name === 'trademark-addendum-required');
const hasTrademarkSigned = labels.some(label => label.name === 'trademark-addendum-signed');
if (!hasTrademarkRequired) {
console.log('PR does not have trademark-addendum-required label, skipping...');
return;
}
if (hasTrademarkSigned) {
console.log('PR already has trademark-addendum-signed label, skipping...');
return;
}
console.log('Valid CLA agreement from PR author, processing...');
// Remove blocking labels
try {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
name: 'trademark-addendum-required'
});
console.log('Removed trademark-addendum-required label');
} catch (e) {
console.log('trademark-addendum-required label not found or already removed');
}
try {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
name: 'integrations-with-image-change'
});
console.log('Removed integrations-with-image-change label');
} catch (e) {
console.log('integrations-with-image-change label not found or already removed');
}
// Add trademark-addendum-signed label
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
labels: ['trademark-addendum-signed']
});
console.log('Added trademark-addendum-signed label successfully');
// Store signature details for the next step
core.setOutput('pr_number', prNumber);
core.setOutput('pr_author', prAuthor);
core.setOutput('approved_by', prAuthor);
core.setOutput('pr_head_sha', pr.head.sha);
core.setOutput('pr_head_ref', pr.head.ref);
core.setOutput('pr_head_repo_full_name', pr.head.repo.full_name);
core.setOutput('is_fork', pr.head.repo.full_name !== context.repo.owner + '/' + context.repo.repo);
// Add confirmation comment
const confirmationBody = [
'## Trademark license agreement confirmed ✅',
'',
`The trademark license agreement has been confirmed for @${prAuthor}.`,
'',
'**Status:** Confirmed',
`**Date:** ${new Date().toISOString()}`,
'**Method:** Self-signed agreement via comment',
'',
'This PR is now unblocked and can proceed with normal review.'
].join('\n');
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body: confirmationBody
});
console.log(`✅ CLA agreement processed successfully for ${prAuthor}`);
- name: Check out repository
if: success() && steps.process-comment.outputs.pr_number != ''
uses: actions/checkout@v6
with:
fetch-depth: 0
# For forked PRs, we need to fetch from the fork and checkout the SHA
# For non-fork PRs, we can checkout the branch directly
ref: ${{ steps.process-comment.outputs.is_fork == 'true' && steps.process-comment.outputs.pr_head_sha || steps.process-comment.outputs.pr_head_ref }}
token: ${{ steps.generate-token.outputs.token || secrets.GITHUB_TOKEN }}
- name: Record signature to file
id: record-signature
if: success() && steps.process-comment.outputs.pr_number != ''
run: |
set -e
echo "=== Recording signature immediately after label addition ==="
# Debug: Check current working directory and branch
echo "=== Debug Info ==="
pwd
echo "Current branch: $(git branch --show-current)"
echo "Git remote: $(git remote -v)"
ls -la contribute/ 2>/dev/null || echo "contribute/ directory does not exist"
# Get signature details
USERNAME="${{ steps.process-comment.outputs.pr_author }}"
DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
PR_NUMBER="${{ steps.process-comment.outputs.pr_number }}"
APPROVED_BY="${{ steps.process-comment.outputs.approved_by }}"
echo "Recording signature for PR #$PR_NUMBER"
echo " Username: $USERNAME"
echo " Approved by: $APPROVED_BY"
echo " Date: $DATE"
# Ensure contribute directory exists
mkdir -p contribute
# Signature file
SIGNATURES_FILE="contribute/trade-addendum-signatures.json"
# Create or read existing signatures file
if [ ! -f "$SIGNATURES_FILE" ]; then
echo '{"signatures": []}' > "$SIGNATURES_FILE"
echo "Created new signatures file"
fi
# Check if signature already exists
EXISTING=$(jq --arg user "$USERNAME" --arg pr "$PR_NUMBER" '.signatures[] | select(.username == $user and .pr_number == ($pr | tonumber))' "$SIGNATURES_FILE" 2>/dev/null || echo "")
if [ -z "$EXISTING" ]; then
# Add new signature
echo "Adding signature to file..."
jq --arg user "$USERNAME" \
--arg date "$DATE" \
--arg pr "$PR_NUMBER" \
--arg approved_by "$APPROVED_BY" \
'.signatures += [{
"username": $user,
"date": $date,
"pr_number": ($pr | tonumber),
"approved_by": $approved_by
}]' "$SIGNATURES_FILE" > tmp.json && mv tmp.json "$SIGNATURES_FILE"
echo "✅ Added signature for $USERNAME"
echo "File contents after update:"
cat "$SIGNATURES_FILE"
else
echo "ℹ️ Signature already exists for $USERNAME on PR #$PR_NUMBER"
fi
# Configure git
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
# Debug: Check git status
echo "=== Git status ==="
git status
echo "=== Git diff ==="
git diff "$SIGNATURES_FILE"
# Add the file to git and commit
git add "$SIGNATURES_FILE"
# Store signature in ClickHouse
echo "Storing signature in ClickHouse..."
# Format date for ClickHouse DateTime (YYYY-MM-DD HH:MM:SS)
CH_DATE=$(date -u +"%Y-%m-%d %H:%M:%S")
# Prepare SQL INSERT query
SQL_QUERY="INSERT INTO docs_trademark_agreements.signatures (date, user_name, pr_number) VALUES ('$CH_DATE', '$USERNAME', $PR_NUMBER)"
echo "Executing SQL: $SQL_QUERY"
# Send to ClickHouse
RESPONSE=$(curl -s -w "%{http_code}" -o /tmp/ch_response.txt \
-X POST \
-H "x-clickhouse-user: docs_feedback" \
-H "x-clickhouse-key: " \
-H "Content-Type: text/plain" \
-d "$SQL_QUERY" \
"https://sql-clickhouse.clickhouse.com")
HTTP_CODE="${RESPONSE: -3}"
RESPONSE_BODY=$(cat /tmp/ch_response.txt)
if [ "$HTTP_CODE" = "200" ]; then
echo "✅ Signature stored successfully in ClickHouse"
else
echo "❌ Failed to store signature in ClickHouse"
echo "HTTP Code: $HTTP_CODE"
echo "Response: $RESPONSE_BODY"
# Don't exit 1 here - we don't want to fail the workflow if ClickHouse is down
echo "⚠️ Continuing workflow despite ClickHouse error"
fi