Skip to content

Org — Manage CLA Stubs (requires_cla) #51

Org — Manage CLA Stubs (requires_cla)

Org — Manage CLA Stubs (requires_cla) #51

name: Org — Manage CLA Stubs (requires_cla)
on:
workflow_dispatch:
inputs:
org:
description: Organization login (defaults to caller's org)
required: false
reusable_ref:
description: Ref for reusable CLA workflow (e.g., main)
required: false
default: main
allowlist_branch:
description: Branch in .github with allowlist
required: false
default: cla-config
allowlist_path:
description: Path to YAML allowlist in .github
required: false
default: cla/allowlist.yml
sign_phrase:
description: Exact phrase for signing via comment
required: false
default: I have read the CLA Document and I hereby sign the CLA
secret_name:
description: Secret forwarded to reusable workflow
required: false
default: CLA_ASSISTANT_PAT
include_repos:
description: Comma-separated glob(s) to include (optional)
required: false
default: ""
exclude_repos:
description: Comma-separated glob(s) to exclude (optional)
required: false
default: ""
permissions:
contents: read
actions: read
concurrency:
group: ${{ github.workflow }}-${{ github.run_id }}
cancel-in-progress: false
jobs:
manage:
name: Discover & reconcile stubs via cla_manager.py
runs-on: ubuntu-latest
timeout-minutes: 30
env:
ORG: ${{ inputs.org || github.repository_owner }}
REUSABLE_REF: ${{ inputs.reusable_ref }}
ALLOWLIST_BRANCH: ${{ inputs.allowlist_branch }}
ALLOWLIST_PATH: ${{ inputs.allowlist_path }}
SIGN_PHRASE: ${{ inputs.sign_phrase }}
SECRET_NAME: ${{ inputs.secret_name }}
INCLUDE_REPOS: ${{ inputs.include_repos }}
EXCLUDE_REPOS: ${{ inputs.exclude_repos }}
steps:
- name: Check out current repo (for scripts)
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install deps (optional)
run: |
python -m pip install --upgrade pip
if [ -f scripts/requirements.txt ]; then
echo "Installing from ./scripts/requirements.txt"
python -m pip install -r scripts/requirements.txt
fi
# if [ -f scripts/requirements.txt ]; then pip install -r scripts/requirements.txt; fi
- name: Mask secrets
run: |
# Mask these tokens so if they get echoed, they are redacted in logs
if [ -n "${{ secrets.ORG_PAT }}" ]; then
echo "::add-mask::${{ secrets.ORG_PAT }}"
fi
if [ -n "${{ secrets.CLA_ASSISTANT_PAT }}" ]; then
echo "::add-mask::${{ secrets.CLA_ASSISTANT_PAT }}"
fi
- name: Run CLA manager (opens/updates PRs everywhere)
env:
ORG_PAT: ${{ secrets.ORG_PAT }} # FG-PAT with Contents:RW + Pull Requests:RW (Issues:RW if you want PR comments)
run: |
set -euo pipefail
python scripts/cla_manager.py \
--org "${ORG}" \
--reusable-ref "${REUSABLE_REF}" \
--allowlist-branch "${ALLOWLIST_BRANCH}" \
--allowlist-path "${ALLOWLIST_PATH}" \
--sign-phrase "${SIGN_PHRASE}" \
--secret-name "${SECRET_NAME}" \
--include-repos "${INCLUDE_REPOS}" \
--exclude-repos "${EXCLUDE_REPOS}" \
2>&1 | tee manager-results.log
- name: Summarize reconciliation
run: |
python - <<'PY'
import os, re
from collections import Counter
rows=[]
with open('manager-results.log','r',encoding='utf-8',errors='ignore') as f:
for line in f:
m=re.search(r'REPO=([^ ]+)\s+STATUS=([^ ]+)\s+DECISION=([^ ]+)\s+MSG=(.*)', line.strip())
if m: rows.append(m.groups())
counts=Counter(r[1] for r in rows)
with open(os.environ['GITHUB_STEP_SUMMARY'],'a',encoding='utf-8') as out:
out.write("## CLA Stub Reconciliation — Summary (PR-everywhere)\n\n")
if counts:
out.write("**Counts by status:** " + ", ".join(f"`{k}`={v}" for k,v in counts.items()) + "\n\n")
else:
out.write("_No reconciliation rows parsed; check raw log below._\n\n")
out.write("| Repo | Status | RequiresCLA | Message |\n|---|---|---|---|\n")
for repo,status,decision,msg in rows:
out.write(f"| `{repo}` | `{status}` | `{decision}` | {msg} |\n")
PY
- name: Upload raw log
uses: actions/upload-artifact@v4
with:
name: manager-results
path: manager-results.log
if-no-files-found: warn