Update upgrades.md #354
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
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@v1 | |
with: | |
app-id: "${{ secrets.WORKFLOW_AUTH_PUBLIC_APP_ID }}" | |
private-key: "${{ secrets.WORKFLOW_AUTH_PUBLIC_PRIVATE_KEY }}" | |
- name: Check out code | |
uses: actions/checkout@v4 | |
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; | |
} |