Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ On Windows with an NVIDIA GPU some tests are skipped by design (VideoOut tests w
### Review and checks

- `main` only changes through pull requests. Force pushes and deletion of `main` are blocked for everyone.
- Every pull request needs an approving review from the code owner ([.github/CODEOWNERS](.github/CODEOWNERS)) and these checks to pass: **Conventions** (`tools/check_conventions.py`, run from the base branch without executing your code), **Relinker on Linux** and **Windows build and tests**. A pull request that only changes documentation skips the two builds.
- Every pull request needs an approving review from the code owner ([.github/CODEOWNERS](.github/CODEOWNERS)) and these checks to pass: **Conventions** (`tools/check_conventions.py`, run from the base branch without executing your code), **Relinker on Linux** and **Windows build and tests**. A pull request that only changes documentation skips the two builds. Dependabot's pull requests skip the description template, but their title is still checked.
- Workflows of a pull request from a fork run only after the maintainer has read the changes and approved the run. Changes to `.github/workflows/` get extra scrutiny.
- All review conversations must be resolved before merging.

Expand Down
9 changes: 8 additions & 1 deletion tools/check_conventions.py
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,8 @@ def env_reference(self):
def pull_request(self, title, body):
if not CONVENTIONAL.match(title):
self.report("pr-title", "", 0, title)
if body is None:
return
body = re.sub(r"<!--.*?-->", "", body or "", flags=re.S)
sections = dict(zip(SECTION.findall(body), SECTION.split(body)[2::2]))
for name in ("What", "Tested", "Checklist"):
Expand All @@ -360,6 +362,11 @@ def pull_request(self, title, body):
self.report("pr-template", "", 0, "fill Depends on with #N or none")


def dependabot(pr):
user = pr.get("user") or {}
return user.get("login") == "dependabot[bot]" and user.get("type") == "Bot"


def utf8(data):
try:
data.decode("utf-8")
Expand Down Expand Up @@ -595,7 +602,7 @@ def output(check, repo):
check.env_reference()
pr = json.load(open(args.event, encoding="utf-8")).get("pull_request") if args.event else None
if pr:
check.pull_request(pr["title"], pr["body"])
check.pull_request(pr["title"], None if dependabot(pr) else pr["body"])
elif args.title is not None or args.body:
check.pull_request(args.title or "", open(args.body, encoding="utf-8-sig").read() if args.body else "")
raise SystemExit(output(check, os.environ.get("GITHUB_REPOSITORY", "boykopovar/AnyPS5")))
30 changes: 30 additions & 0 deletions tools/tests/test_check_conventions_pr_template.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import json
import os
import re
import subprocess
Expand Down Expand Up @@ -125,5 +126,34 @@ def test_title_must_be_conventional(self):
self.assertIn("[pr-title] Pull request title is not Conventional Commits", result.stdout)


def run_event(self, user, title="ci: bump actions/checkout", text="Bumps actions/checkout from 6 to 7."):
event = {"pull_request": {"title": title, "body": text, "user": user}}
(self.root / "event.json").write_text(json.dumps(event), encoding="utf-8")
result = subprocess.run(
[sys.executable, "-I", str(CHECKER), "--base", "HEAD", "--head", "HEAD", "--event", "event.json"],
cwd=self.root, capture_output=True, text=True, encoding="utf-8",
env={key: value for key, value in os.environ.items()
if key not in ("GITHUB_EVENT_PATH", "GITHUB_STEP_SUMMARY", "GITHUB_ACTIONS")},
)
return result, [line[len(PREFIX):] for line in result.stdout.splitlines() if line.startswith(PREFIX)]

def test_dependabot_pull_request_skips_the_template(self):
result, findings = self.run_event({"login": "dependabot[bot]", "type": "Bot"})
self.assertEqual(result.returncode, 0, result.stdout + result.stderr)
self.assertEqual(findings, [])

def test_dependabot_title_is_still_checked(self):
result, _ = self.run_event({"login": "dependabot[bot]", "type": "Bot"}, title="Bump actions/checkout")
self.assertEqual(result.returncode, 1, result.stdout)
self.assertIn("[pr-title] Pull request title is not Conventional Commits", result.stdout)

def test_other_authors_of_the_same_description_fill_the_template(self):
for user in ({"login": "someone", "type": "User"}, {"login": "dependabot[bot]", "type": "User"},
{"login": "renovate[bot]", "type": "Bot"}, None):
with self.subTest(user=user):
result, findings = self.run_event(user)
self.assertEqual(result.returncode, 1, result.stdout)
self.assertIn("section 'What' is missing or empty", findings)

if __name__ == "__main__":
unittest.main()
Loading