Skip to content

Let Plus devices share a short restore code or QR #130

Let Plus devices share a short restore code or QR

Let Plus devices share a short restore code or QR #130

Workflow file for this run

name: ✍️ CLA
on:
pull_request:
branches:
- main
types:
- opened
- reopened
- synchronize
issue_comment:
types:
- created
- edited
permissions:
contents: read
jobs:
cla:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
name: ✍️ CLA
timeout-minutes: 5
permissions:
contents: read
pull-requests: write
steps:
- name: 📦 Checkout base
uses: actions/checkout@v6.0.2
with:
ref: ${{ github.event.pull_request.base.ref }}
persist-credentials: false
- name: 🟢 Setup Node
uses: actions/setup-node@v6
with:
node-version: 24
- name: 🧾 Collect identities
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
const identities = [
{
githubLogin: context.payload.pull_request.user.login,
name: context.payload.pull_request.user.login,
email: null,
},
]
const commits = await github.paginate(
github.rest.pulls.listCommits,
{
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.payload.pull_request.number,
per_page: 100,
},
)
for (const commit of commits) {
identities.push({
githubLogin: commit.author?.login ?? null,
name: commit.commit.author?.name ?? null,
email: commit.commit.author?.email ?? null,
})
}
const fs = await import('node:fs/promises')
await fs.writeFile(
'cla-identities.json',
`${JSON.stringify(identities, null, '\t')}\n`,
)
- name: ✍️ Check CLA
id: check
run: |
if [ ! -f tools/ci/check-cla.mjs ] || [ ! -f .github/cla-signers.json ]; then
echo "CLA checker is not on the base branch yet."
exit 0
fi
set +e
node tools/ci/check-cla.mjs \
--signers .github/cla-signers.json \
--identities-json cla-identities.json
code=$?
echo "exit_code=$code" >> "$GITHUB_OUTPUT"
if [ "$code" -ne 0 ] && [ "$code" -ne 1 ]; then
exit "$code"
fi
- name: 💬 Comment when unsigned
if: steps.check.outputs.exit_code == '1'
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
script: |
const marker = '<!-- kody-cla-check -->'
const body = `${marker}
Unsigned contributions cannot merge.
1. Read the [Individual CLA](https://github.com/${{ github.repository }}/blob/main/docs/legal/individual-cla.md) (or the [Entity CLA](https://github.com/${{ github.repository }}/blob/main/docs/legal/entity-cla.md) if an organization owns the work).
2. Comment exactly: \`I have read the CLA and I hereby sign the CLA\`
3. The CLA workflow records your GitHub username on \`main\` and re-runs this check. See [Inbound contributions](https://github.com/${{ github.repository }}/blob/main/docs/contribute/inbound-contributions.md).
Adding your own username on this branch does not pass the check.`
const comments = await github.paginate(
github.rest.issues.listComments,
{
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
per_page: 100,
},
)
const existing = comments.find((comment) =>
comment.body?.includes(marker),
)
if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
})
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
body,
})
}
- name: ❌ Fail when unsigned
if: steps.check.outputs.exit_code == '1'
run: exit 1
record:
if: >
github.event_name == 'issue_comment' && github.event.issue.pull_request &&
github.event.comment.user.type == 'User' &&
contains(github.event.comment.body, 'I hereby sign the CLA')
runs-on: ubuntu-latest
name: 📝 Record CLA
timeout-minutes: 5
concurrency:
group: cla-signers-main
cancel-in-progress: false
permissions:
contents: write
pull-requests: write
actions: write
steps:
- name: 📦 Checkout main
uses: actions/checkout@v6.0.2
with:
ref: main
- name: 🟢 Setup Node
uses: actions/setup-node@v6
with:
node-version: 24
- name: 📝 Record signer
id: record
env:
CLA_COMMENT: ${{ github.event.comment.body }}
CLA_LOGIN: ${{ github.event.comment.user.login }}
CLA_SIGNED_AT: ${{ github.event.comment.created_at }}
run: |
if [ ! -f tools/ci/check-cla.mjs ] || [ ! -f .github/cla-signers.json ]; then
echo "skipped=true" >> "$GITHUB_OUTPUT"
echo "added=false" >> "$GITHUB_OUTPUT"
exit 0
fi
printf '%s' "$CLA_COMMENT" > cla-comment.txt
node tools/ci/check-cla.mjs \
--signers .github/cla-signers.json \
--record-signer "$CLA_LOGIN" \
--signed-at "${CLA_SIGNED_AT%%T*}" \
--comment-file cla-comment.txt > cla-record-output.txt
cat cla-record-output.txt
grep -E '^(skipped|added|github)=' cla-record-output.txt >> "$GITHUB_OUTPUT"
- name: 💾 Commit signer on main
if: steps.record.outputs.added == 'true'
env:
CLA_GITHUB: ${{ steps.record.outputs.github }}
run: |
git config user.name 'github-actions[bot]'
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
git add .github/cla-signers.json
git commit -m "Record @${CLA_GITHUB} as an individual CLA signer"
git pull --rebase origin main
git push origin HEAD:main
- name: 💬 Comment and re-run CLA
if: steps.record.outputs.skipped == 'false'
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
env:
CLA_ADDED: ${{ steps.record.outputs.added }}
CLA_GITHUB: ${{ steps.record.outputs.github }}
with:
script: |
const login = process.env.CLA_GITHUB
const added = process.env.CLA_ADDED === 'true'
const marker = '<!-- kody-cla-recorded -->'
const owner = context.repo.owner
const repo = context.repo.repo
const pull = await github.rest.pulls.get({
owner,
repo,
pull_number: context.payload.issue.number,
})
const headSha = pull.data.head.sha
async function latestClaRun() {
const runs = await github.rest.actions.listWorkflowRuns({
owner,
repo,
workflow_id: 'cla.yml',
event: 'pull_request',
head_sha: headSha,
per_page: 5,
})
return runs.data.workflow_runs[0] ?? null
}
const deadline = Date.now() + 180_000
let latest = await latestClaRun()
while (latest && latest.status !== 'completed' && Date.now() < deadline) {
await new Promise((resolve) => setTimeout(resolve, 10_000))
latest = await latestClaRun()
}
let reran = false
if (latest?.status === 'completed') {
try {
await github.rest.actions.reRunWorkflow({
owner,
repo,
run_id: latest.id,
})
reran = true
} catch (error) {
core.warning(
`Could not re-run CLA: ${error instanceof Error ? error.message : String(error)}`,
)
}
}
const followUp = reran
? 'The CLA check will re-run.'
: 'The next CLA check will read the updated signers file.'
const body = added
? `${marker}
Recorded @${login} as an individual CLA signer on \`main\`. ${followUp}`
: `${marker}
@${login} is already recorded as an individual CLA signer. ${followUp}`
const comments = await github.paginate(
github.rest.issues.listComments,
{
owner,
repo,
issue_number: context.payload.issue.number,
per_page: 100,
},
)
const existing = comments.find((comment) =>
comment.body?.includes(marker),
)
if (existing) {
await github.rest.issues.updateComment({
owner,
repo,
comment_id: existing.id,
body,
})
} else {
await github.rest.issues.createComment({
owner,
repo,
issue_number: context.payload.issue.number,
body,
})
}