Org — Manage CLA Stubs (requires_cla) #44
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |