[CI] update pr-gate to be compatible with new slash triggering mananer. (#13522)

This commit is contained in:
Liangsheng Yin
2025-11-19 00:49:13 +08:00
committed by GitHub
parent c1a30aa765
commit 109f27ba3a
3 changed files with 87 additions and 10 deletions
+70 -10
View File
@@ -14,9 +14,15 @@ jobs:
pr-gate:
runs-on: ubuntu-latest
steps:
# 1. for commits on main: no gating needed
# 2. for workflow_dispatch: this can only be triggered by users with write access
- name: Skip PR-Gate for non-PR events
if: github.event_name != 'pull_request'
run: |
echo "Not a pull_request event; skipping PR-Gate checks."
exit 0
- name: Fetch latest PR info
id: pr
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
@@ -42,13 +48,13 @@ jobs:
echo "==================="
- name: Block draft PR
if: github.event_name == 'pull_request' && fromJson(steps.pr.outputs.draft)
if: fromJson(steps.pr.outputs.draft)
run: |
echo "PR is draft. Blocking CI."
exit 1
- name: Require run-ci label (optional)
if: github.event_name == 'pull_request' && inputs.require-run-ci == true
if: inputs.require-run-ci == true
run: |
labels='${{ steps.pr.outputs.labels }}'
if [[ "${{ contains(fromJson(steps.pr.outputs.labels), 'run-ci') }}" == "false" ]]; then
@@ -57,19 +63,24 @@ jobs:
fi
- name: Enforce rate limit for low-permission actors (optional)
if: (github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch') && inputs.rate-limit-hours != 0
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const HOURS = Number("${{ inputs.rate-limit-hours }}");
const DEFAULT_HOURS = Number("${{ inputs.rate-limit-hours }}");
const owner = context.repo.owner;
const repo = context.repo.repo;
const eventName = context.eventName;
const curRun = await github.rest.actions.getWorkflowRun({
owner, repo, run_id: context.runId
});
const triggeringActor = curRun.data.triggering_actor?.login || context.actor;
let triggeringActor = curRun.data.triggering_actor?.login || context.actor;
if (triggeringActor === "github-actions[bot]") {
triggeringActor = `${{ steps.pr.outputs.user }}`;
core.info(
`triggering_actor is github-actions[bot]; substituting PR author '${triggeringActor}'.`
);
}
async function hasHighPermission(username) {
try {
@@ -87,8 +98,55 @@ jobs:
return;
}
const cutoff = new Date(Date.now() - HOURS * 60 * 60 * 1000);
core.info(`Checking for workflow runs since ${cutoff.toISOString()} (last ${HOURS} hours) for event '${eventName}'.`);
let effectiveCooldownMinutes = DEFAULT_HOURS * 60;
let perUserCooldownMinutes = null;
try {
const contentResp = await github.rest.repos.getContent({
owner,
repo,
path: ".github/CI_PERMISSIONS.json",
ref: "main",
});
if (!Array.isArray(contentResp.data) && contentResp.data && "content" in contentResp.data) {
const raw = Buffer.from(
contentResp.data.content,
contentResp.data.encoding || "base64"
).toString();
const ciPermissions = JSON.parse(raw);
const userPerm = ciPermissions[triggeringActor];
if (userPerm && typeof userPerm.cooldown_interval_minutes === "number") {
perUserCooldownMinutes = userPerm.cooldown_interval_minutes;
core.info(
`Per-user cooldown for '${triggeringActor}' from CI_PERMISSIONS.json: ${perUserCooldownMinutes} minutes.`
);
} else {
core.info(`No per-user cooldown found for '${triggeringActor}' in CI_PERMISSIONS.json.`);
}
} else {
core.info("CI_PERMISSIONS.json content response is not a file; skipping per-user cooldown.");
}
} catch (e) {
core.info(`CI_PERMISSIONS.json not found or unreadable: ${e.message}. Using default rate limit only.`);
}
if (perUserCooldownMinutes !== null) {
effectiveCooldownMinutes = Math.min(effectiveCooldownMinutes, perUserCooldownMinutes);
}
if (effectiveCooldownMinutes <= 0) {
core.info(
`Effective cooldown for '${triggeringActor}' is 0 minutes; no rate limit enforced for this user.`
);
return;
}
const cutoff = new Date(Date.now() - effectiveCooldownMinutes * 60 * 1000);
core.info(
`Checking for workflow runs since ${cutoff.toISOString()} (last ${effectiveCooldownMinutes} minutes) for event '${eventName}'.`
);
const { data } = await github.rest.actions.listWorkflowRuns({
owner,
@@ -108,8 +166,10 @@ jobs:
if (recentFound) {
core.setFailed(
`User '${triggeringActor}' already triggered '${context.workflow}' via '${eventName}' at ${recentFound.created_at}. ` +
`Please wait ${HOURS} hours before triggering again.`
`Please wait ${effectiveCooldownMinutes} minutes before triggering again.`
);
} else {
core.info(`No recent runs detected within the last ${HOURS} hours; proceeding.`);
core.info(
`No recent runs detected for '${triggeringActor}' within the last ${effectiveCooldownMinutes} minutes; proceeding.`
);
}