Module: wine
Branch: master
Commit: 830348d78c38e9f68772bd6e5a3ea2555a206dd8
URL: https://gitlab.winehq.org/wine/wine/-/commit/830348d78c38e9f68772bd6e5a3ea2…
Author: Zhiyi Zhang <zzhang(a)codeweavers.com>
Date: Fri Jul 15 14:57:59 2022 +0800
comctl32/button: Pass the destination rectangle to GetThemePartSize() when painting check boxes.
The destination rectangle may be smaller than that of theme parts, in which case, the draw size
returned is adjusted to fit the destination rectangle. Without passing a destination rectangle
to GetThemePartSize(), the function assumes that there is no limit for destination.
This fixes winecfg check boxes missing the upper edge in 192 DPI. You may notice that the check box
bitmap is slightly shrank and so the shape is a bit off. However, this is what happens on Windows as
well when check box height is set to 8 DLUs.
GetThemePartSize() without destination rectangles are also used in other controls, but manual tests
showed that those controls don't shrink their theme background as check boxes do so they are left
unchanged.
Signed-off-by: Zhiyi Zhang <zzhang(a)codeweavers.com>
---
dlls/comctl32/button.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/comctl32/button.c b/dlls/comctl32/button.c
index ee7c2c288b1..089534b2b9d 100644
--- a/dlls/comctl32/button.c
+++ b/dlls/comctl32/button.c
@@ -2830,7 +2830,7 @@ static void CB_ThemedPaint(HTHEME theme, const BUTTON_INFO *infoPtr, HDC hDC, in
GetThemeBackgroundContentRect(theme, hDC, part, state, &client_rect, &content_rect);
region = set_control_clipping(hDC, &client_rect);
- if (FAILED(GetThemePartSize(theme, hDC, part, state, NULL, TS_DRAW, &box_size)))
+ if (FAILED(GetThemePartSize(theme, hDC, part, state, &content_rect, TS_DRAW, &box_size)))
{
box_size.cx = 12 * GetDpiForWindow(infoPtr->hwnd) / 96 + 1;
box_size.cy = box_size.cx;
Module: tools
Branch: master
Commit: e71c99a61b6b7e9cb20c2c88ba43fa212b039cbb
URL: https://gitlab.winehq.org/winehq/tools/-/commit/e71c99a61b6b7e9cb20c2c88ba4…
Author: Jeremy White <jwhite(a)codeweavers.com>
Date: Wed Jul 13 16:52:11 2022 -0500
Assign reviewers to merge requests with none.
The algorithm is intended to function as follows:
1. Gather all entries where the F: pattern matches at least one file
changed in the MR. The wildcard pattern (THE REST) is skipped.
2. Build the union of the M: fields of all matched entries. If empty,
build the union of the P: fields instead. Assign all members of the
union as reviewers. If empty, do nothing.
We ignore people that are not found in MAINTAINERS.
---
gitlab/gitlab-to-mail/assign.py | 130 ++++++++++++++++++++++++++++++++++
gitlab/gitlab-to-mail/gitlabtomail.py | 18 +++--
2 files changed, 143 insertions(+), 5 deletions(-)
diff --git a/gitlab/gitlab-to-mail/assign.py b/gitlab/gitlab-to-mail/assign.py
new file mode 100755
index 00000000..5a8b914d
--- /dev/null
+++ b/gitlab/gitlab-to-mail/assign.py
@@ -0,0 +1,130 @@
+#!/usr/bin/env -S python3 -B
+
+"""
+Determine who should review a given MR and assign them as reviewers
+"""
+
+import sys
+import copy
+import re
+from urllib.parse import urljoin
+import fnmatch
+import requests
+
+from util import fetch_all, Settings
+
+settings = Settings(sys.argv[1])
+
+def empty_record():
+ m = { 'name': None,
+ 'globs': [],
+ 'maintainers': [],
+ 'people': [],
+ }
+ return copy.deepcopy(m)
+
+def fetch_users():
+ url = urljoin(settings.GITLAB_URL, f"api/v4/projects/{settings.GITLAB_PROJECT_ID}/users")
+ return fetch_all(url, settings)
+
+def append_user(user_map, line, out, verbose=False):
+ match = re.match("(.+)<", line)
+ if match:
+ name = match.group(1).strip()
+ else:
+ print("Malformed person in MAINTAINERS: {}".format(line), file=sys.stderr)
+ return
+
+ if name in user_map:
+ out.append(user_map[name])
+ elif verbose:
+ print("Cannot find GitLab account for [{}]".format(name), file=sys.stderr)
+
+def get_maintainers_map(verbose=False):
+ url = urljoin(settings.GITLAB_URL, f"{settings.GITLAB_PROJECT_NAME}/-/raw/master/MAINTAINERS")
+ r = requests.get(url, headers={"PRIVATE-TOKEN": settings.GITLAB_TOKEN})
+ r = requests.get(url)
+ r.raise_for_status()
+
+ users = fetch_users()
+ user_map = {}
+ for u in users:
+ user_map[u['name']] = u['id']
+
+ maintainers = []
+
+ m = empty_record()
+ for utf_line in r.iter_lines():
+ line = utf_line.decode(r.encoding)
+ if not line or len(line) < 3:
+ continue
+ if line.find("F:\t") == 0:
+ # Skip THE REST patterns for now
+ if line[3:4] == '*':
+ continue
+ glob = line[3:]
+ # The Wine patterns are a bit unusual. They are file globs,
+ # but with an implicit trailing * if the target is a directory.
+ if glob[-1] == '/':
+ glob += '*'
+ m['globs'].append(glob)
+ elif line.find("M:\t") == 0:
+ append_user(user_map, line[3:], m['maintainers'], verbose)
+ elif line.find("P:\t") == 0:
+ append_user(user_map, line[3:], m['people'], verbose)
+ elif line.find("W:\t") == 0:
+ pass
+ elif len(m['globs']) == 0:
+ m['name'] = line
+ else:
+ maintainers.append(m)
+ m = empty_record()
+ m['name'] = line
+
+ return maintainers
+
+def post_reviewers(mr_iid, reviewers):
+ url = urljoin(settings.GITLAB_URL, f"api/v4/projects/{settings.GITLAB_PROJECT_ID}/merge_requests/{mr_iid}/")
+ r = requests.put(url, headers={"PRIVATE-TOKEN": settings.GITLAB_TOKEN}, json={'reviewer_ids': reviewers})
+ r.raise_for_status()
+
+def get_assignees(maintainers_map, files):
+ maintainers = []
+ people = []
+ for m in maintainers_map:
+ for glob in m['globs']:
+ for f in files:
+ if fnmatch.fnmatch(f, glob):
+ maintainers = maintainers + m['maintainers']
+ people = people + m['people']
+ if len(maintainers) > 0:
+ return maintainers
+ return people
+
+def assign_reviewers(mr_iid, version, maintainers_map, update_db):
+ paths = []
+ if 'diffs' not in version:
+ return
+ for d in version['diffs']:
+ if 'new_path' in d:
+ paths.append(d['new_path'])
+ a = get_assignees(maintainers_map, paths)
+ if len(a) > 0:
+ if update_db:
+ # set() prunes dupes, list() makes it json transmittable again
+ post_reviewers(mr_iid, list(set(a)))
+ else:
+ print("Debug: would set reviewers for {} to ids {}".format(mr_iid, a))
+
+def main(argv):
+ """ Debug code; pass in a config file and the names of files you want to test """
+ maintainers_map = get_maintainers_map(True)
+ a = get_assignees(maintainers_map, argv[2:])
+ users = fetch_users()
+ for id in a:
+ for u in users:
+ if id == u['id']:
+ print("{}: {}".format(id, u['name']))
+
+if __name__ == "__main__":
+ main(sys.argv)
diff --git a/gitlab/gitlab-to-mail/gitlabtomail.py b/gitlab/gitlab-to-mail/gitlabtomail.py
index 03824504..67909567 100755
--- a/gitlab/gitlab-to-mail/gitlabtomail.py
+++ b/gitlab/gitlab-to-mail/gitlabtomail.py
@@ -13,6 +13,7 @@ import mailbox
import smtplib
import email
from util import fetch_all, Settings
+from assign import get_maintainers_map, assign_reviewers
settings = Settings(sys.argv[1])
@@ -570,7 +571,7 @@ def create_cover(mr_id, mr_iid, mr_version, versions, nr_patches, mr):
return mail
-def process_mr(mr, update_db):
+def process_mr(mr, update_db, maintainers_map):
iid = mr['iid']
log(f"MR{iid} updated - processing")
@@ -623,6 +624,11 @@ def process_mr(mr, update_db):
log(f"MR{iid}v{version} - skipping, has no changes")
return
+ # Assign reviewers if there are none currently
+ if len(mr['reviewers']) == 0:
+ full_version = fetch_mr_version(iid, versions[0]['id'])
+ assign_reviewers(iid, full_version, maintainers_map, update_db)
+
fixup_date(cover, date)
create_headers_from_mr(cover, mr)
send_email(cover)
@@ -647,12 +653,12 @@ def process_mr(mr, update_db):
db.set_last_mr_updated_at(updated_at)
-def handle_debug_requests():
+def handle_debug_requests(maintainers_map):
for arg in sys.argv[2:]:
if arg.find("mr=") == 0:
print(f"Processing MR iid {arg[3:]}")
mr = fetch_specific_mr(int(arg[3:]))
- process_mr(mr, False)
+ process_mr(mr, False, maintainers_map)
elif arg.find("event=") == 0:
print(f"Processing event id {arg[6:]}")
# I did not immediately see a way to get a specific event.
@@ -667,8 +673,10 @@ def handle_debug_requests():
def main():
+ maintainers_map = get_maintainers_map()
+
if len(sys.argv) > 2:
- handle_debug_requests()
+ handle_debug_requests(maintainers_map)
return
# Process any new merge requests
@@ -679,7 +687,7 @@ def main():
db.set_last_mr_updated_at(last_mr_updated_at)
for mr in fetch_recently_updated_mrs(last_mr_updated_at):
- process_mr(mr, not settings.READ_ONLY)
+ process_mr(mr, not settings.READ_ONLY, maintainers_map)
date = db.get_last_event_date()
if not date: