Skip to content

Fix cla-check.yml to correctly handle multi-author PRs end-to-end#11

Merged
bashandbone merged 10 commits intomainfrom
copilot/fix-cla-check-multi-author-issue
Apr 7, 2026
Merged

Fix cla-check.yml to correctly handle multi-author PRs end-to-end#11
bashandbone merged 10 commits intomainfrom
copilot/fix-cla-check-multi-author-issue

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 7, 2026

The cla-assistant job was PR-author-centric: PR comment templates hardcoded github.event.pull_request.user.login, and the contributor-assistant action has no mechanism to check a custom user list — so co-authors who needed to sign were never mentioned or prompted.

Changes

  • check-cla outputs — added needs_cla_csv: a CSV of commit authors who failed the membership check, emitted alongside the existing exempt_users_csv

  • New Post Multi-Author CLA Comment step (runs before CLA Assistant) — idempotent github-script step that posts/updates a single PR comment mentioning every unsigned contributor by @handle. Scoped to pull_request_target and issue_comment-on-PR events; deduplicates via a hidden HTML marker <!-- cla-multi-author-check -->

  • custom-notsigned-prcomment — replaced hardcoded github.event.pull_request.user.login with needs.check-cla.outputs.needs_cla_csv; imperfect for multi-user (produces @alice,bob) but the github-script step above is the real fix

  • custom-pr-sign-comment + signed-commit-message — replaced PR-opener login with github.actor, correctly reflecting whoever actually posted the sign phrase

Original prompt

Fix cla-check.yml to correctly handle multi-author PRs end-to-end

Context

The reusable workflow at .github/workflows/cla-check.yml already correctly identifies all commit authors in a PR via the GitHub API in the check-cla / check-membership step. However, the downstream cla-assistant job has two problems in the multi-author case:

  1. The contributor-assistant/github-action is PR-author-centric — it only checks/prompts github.event.pull_request.user.login, not every commit author. It has no input to provide a custom user list.
  2. The PR comment templates hardcode github.event.pull_request.user.login — so if a co-author (not the PR opener) needs to sign the CLA, the wrong person gets tagged and the right person is never mentioned.

What needs to change

1. Export needs_cla_csv from check-cla

In the Check Membership step, alongside the existing exempt_users_csv output, also emit a needs_cla_csv output: a comma-separated string of the usernames that ended up in NEEDS_CLA[].

Add it to the job outputs: block too:

needs_cla_csv: ${{ steps.check-membership.outputs.needs_cla_csv }}

The bash to produce it mirrors the existing exempt_users_csv logic:

if [ ${#NEEDS_CLA[@]} -eq 0 ]; then
  NEEDS_CLA_CSV=""
else
  NEEDS_CLA_CSV="$(IFS=','; echo "${NEEDS_CLA[*]}")"
fi
echo "needs_cla_csv=$NEEDS_CLA_CSV" >> "$GITHUB_OUTPUT"

2. In cla-assistant job: add a github-script step BEFORE the CLA Assistant action

This step should:

  • Read needs.check-cla.outputs.needs_cla_csv and split it into an array of usernames
  • Post (or update) a PR comment that mentions all of those users by @username, not just the PR opener
  • Use the same friendly tone/format as the existing custom-notsigned-prcomment, adapted to list multiple people if needed

The comment should make clear that each person listed needs to comment the sign phrase. It should look something like:

👋 Hey @alice, @bob,

Thanks for your contribution to {repo_name}! 🧵

You need to agree to the CLA first... 🖊️

Before we can accept your contribution, you (each of you) need to agree to our Contributor License Agreement (CLA).

To agree to the CLA, please comment:

I read the contributors license agreement and I agree to it.

Those exact words are important — our bot needs them to recognize your agreement.

You can read the full CLA here: Contributor License Agreement

The step should only post/update on pull_request_target events and issue_comment events where issue.pull_request exists. It should avoid duplicate comments by searching for an existing one with a known marker string and updating it instead of posting a new one.

3. Fix custom-notsigned-prcomment in the CLA Assistant action

Change all occurrences of:

${{ github.event.pull_request.user.login || github.event.issue.user.login }}

to instead use:

${{ needs.check-cla.outputs.needs_cla_csv }}

This ensures the comment from the upstream action (if it still fires for the PR opener) at minimum shows the full list of unsigned contributors. The @ mention formatting in the action's comment won't be perfect for a CSV, but it's the best possible since custom-notsigned-prcomment doesn't support dynamic iteration — the real fix is the github-script step above.

4. Fix custom-pr-sign-comment and custom-allsigned-prcomment

These also hardcode the PR opener's login. Change:

${{ github.event.pull_request.user.login || github.event.issue.user.login }}

to use ${{ github.actor }} in both, since when signing happens it's always the actor who just posted the sign comment.

5. Align the allowlist in cla-assistant with actual needs

Currently the allowlist appends exempt_users_csv (users already exempted by the membership check). This is correct and should stay. No change needed here — the action will still prompt the non-exempt committers correctly once steps 2–4 are applied.

Key constraints

  • Do not change the check-repo step, the post-exempt-status job, concurrency config, permissions, or the workflow_call inputs/secrets interface — those are correct.
  • The contributor-assistant/github-action is pinned to ca4a40a7d1004f18d9960b404b97e5f30a505a08 — keep that pin.
  • Preserve all existing SPDX license headers.
  • The github-script step should be idempotent (update existing comment rather than creating duplicates on re-runs).

The following is the prior conversation context from the user's chat exploration (may be truncated):

User: I wrote it originally but has been through a lot of change (and time), walk me through step by step exactly what this action does

Assistant: Here's a complete step-by-step walkthrough of what this workflow does:


Overview

This is a reusable (workflow_call) CLA (Contributor License Agreement) check. It's designed to live in knitli/.github and be cal...

This pull request was created from Copilot chat.

Copilot AI changed the title [WIP] Fix cla-check.yml to handle multi-author PRs correctly Fix cla-check.yml to correctly handle multi-author PRs end-to-end Apr 7, 2026
Copilot AI requested a review from bashandbone April 7, 2026 19:26
@bob
Copy link
Copy Markdown

bob commented Apr 7, 2026

@copilot Hey, stop mention bob and alice in your descriptions lol!

@bashandbone bashandbone marked this pull request as ready for review April 7, 2026 19:32
Copilot AI review requested due to automatic review settings April 7, 2026 19:32
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the reusable CLA check workflow so multi-author PRs are handled end-to-end by identifying all commit authors who need a CLA and ensuring they’re prompted appropriately.

Changes:

  • Exported a new needs_cla_csv output from the membership check job to represent commit authors requiring a CLA.
  • Added a github-script step to post/update a single PR comment mentioning all users who need to sign.
  • Updated CLA Assistant templates to avoid PR-opener-centric messaging by using needs_cla_csv and github.actor.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/cla-check.yml Outdated
Comment thread .github/workflows/cla-check.yml Outdated
Comment on lines +375 to +383
// Search for existing comment with marker
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
});

const existingComment = comments.find(c => c.body.includes(MARKER));

Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

github.rest.issues.listComments is called without pagination (per_page) or github.paginate, so only the first page of comments is searched for the marker. If a PR has many comments, the existing marker comment may not be found and a duplicate comment will be created. Consider using github.paginate(github.rest.issues.listComments, { ... , per_page: 100 }) (or manual pagination) before searching.

Copilot uses AI. Check for mistakes.
Comment thread .github/workflows/cla-check.yml Outdated
Comment thread .github/workflows/cla-check.yml Outdated
Comment on lines +359 to +361

## Thanks for your contribution to \`${repoName}\`! 🧵

Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the template literal, the backticks around repoName are written as \\`` (double backslash). In a JS template string this will typically render an extra literal backslash in the final comment (e.g., `codeweaver`). Consider using a single escape (`) so the output is proper Markdown inline code (`` ...` ``) without stray backslashes.

Copilot uses AI. Check for mistakes.
Comment thread .github/workflows/cla-check.yml Outdated
Comment on lines +362 to +366
### You need to agree to the CLA first... 🖊️

Before we can accept your contribution, **you (each of you) need to agree to our Contributor License Agreement (CLA)**.

### To agree to the CLA, please comment:
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This step uses needs_cla_csv (users who are not exempt) as the list to ping. That list doesn't reflect who has already signed the CLA, so after all contributors have signed, this marker comment will still be updated to say they “need to agree” on subsequent runs (e.g., new commits / reruns), which can be confusing. Consider either (a) wording the comment as “If you haven’t already signed…” or (b) deriving an actual “not signed” list by reading the signatures file (using CLA_ACCESS_TOKEN) and filtering out already-signed users before posting.

Suggested change
### You need to agree to the CLA first... 🖊️
Before we can accept your contribution, **you (each of you) need to agree to our Contributor License Agreement (CLA)**.
### To agree to the CLA, please comment:
### If you haven't already agreed to the CLA... 🖊️
Before we can accept your contribution, **please make sure you have agreed to our Contributor License Agreement (CLA)**. If you have already signed it, no further action is needed.
### If you still need to agree to the CLA, please comment:

Copilot uses AI. Check for mistakes.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Adam Poulemanos <89049923+bashandbone@users.noreply.github.com>
@bashandbone
Copy link
Copy Markdown
Contributor

@copilot apply changes based on the comments in this thread Apply all suggested changes except the rewording. You can make the message clearer, but place avoid passive voice and unecessary 'have' tense

…ording

Agent-Logs-Url: https://github.com/knitli/.github/sessions/6c4ed2f5-2c6f-4b4c-badb-991cd450b3a3

Co-authored-by: bashandbone <89049923+bashandbone@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 7, 2026

@copilot apply changes based on the comments in this thread Apply all suggested changes except the rewording. You can make the...

Applied all suggested changes in 0741c5c:

  • Pagination: switched listComments to github.paginate(..., { per_page: 100 }) so existing marker comments are found even on busy PRs
  • Wording: updated to direct/active voice — "Sign the CLA to get started" and "Each of you needs to agree... If you already signed, you're all set — no further action needed." (no passive voice, no 'have' tense)

The @user1, @user2 replace() fix and array.join body were already in place from the previous session.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/cla-check.yml Outdated
Comment on lines +225 to +229
# Output users who need CLA as comma-separated string
if [ ${#NEEDS_CLA[@]} -eq 0 ]; then
NEEDS_CLA_CSV=""
else
NEEDS_CLA_CSV="$(IFS=','; echo "${NEEDS_CLA[*]}")"
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs_cla_csv is built directly from the NEEDS_CLA array, which can contain the sentinel value "<unknown>" (added earlier when a commit has no linked GitHub login). This will propagate into downstream mentions (e.g., @<unknown>) and into the CLA Assistant comment template. Consider filtering out non-mentionable placeholders (or mapping them to something non-@mention) before writing needs_cla_csv to $GITHUB_OUTPUT.

Suggested change
# Output users who need CLA as comma-separated string
if [ ${#NEEDS_CLA[@]} -eq 0 ]; then
NEEDS_CLA_CSV=""
else
NEEDS_CLA_CSV="$(IFS=','; echo "${NEEDS_CLA[*]}")"
# Output users who need CLA as comma-separated string, excluding
# non-mentionable placeholders such as "<unknown>"
NEEDS_CLA_MENTIONABLE=()
for user in "${NEEDS_CLA[@]}"; do
if [ "$user" != "<unknown>" ]; then
NEEDS_CLA_MENTIONABLE+=("$user")
fi
done
if [ ${#NEEDS_CLA_MENTIONABLE[@]} -eq 0 ]; then
NEEDS_CLA_CSV=""
else
NEEDS_CLA_CSV="$(IFS=','; echo "${NEEDS_CLA_MENTIONABLE[*]}")"

Copilot uses AI. Check for mistakes.
Comment on lines +319 to +323
- name: Post Multi-Author CLA Comment
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This step uses github.rest.issues.listComments / createComment / updateComment, which require the workflow token to have issues: read/write permission. The reusable workflow currently only declares pull-requests: write (no issues permission), so this step may fail with 403 when it tries to manage PR comments. Add issues: write to the workflow permissions: (or switch to an API that matches the granted permissions).

Copilot uses AI. Check for mistakes.
@bashandbone
Copy link
Copy Markdown
Contributor

@copilot apply changes based on the comments in this thread

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 7, 2026

@copilot apply changes based on the comments in this thread

Applied both fixes in 6f26b1e:

  • <unknown> filtering: needs_cla_csv now builds from a filtered NEEDS_CLA_MENTIONABLE array that excludes the "<unknown>" sentinel, preventing @<unknown> from appearing in comments or the CLA Assistant allowlist
  • issues: write permission: added to the workflow-level permissions block so the github-script step can create/update PR comments without a 403

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +372 to +376
'### Sign the CLA to get started 🖊️',
'',
'Each of you needs to agree to our Contributor License Agreement (CLA) before we can accept this contribution. If you already signed, you\'re all set — no further action needed.',
'',
'### To agree to the CLA, please comment:',
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This step builds the mention list from needs_cla_csv (non-exempt commit authors) rather than contributors who are actually missing a CLA signature. That means the comment can keep tagging users who already signed in a prior PR/run, which is noisy and can be misleading. Consider either (a) checking the signatures JSON to derive the truly unsigned set before mentioning, or (b) limiting this comment to pull_request_target opened/synchronize events (and only creating it when missing on issue_comment) so it doesn’t repeatedly ping people who are already compliant.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot apply changes based on this feedback

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied in 28581c1. The Post Multi-Author CLA Comment step now:

  • pull_request_target opened/synchronize: creates or updates the comment (skips update if body unchanged)
  • issue_comment on PRs: only creates the comment if it doesn't exist yet — never updates, so contributors who already signed won't get re-pinged when someone else comments to trigger a re-run
  • All other events / pull_request_target actions (e.g., labeled, closed): skipped entirely

Comment thread .github/workflows/cla-check.yml Outdated
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Adam Poulemanos <89049923+bashandbone@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/cla-check.yml Outdated
bashandbone and others added 2 commits April 7, 2026 17:09
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Adam Poulemanos <89049923+bashandbone@users.noreply.github.com>
Signed-off-by: Adam Poulemanos <89049923+bashandbone@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 304 to +309
needs: check-cla
# Make this condition MORE explicit and guard against non-PR issue_comment events
if: needs.check-cla.outputs.is_knitli_repo == 'true' && needs.check-cla.outputs.should_run_cla == 'true' && (github.event_name != 'issue_comment' || github.event.issue.pull_request != null)
runs-on: ubuntu-latest
permissions:
issues: write
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cla-assistant now sets job-level permissions to only issues: write, which overrides the workflow-level permissions and effectively drops statuses: write / pull-requests: write / contents: read for this job. The contributor-assistant/github-action flow typically needs statuses: write (and may rely on the other scopes) to set the "CLA Assistant" status/check and interact with PR metadata; with the current permissions it may fail or stop reporting status.

Consider either (a) adding issues: write at the workflow top-level permissions so existing scopes remain, or (b) expanding this job’s permissions to include the previously granted scopes (at least statuses: write, plus whatever else the action requires).

Copilot uses AI. Check for mistakes.
Signed-off-by: Adam Poulemanos <89049923+bashandbone@users.noreply.github.com>
@bashandbone bashandbone merged commit 4d30655 into main Apr 7, 2026
2 checks passed
@bashandbone bashandbone deleted the copilot/fix-cla-check-multi-author-issue branch April 7, 2026 21:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants