mirror of
https://github.com/n8n-io/n8n.git
synced 2026-05-12 16:10:30 +02:00
ci: Add in-house CLA check workflow (#30209)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
75646c4527
commit
410b75c3d0
114
.github/scripts/cla/check-signatures.mjs
vendored
Normal file
114
.github/scripts/cla/check-signatures.mjs
vendored
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
// Invoked from .github/workflows/ci-cla-check.yml via actions/github-script.
|
||||
//
|
||||
// Collects unique commit authors for the PR (or for the commits a merge
|
||||
// queue is about to land) and asks the n8n CLA service whether each one
|
||||
// has signed. Surfaces three buckets to subsequent steps:
|
||||
// - signed : verified contributors
|
||||
// - unsigned : verified non-contributors (block the merge)
|
||||
// - errored : CLA lookup failed (block the merge — fail-closed so we
|
||||
// never green-light an unverified contribution)
|
||||
//
|
||||
// Commits whose author email is not linked to a GitHub account can't be
|
||||
// looked up by login; they're surfaced separately as `unlinked`.
|
||||
|
||||
/**
|
||||
* @typedef { InstanceType<typeof import("@actions/github/lib/utils").GitHub> } GitHubInstance
|
||||
* @typedef { import("@actions/github/lib/context").Context } Context
|
||||
* @typedef { typeof import("@actions/core") } Core
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {{ github: GitHubInstance, context: Context, core: Core }} params
|
||||
*/
|
||||
export default async function checkSignatures ({ github, context, core }) {
|
||||
const { owner, repo } = context.repo;
|
||||
const prNumber = process.env.PR_NUMBER;
|
||||
const headSha = process.env.HEAD_SHA;
|
||||
const baseSha = process.env.BASE_SHA;
|
||||
const isMergeGroup = process.env.IS_MERGE_GROUP === 'true';
|
||||
|
||||
/** @type {Set<string>} */
|
||||
const authors = new Set();
|
||||
/** @type {Array<{sha: string, name: string, email: string}>} */
|
||||
const unlinkedCommits = [];
|
||||
|
||||
/**
|
||||
* @param {Array<any>} commits
|
||||
*/
|
||||
const collect = (commits) => {
|
||||
for (const c of commits) {
|
||||
// Bot-authored commits don't need a CLA; skip before the linked/unlinked split
|
||||
// so they don't fall through to `unlinkedCommits` and fail `all_signed`.
|
||||
if (c.author && c.author.type === 'Bot') continue;
|
||||
|
||||
if (c.author && c.author.login) {
|
||||
authors.add(c.author.login);
|
||||
} else if (c.commit && c.commit.author) {
|
||||
unlinkedCommits.push({
|
||||
sha: c.sha,
|
||||
name: c.commit.author.name,
|
||||
email: c.commit.author.email,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (isMergeGroup) {
|
||||
const { data: comparison } = await github.rest.repos.compareCommitsWithBasehead({
|
||||
owner,
|
||||
repo,
|
||||
basehead: `${baseSha}...${headSha}`,
|
||||
});
|
||||
collect(comparison.commits || []);
|
||||
} else if (prNumber) {
|
||||
const commits = await github.paginate(github.rest.pulls.listCommits, {
|
||||
owner,
|
||||
repo,
|
||||
pull_number: Number(prNumber),
|
||||
per_page: 100,
|
||||
});
|
||||
collect(commits);
|
||||
}
|
||||
|
||||
const loginList = [...authors];
|
||||
core.info(`Contributors to check: ${loginList.join(', ') || '(none)'}`);
|
||||
if (unlinkedCommits.length > 0) {
|
||||
core.warning(
|
||||
`${unlinkedCommits.length} commit(s) have an author email not linked to a GitHub account ` +
|
||||
'and cannot be verified against the CLA service.',
|
||||
);
|
||||
}
|
||||
|
||||
/** @type {string[]} */
|
||||
const signed = [];
|
||||
/** @type {string[]} */
|
||||
const unsigned = [];
|
||||
/** @type {string[]} */
|
||||
const errored = [];
|
||||
|
||||
for (const login of loginList) {
|
||||
const url = `${process.env.CLA_API}?checkContributor=${encodeURIComponent(login)}`;
|
||||
try {
|
||||
const res = await fetch(url);
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
const data = await res.json();
|
||||
if (data && data.isContributor === true) {
|
||||
signed.push(login);
|
||||
} else {
|
||||
unsigned.push(login);
|
||||
}
|
||||
} catch (e) {
|
||||
core.warning(`CLA lookup failed for @${login}: ${e instanceof Error ? e.message : String(e)}`);
|
||||
errored.push(login);
|
||||
}
|
||||
}
|
||||
|
||||
const blocking = [...unsigned, ...errored];
|
||||
const allSigned = blocking.length === 0 && unlinkedCommits.length === 0;
|
||||
|
||||
core.setOutput('signed', signed.join(','));
|
||||
core.setOutput('unsigned', unsigned.join(','));
|
||||
core.setOutput('errored', errored.join(','));
|
||||
core.setOutput('unlinked', JSON.stringify(unlinkedCommits));
|
||||
core.setOutput('all_signed', String(allSigned));
|
||||
}
|
||||
66
.github/scripts/cla/post-final-status.mjs
vendored
Normal file
66
.github/scripts/cla/post-final-status.mjs
vendored
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
// Invoked from .github/workflows/ci-cla-check.yml via actions/github-script.
|
||||
//
|
||||
// Translates the buckets emitted by check-signatures.mjs into a single
|
||||
// commit status on the head SHA. The status `context` name is what a
|
||||
// repository ruleset gates on; description and target_url are best-effort
|
||||
// human signals.
|
||||
//
|
||||
// State mapping:
|
||||
// - success: every contributor is signed and every commit author is linked
|
||||
// - error : only failures were API lookup errors (transient)
|
||||
// - failure: at least one contributor is verified unsigned, or commits
|
||||
// have author emails not linked to a GitHub account
|
||||
|
||||
/**
|
||||
* @typedef { InstanceType<typeof import("@actions/github/lib/utils").GitHub> } GitHubInstance
|
||||
* @typedef { import("@actions/github/lib/context").Context } Context
|
||||
* @typedef { typeof import("@actions/core") } Core
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {{ github: GitHubInstance, context: Context, core: Core }} params
|
||||
*/
|
||||
export default async function postFinalClaStatus({ github, context }) {
|
||||
const allSigned = process.env.ALL_SIGNED === 'true';
|
||||
const unsigned = (process.env.UNSIGNED ?? '').split(',').filter(Boolean);
|
||||
const errored = (process.env.ERRORED ?? '').split(',').filter(Boolean);
|
||||
const unlinked = JSON.parse(process.env.UNLINKED || '[]');
|
||||
|
||||
/** @type {'success' | 'failure' | 'error' | 'pending'} */
|
||||
let state;
|
||||
let description;
|
||||
if (allSigned) {
|
||||
state = 'success';
|
||||
description = 'All contributors have signed the CLA';
|
||||
} else if (errored.length > 0 && unsigned.length === 0 && unlinked.length === 0) {
|
||||
state = 'error';
|
||||
description = `Could not verify: ${errored.join(', ')}`;
|
||||
} else {
|
||||
state = 'failure';
|
||||
const parts = [];
|
||||
if (unsigned.length > 0) parts.push(`unsigned: ${unsigned.join(', ')}`);
|
||||
if (errored.length > 0) parts.push(`errored: ${errored.join(', ')}`);
|
||||
if (unlinked.length > 0) parts.push(`${unlinked.length} unlinked commit(s)`);
|
||||
description = parts.join(' | ');
|
||||
}
|
||||
|
||||
// GitHub commit status description is capped at 140 chars.
|
||||
if (description.length > 140) {
|
||||
description = description.slice(0, 137) + '…';
|
||||
}
|
||||
|
||||
const prNumber = process.env.PR_NUMBER;
|
||||
const target_url = prNumber
|
||||
? `${context.payload.repository?.html_url}/pull/${prNumber}`
|
||||
: process.env.CLA_SIGN_URL;
|
||||
|
||||
await github.rest.repos.createCommitStatus({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
sha: /** @type {string} */ (process.env.HEAD_SHA),
|
||||
state,
|
||||
context: /** @type {string} */ (process.env.STATUS_CONTEXT),
|
||||
description,
|
||||
target_url,
|
||||
});
|
||||
}
|
||||
76
.github/scripts/cla/resolve-context.mjs
vendored
Normal file
76
.github/scripts/cla/resolve-context.mjs
vendored
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
// Invoked from .github/workflows/ci-cla-check.yml via actions/github-script.
|
||||
//
|
||||
// Reads the triggering event (pull_request_target, issue_comment, or
|
||||
// merge_group) and emits the head/base SHA and PR number that the rest of
|
||||
// the workflow needs. For /cla-check comments, also leaves an "eyes"
|
||||
// reaction so the commenter sees we picked it up.
|
||||
|
||||
/**
|
||||
* @typedef { InstanceType<typeof import("@actions/github/lib/utils").GitHub> } GitHubInstance
|
||||
* @typedef { import("@actions/github/lib/context").Context } Context
|
||||
* @typedef { typeof import("@actions/core") } Core
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {{ github: GitHubInstance, context: Context, core: Core }} params
|
||||
*/
|
||||
export default async function resolveClaContext({ github, context, core }) {
|
||||
const { owner, repo } = context.repo;
|
||||
const event = context.eventName;
|
||||
|
||||
let prNumber = '';
|
||||
let headSha = '';
|
||||
let baseSha = '';
|
||||
let isMergeGroup = false;
|
||||
|
||||
if (event === 'pull_request_target' && context.payload.pull_request) {
|
||||
const pr = context.payload.pull_request;
|
||||
prNumber = String(pr.number);
|
||||
headSha = pr.head.sha;
|
||||
baseSha = pr.base.sha;
|
||||
} else if (event === 'issue_comment' && context.payload.issue) {
|
||||
prNumber = String(context.payload.issue.number);
|
||||
const { data: pr } = await github.rest.pulls.get({
|
||||
owner,
|
||||
repo,
|
||||
pull_number: Number(prNumber),
|
||||
});
|
||||
headSha = pr.head.sha;
|
||||
baseSha = pr.base.sha;
|
||||
|
||||
// Acknowledge the command so the commenter sees we received it.
|
||||
try {
|
||||
await github.rest.reactions.createForIssueComment({
|
||||
owner,
|
||||
repo,
|
||||
comment_id: context.payload.comment?.id || -1,
|
||||
content: 'eyes',
|
||||
});
|
||||
} catch (e) {
|
||||
core.info(`Could not react to comment: ${e instanceof Error ? e.message : String(e)}`);
|
||||
}
|
||||
} else if (event === 'merge_group') {
|
||||
isMergeGroup = true;
|
||||
headSha = context.payload.merge_group.head_sha;
|
||||
baseSha = context.payload.merge_group.base_sha;
|
||||
} else if (event === 'workflow_dispatch') {
|
||||
const input = context.payload.inputs?.pr_number;
|
||||
if (!input) {
|
||||
core.setFailed('workflow_dispatch requires the pr_number input');
|
||||
return;
|
||||
}
|
||||
prNumber = String(input);
|
||||
const { data: pr } = await github.rest.pulls.get({
|
||||
owner,
|
||||
repo,
|
||||
pull_number: Number(prNumber),
|
||||
});
|
||||
headSha = pr.head.sha;
|
||||
baseSha = pr.base.sha;
|
||||
}
|
||||
|
||||
core.setOutput('pr_number', prNumber);
|
||||
core.setOutput('head_sha', headSha);
|
||||
core.setOutput('base_sha', baseSha);
|
||||
core.setOutput('is_merge_group', String(isMergeGroup));
|
||||
}
|
||||
106
.github/scripts/cla/update-pr-comment.mjs
vendored
Normal file
106
.github/scripts/cla/update-pr-comment.mjs
vendored
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
// Invoked from .github/workflows/ci-cla-check.yml via actions/github-script.
|
||||
//
|
||||
// Maintains a single CLA comment per PR, keyed by an HTML marker so the
|
||||
// same comment is edited in place across re-runs instead of spammed.
|
||||
// A clean PR that has never been flagged gets no comment at all — only
|
||||
// PRs that needed a nudge get the eventual "thanks" follow-up.
|
||||
|
||||
/**
|
||||
* @typedef { InstanceType<typeof import("@actions/github/lib/utils").GitHub> } GitHubInstance
|
||||
* @typedef { import("@actions/github/lib/context").Context } Context
|
||||
* @typedef { typeof import("@actions/core") } Core
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {{ github: GitHubInstance, context: Context, core: Core }} params
|
||||
*/
|
||||
export default async function updatePRComment({ github, context }) {
|
||||
const { owner, repo } = context.repo;
|
||||
const issue_number = Number(process.env.PR_NUMBER);
|
||||
const allSigned = process.env.ALL_SIGNED === 'true';
|
||||
const unsigned = (process.env.UNSIGNED ?? '').split(',').filter(Boolean);
|
||||
const errored = (process.env.ERRORED ?? '').split(',').filter(Boolean);
|
||||
const unlinked = JSON.parse(process.env.UNLINKED || '[]');
|
||||
const MARKER = /** @type {string} */ (process.env.COMMENT_MARKER);
|
||||
|
||||
const comments = await github.paginate(github.rest.issues.listComments, {
|
||||
owner,
|
||||
repo,
|
||||
issue_number,
|
||||
per_page: 100,
|
||||
});
|
||||
// Only adopt the comment as ours if it's bot-authored — otherwise a user
|
||||
// who copies our marker into their own comment would either hijack the
|
||||
// thread or make updateComment 403 with insufficient permissions.
|
||||
const existing = comments.find(
|
||||
(c) => c.body && c.body.includes(MARKER) && c.user && c.user.type === 'Bot',
|
||||
);
|
||||
|
||||
let body;
|
||||
if (allSigned) {
|
||||
// Only leave a "thanks" trail if we already nudged once. Avoids
|
||||
// pinging every clean PR with a CLA comment.
|
||||
if (!existing) {
|
||||
return;
|
||||
}
|
||||
|
||||
body = [
|
||||
MARKER,
|
||||
'✅ **CLA Check passed.** All contributors on this PR have signed the n8n CLA — thank you!',
|
||||
].join('\n');
|
||||
} else {
|
||||
const lines = [MARKER, '## CLA signatures required', ''];
|
||||
lines.push(`Thank you for your submission! We really appreciate it.
|
||||
Like many open source projects, we ask that you sign our [Contributor License Agreement](${process.env.CLA_SIGN_URL}) before we can accept your contribution.
|
||||
|
||||
After signing, please comment \`\`\`/cla-check\`\`\` to re-check signature status.`);
|
||||
lines.push('');
|
||||
|
||||
if (unsigned.length > 0) {
|
||||
lines.push('**Contributors who still need to sign:**');
|
||||
for (const u of unsigned) {
|
||||
lines.push(`- @${u}`);
|
||||
}
|
||||
lines.push('');
|
||||
}
|
||||
if (errored.length > 0) {
|
||||
lines.push('**Could not verify (will retry on next push):**');
|
||||
for (const u of errored) {
|
||||
lines.push(`- @${u}`);
|
||||
}
|
||||
lines.push('');
|
||||
}
|
||||
if (unlinked.length > 0) {
|
||||
lines.push('**Commits authored by an email not linked to a GitHub account:**');
|
||||
for (const c of unlinked) {
|
||||
lines.push(`- \`${c.sha.slice(0, 7)}\` — ${c.name} <${c.email}>`);
|
||||
}
|
||||
lines.push('');
|
||||
lines.push(
|
||||
'Add the email to your GitHub account ' +
|
||||
'([instructions](https://docs.github.com/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-email-preferences/adding-an-email-address-to-your-github-account)) ' +
|
||||
'or amend the commits to use a linked email, then push again.',
|
||||
);
|
||||
lines.push('');
|
||||
}
|
||||
|
||||
lines.push('Once signed, comment `/cla-check` on this PR to re-run verification.');
|
||||
body = lines.join('\n');
|
||||
}
|
||||
|
||||
if (existing) {
|
||||
await github.rest.issues.updateComment({
|
||||
owner,
|
||||
repo,
|
||||
comment_id: existing.id,
|
||||
body,
|
||||
});
|
||||
} else {
|
||||
await github.rest.issues.createComment({
|
||||
owner,
|
||||
repo,
|
||||
issue_number,
|
||||
body,
|
||||
});
|
||||
}
|
||||
}
|
||||
168
.github/workflows/ci-cla-check.yml
vendored
Normal file
168
.github/workflows/ci-cla-check.yml
vendored
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
name: 'CI: CLA Check'
|
||||
|
||||
# In-house replacement for the GitHub App "CLA Bot".
|
||||
#
|
||||
# Triggers
|
||||
# - pull_request_target (opened/synchronize/reopened): re-checks signatures
|
||||
# whenever a PR is opened or new commits are pushed.
|
||||
# - issue_comment (`/cla-check` on a PR): manual re-check after a contributor
|
||||
# signs the CLA, without needing a push.
|
||||
# - merge_group: re-checks at merge-queue time so a ruleset can hard-block
|
||||
# unsigned merges even if the PR check went stale.
|
||||
#
|
||||
# Output
|
||||
# - A commit status named "CLA Check" on the head SHA. Add this name to a
|
||||
# ruleset's required-checks list to gate merges on it.
|
||||
# - A single, edited-in-place PR comment listing unsigned contributors.
|
||||
#
|
||||
# Implementation
|
||||
# The heavy lifting lives in .github/scripts/cla/*.mjs. Each step below
|
||||
# loads its corresponding module and invokes its default export.
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, synchronize, reopened]
|
||||
issue_comment:
|
||||
types: [created]
|
||||
merge_group:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
pr_number:
|
||||
description: 'Pull request number to re-verify'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
issues: write
|
||||
statuses: write
|
||||
|
||||
concurrency:
|
||||
group: cla-check-${{ github.event.pull_request.number || github.event.issue.number || github.event.merge_group.head_sha || github.event.inputs.pr_number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
STATUS_CONTEXT: 'CLA Check'
|
||||
CLA_API: 'https://cla-bot-prod.users.n8n.cloud/webhook/cla/check'
|
||||
CLA_SIGN_URL: 'https://cla-bot-prod.users.n8n.cloud/webhook/cla'
|
||||
COMMENT_MARKER: '<!-- n8n-cla-check -->'
|
||||
|
||||
jobs:
|
||||
cla-check:
|
||||
name: Verify CLA signatures
|
||||
# Skip issue_comment unless it's on a PR and the body starts with /cla-check.
|
||||
if: >-
|
||||
github.event_name != 'issue_comment' ||
|
||||
(github.event.issue.pull_request != null &&
|
||||
startsWith(github.event.comment.body, '/cla-check'))
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- name: Generate GitHub App Token
|
||||
id: generate-token
|
||||
uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
|
||||
with:
|
||||
app-id: ${{ secrets.N8N_ASSISTANT_APP_ID }}
|
||||
private-key: ${{ secrets.N8N_ASSISTANT_PRIVATE_KEY }}
|
||||
|
||||
- name: Checkout CLA scripts
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
sparse-checkout: .github/scripts/cla
|
||||
sparse-checkout-cone-mode: false
|
||||
|
||||
- name: Resolve PR context
|
||||
id: context
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
|
||||
with:
|
||||
github-token: ${{ steps.generate-token.outputs.token }}
|
||||
script: |
|
||||
const mod = await import('${{ github.workspace }}/.github/scripts/cla/resolve-context.mjs');
|
||||
await mod.default({ github, context, core });
|
||||
|
||||
- name: Post pending commit status
|
||||
if: steps.context.outputs.head_sha != ''
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
|
||||
env:
|
||||
HEAD_SHA: ${{ steps.context.outputs.head_sha }}
|
||||
with:
|
||||
github-token: ${{ steps.generate-token.outputs.token }}
|
||||
script: |
|
||||
await github.rest.repos.createCommitStatus({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
sha: process.env.HEAD_SHA,
|
||||
state: 'pending',
|
||||
context: process.env.STATUS_CONTEXT,
|
||||
description: 'Verifying CLA signatures…',
|
||||
});
|
||||
|
||||
- name: Check CLA signatures
|
||||
id: check
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
|
||||
env:
|
||||
PR_NUMBER: ${{ steps.context.outputs.pr_number }}
|
||||
HEAD_SHA: ${{ steps.context.outputs.head_sha }}
|
||||
BASE_SHA: ${{ steps.context.outputs.base_sha }}
|
||||
IS_MERGE_GROUP: ${{ steps.context.outputs.is_merge_group }}
|
||||
with:
|
||||
github-token: ${{ steps.generate-token.outputs.token }}
|
||||
script: |
|
||||
const mod = await import('${{ github.workspace }}/.github/scripts/cla/check-signatures.mjs');
|
||||
await mod.default({ github, context, core });
|
||||
|
||||
- name: Post final commit status
|
||||
if: always() && steps.context.outputs.head_sha != ''
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
|
||||
env:
|
||||
HEAD_SHA: ${{ steps.context.outputs.head_sha }}
|
||||
PR_NUMBER: ${{ steps.context.outputs.pr_number }}
|
||||
ALL_SIGNED: ${{ steps.check.outputs.all_signed }}
|
||||
UNSIGNED: ${{ steps.check.outputs.unsigned }}
|
||||
ERRORED: ${{ steps.check.outputs.errored }}
|
||||
UNLINKED: ${{ steps.check.outputs.unlinked }}
|
||||
with:
|
||||
github-token: ${{ steps.generate-token.outputs.token }}
|
||||
script: |
|
||||
const mod = await import('${{ github.workspace }}/.github/scripts/cla/post-final-status.mjs');
|
||||
await mod.default({ github, context, core });
|
||||
|
||||
- name: Update PR comment
|
||||
# Don't comment from merge_group (no PR context) or when the check
|
||||
# failed to produce a result.
|
||||
if: >-
|
||||
always() &&
|
||||
steps.context.outputs.pr_number != '' &&
|
||||
steps.check.outputs.all_signed != ''
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
|
||||
env:
|
||||
PR_NUMBER: ${{ steps.context.outputs.pr_number }}
|
||||
ALL_SIGNED: ${{ steps.check.outputs.all_signed }}
|
||||
UNSIGNED: ${{ steps.check.outputs.unsigned }}
|
||||
ERRORED: ${{ steps.check.outputs.errored }}
|
||||
UNLINKED: ${{ steps.check.outputs.unlinked }}
|
||||
with:
|
||||
github-token: ${{ steps.generate-token.outputs.token }}
|
||||
script: |
|
||||
const mod = await import('${{ github.workspace }}/.github/scripts/cla/update-pr-comment.mjs');
|
||||
await mod.default({ github, context, core });
|
||||
|
||||
- name: React to /cla-check comment
|
||||
if: always() && github.event_name == 'issue_comment' && steps.check.outputs.all_signed != ''
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
|
||||
env:
|
||||
ALL_SIGNED: ${{ steps.check.outputs.all_signed }}
|
||||
with:
|
||||
github-token: ${{ steps.generate-token.outputs.token }}
|
||||
script: |
|
||||
try {
|
||||
await github.rest.reactions.createForIssueComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
comment_id: context.payload.comment.id,
|
||||
content: process.env.ALL_SIGNED === 'true' ? '+1' : '-1',
|
||||
});
|
||||
} catch (e) {
|
||||
core.info(`Could not react to comment: ${e.message}`);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user