From 629341c18f3482d891b665a844975096b47b4779 Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Tue, 24 Mar 2026 03:27:14 +0100 Subject: [PATCH] Added openclaw labeler --- .github/workflows/openclaw-gate.yml | 108 ++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 .github/workflows/openclaw-gate.yml diff --git a/.github/workflows/openclaw-gate.yml b/.github/workflows/openclaw-gate.yml new file mode 100644 index 00000000..4eff559d --- /dev/null +++ b/.github/workflows/openclaw-gate.yml @@ -0,0 +1,108 @@ +name: OpenClaw Gate + +on: + issues: + types: [opened] + pull_request_target: + types: [opened] + +jobs: + check-contributor: + runs-on: ubuntu-latest + permissions: + contents: read + issues: write + pull-requests: write + steps: + - name: Check contributor + uses: actions/github-script@v7 + with: + script: | + const isPR = !!context.payload.pull_request; + const author = isPR + ? context.payload.pull_request.user.login + : context.payload.issue.user.login; + const number = isPR + ? context.payload.pull_request.number + : context.payload.issue.number; + const defaultBranch = context.payload.repository.default_branch; + + if (author.endsWith('[bot]') || author === 'dependabot[bot]') { + console.log(`Skipping bot: ${author}`); + return; + } + + // --- Check APPROVED_CONTRIBUTORS --- + async function getTextFile(path) { + const { data } = await github.rest.repos.getContent({ + owner: context.repo.owner, + repo: context.repo.repo, + path, + ref: defaultBranch, + }); + if (!('content' in data) || typeof data.content !== 'string') { + throw new Error(`Expected file content for ${path}`); + } + return Buffer.from(data.content, 'base64').toString('utf8'); + } + + try { + const content = await getTextFile('.github/APPROVED_CONTRIBUTORS'); + const approved = content + .split('\n') + .map(l => l.trim().toLowerCase()) + .filter(l => l && !l.startsWith('#')); + if (approved.includes(author.toLowerCase())) { + console.log(`${author} is in APPROVED_CONTRIBUTORS, passing`); + return; + } + } catch (err) { + console.log(`Could not read APPROVED_CONTRIBUTORS: ${err.message}`); + } + + // --- Also pass collaborators with write+ access --- + try { + const { data: perm } = await github.rest.repos.getCollaboratorPermissionLevel({ + owner: context.repo.owner, + repo: context.repo.repo, + username: author, + }); + if (['admin', 'maintain', 'write'].includes(perm.permission)) { + console.log(`${author} is a collaborator (${perm.permission}), passing`); + return; + } + } catch { + // not a collaborator + } + + // --- Check if user opened issues/PRs on openclaw/openclaw --- + async function hasOpenClawActivity(username) { + try { + const { data } = await github.rest.search.issuesAndPullRequests({ + q: `repo:openclaw/openclaw author:${username}`, + per_page: 1, + }); + if (data.total_count > 0) { + console.log(`${username} has opened ${data.total_count} issues/PRs on openclaw/openclaw`); + return true; + } + } catch (err) { + console.log(`Search failed: ${err.message}`); + } + return false; + } + + const hasActivity = await hasOpenClawActivity(author); + if (!hasActivity) { + console.log(`${author} has no openclaw/openclaw activity, passing`); + return; + } + + // --- Add openclaw label --- + console.log(`${author} has openclaw/openclaw activity, adding label`); + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: number, + labels: ['possibly-openclaw-clanker'], + });