mirror of
https://github.com/pluja/awesome-privacy.git
synced 2026-07-21 10:55:39 +02:00
ci: run open-source verification on the repos a PR adds
This commit is contained in:
@@ -1,8 +1,10 @@
|
|||||||
name: PR Lint (links + format)
|
name: PR Lint (links + format)
|
||||||
|
|
||||||
# Runs on pull requests that touch the list. Two independent checks:
|
# Runs on pull requests that touch the list. Three independent checks:
|
||||||
# 1. link-check - lychee looks for dead links in README.md.
|
# 1. link-check - lychee looks for dead links in README.md.
|
||||||
# 2. format-lint - warns when a newly added entry has no description.
|
# 2. format-lint - warns when a newly added entry has no description.
|
||||||
|
# 3. openness-check - verifies the repos a PR ADDS: gone, archived, unlicensed,
|
||||||
|
# or no real source code. Warns, never blocks.
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
@@ -122,3 +124,20 @@ jobs:
|
|||||||
# Warn only. Format nits never block a PR.
|
# Warn only. Format nits never block a PR.
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
PY
|
PY
|
||||||
|
|
||||||
|
openness-check:
|
||||||
|
name: Check added repositories
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v5
|
||||||
|
with:
|
||||||
|
fetch-depth: 0 # need the base commit to diff against
|
||||||
|
|
||||||
|
- name: Verify open-source claims of added repos
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # full rate limit
|
||||||
|
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
||||||
|
# Checks only repos this PR adds. Posts warnings to the job summary and
|
||||||
|
# inline annotations; never fails the PR (the maintainer decides).
|
||||||
|
run: python3 scripts/health_report.py --diff-base "$BASE_SHA"
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import datetime as dt
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import urllib.error
|
import urllib.error
|
||||||
@@ -169,6 +170,53 @@ def scan_repos(repos, skull_set, now, token, limit=0):
|
|||||||
return findings, checked, rate_limited
|
return findings, checked, rate_limited
|
||||||
|
|
||||||
|
|
||||||
|
def added_readme_text(base):
|
||||||
|
"""The lines a PR adds to README.md, for scoping the check to new entries."""
|
||||||
|
try:
|
||||||
|
out = subprocess.run(
|
||||||
|
["git", "diff", "--unified=0", base, "HEAD", "--", "README.md"],
|
||||||
|
capture_output=True, text=True, check=False,
|
||||||
|
).stdout
|
||||||
|
except Exception as exc:
|
||||||
|
print(f"::warning::could not compute diff ({exc})", file=sys.stderr)
|
||||||
|
return ""
|
||||||
|
return "\n".join(
|
||||||
|
line[1:] for line in out.splitlines()
|
||||||
|
if line.startswith("+") and not line.startswith("+++")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def run_pr_check(base, now, token, limit):
|
||||||
|
"""Check only the repos a PR adds. Warns, never blocks. Returns exit code 0."""
|
||||||
|
added = added_readme_text(base)
|
||||||
|
repos = extract_repos(added)
|
||||||
|
findings, checked, rate_limited = scan_repos(
|
||||||
|
repos, extract_skull_repos(added), now, token, limit
|
||||||
|
)
|
||||||
|
new = [(s, w) for s, w, sk in findings if not sk]
|
||||||
|
for slug, why in new:
|
||||||
|
print(f"::warning::{slug} - {why}") # inline annotation on the PR
|
||||||
|
|
||||||
|
lines = ["## Open-source check of added repositories", "",
|
||||||
|
f"Checked {checked} newly added repo(s)."]
|
||||||
|
if new:
|
||||||
|
lines += ["", "Review these before merge (warnings, not blockers):"]
|
||||||
|
lines += [f"- {slug} - {why}" for slug, why in new]
|
||||||
|
else:
|
||||||
|
lines.append("No open-source concerns in the added repositories.")
|
||||||
|
if rate_limited:
|
||||||
|
lines += ["", "_GitHub rate limit hit; some repos were not checked._"]
|
||||||
|
summary = "\n".join(lines) + "\n"
|
||||||
|
|
||||||
|
step = os.environ.get("GITHUB_STEP_SUMMARY")
|
||||||
|
if step:
|
||||||
|
with open(step, "a", encoding="utf-8") as fh:
|
||||||
|
fh.write(summary)
|
||||||
|
else:
|
||||||
|
sys.stdout.write(summary)
|
||||||
|
return 0 # warn only; the maintainer decides
|
||||||
|
|
||||||
|
|
||||||
def parse_dead_links(path):
|
def parse_dead_links(path):
|
||||||
"""Return (dead_links, scan_ran). dead_links = [(url, reason), ...]."""
|
"""Return (dead_links, scan_ran). dead_links = [(url, reason), ...]."""
|
||||||
try:
|
try:
|
||||||
@@ -235,12 +283,17 @@ def main():
|
|||||||
ap.add_argument("--lychee", default="lychee/out.json")
|
ap.add_argument("--lychee", default="lychee/out.json")
|
||||||
ap.add_argument("--limit", type=int, default=0, help="cap repos checked (0 = all)")
|
ap.add_argument("--limit", type=int, default=0, help="cap repos checked (0 = all)")
|
||||||
ap.add_argument("--out", default=None)
|
ap.add_argument("--out", default=None)
|
||||||
|
ap.add_argument("--diff-base", default=None,
|
||||||
|
help="PR mode: check only repos added since this git ref (warns, never blocks)")
|
||||||
args = ap.parse_args()
|
args = ap.parse_args()
|
||||||
|
|
||||||
now = dt.datetime.now(dt.timezone.utc)
|
now = dt.datetime.now(dt.timezone.utc)
|
||||||
today = now.date().isoformat()
|
today = now.date().isoformat()
|
||||||
token = os.environ.get("GITHUB_TOKEN") or os.environ.get("GH_TOKEN")
|
token = os.environ.get("GITHUB_TOKEN") or os.environ.get("GH_TOKEN")
|
||||||
|
|
||||||
|
if args.diff_base:
|
||||||
|
sys.exit(run_pr_check(args.diff_base, now, token, args.limit))
|
||||||
|
|
||||||
with open(args.readme, encoding="utf-8") as fh:
|
with open(args.readme, encoding="utf-8") as fh:
|
||||||
readme = fh.read()
|
readme = fh.read()
|
||||||
repos = extract_repos(readme)
|
repos = extract_repos(readme)
|
||||||
|
|||||||
Reference in New Issue
Block a user