Skip to content

Commit 8581525

Browse files
authored
Merge branch '3.x' into tatu-claude/3.1/1419-map-entry-shape-override
2 parents 1169897 + 100a28c commit 8581525

35 files changed

+1894
-784
lines changed
Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,3 @@
1-
# Licensed to the Apache Software Foundation (ASF) under one
2-
# or more contributor license agreements. See the NOTICE file
3-
# distributed with this work for additional information
4-
# regarding copyright ownership. The ASF licenses this file
5-
# to you under the Apache License, Version 2.0 (the
6-
# "License"); you may not use this file except in compliance
7-
# with the License. You may obtain a copy of the License at
8-
#
9-
# https://www.apache.org/licenses/LICENSE-2.0
10-
#
11-
# Unless required by applicable law or agreed to in writing,
12-
# software distributed under the License is distributed on an
13-
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14-
# KIND, either express or implied. See the License for the
15-
# specific language governing permissions and limitations
16-
# under the License.
17-
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip
18-
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.3.2/maven-wrapper-3.3.2.jar
1+
wrapperVersion=3.3.4
2+
distributionType=only-script
3+
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip

filter_popular_issues.py

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Filter GitHub issues from FasterXML/jackson-databind with 5+ upvotes.
4+
5+
This script fetches all open issues from the jackson-databind repository
6+
and filters them by the number of thumbs-up reactions (upvotes).
7+
8+
Usage:
9+
python filter_popular_issues.py [--min-upvotes N] [--state open|closed|all] [--token YOUR_TOKEN]
10+
11+
Environment:
12+
GITHUB_TOKEN: Optional GitHub personal access token for higher rate limits
13+
"""
14+
15+
import argparse
16+
import os
17+
import sys
18+
from typing import List, Dict
19+
import urllib.request
20+
import urllib.error
21+
import json
22+
import time
23+
24+
25+
def fetch_issues(owner: str, repo: str, state: str = "open", token: str = None) -> List[Dict]:
26+
"""
27+
Fetch all issues from a GitHub repository.
28+
29+
Args:
30+
owner: Repository owner (e.g., 'FasterXML')
31+
repo: Repository name (e.g., 'jackson-databind')
32+
state: Issue state filter ('open', 'closed', 'all')
33+
token: Optional GitHub personal access token
34+
35+
Returns:
36+
List of issue dictionaries
37+
"""
38+
issues = []
39+
page = 1
40+
per_page = 100
41+
42+
headers = {
43+
'Accept': 'application/vnd.github.v3+json',
44+
'User-Agent': 'Jackson-Issue-Filter/1.0'
45+
}
46+
47+
if token:
48+
headers['Authorization'] = f'token {token}'
49+
50+
while True:
51+
url = f'https://api.github.com/repos/{owner}/{repo}/issues?state={state}&page={page}&per_page={per_page}'
52+
53+
try:
54+
req = urllib.request.Request(url, headers=headers)
55+
with urllib.request.urlopen(req) as response:
56+
page_issues = json.loads(response.read().decode('utf-8'))
57+
58+
if not page_issues:
59+
break
60+
61+
# Filter out pull requests (they're returned by the issues API)
62+
page_issues = [issue for issue in page_issues if 'pull_request' not in issue]
63+
issues.extend(page_issues)
64+
65+
print(f"Fetched page {page} ({len(page_issues)} issues)...", file=sys.stderr)
66+
page += 1
67+
68+
# Be nice to the API
69+
time.sleep(0.5)
70+
71+
except urllib.error.HTTPError as e:
72+
if e.code == 403:
73+
print(f"Rate limit exceeded. Consider using a GitHub token.", file=sys.stderr)
74+
print(f"Error: {e.read().decode('utf-8')}", file=sys.stderr)
75+
else:
76+
print(f"HTTP Error {e.code}: {e.read().decode('utf-8')}", file=sys.stderr)
77+
sys.exit(1)
78+
except Exception as e:
79+
print(f"Error fetching issues: {e}", file=sys.stderr)
80+
sys.exit(1)
81+
82+
return issues
83+
84+
85+
def get_upvotes(issue: Dict) -> int:
86+
"""
87+
Get the number of thumbs-up reactions for an issue.
88+
89+
Args:
90+
issue: Issue dictionary from GitHub API
91+
92+
Returns:
93+
Number of thumbs-up reactions
94+
"""
95+
reactions = issue.get('reactions', {})
96+
return reactions.get('+1', 0)
97+
98+
99+
def filter_by_upvotes(issues: List[Dict], min_upvotes: int) -> List[Dict]:
100+
"""
101+
Filter issues by minimum upvote count.
102+
103+
Args:
104+
issues: List of issue dictionaries
105+
min_upvotes: Minimum number of upvotes required
106+
107+
Returns:
108+
Filtered list of issues
109+
"""
110+
filtered = [issue for issue in issues if get_upvotes(issue) >= min_upvotes]
111+
# Sort by upvotes (descending)
112+
filtered.sort(key=get_upvotes, reverse=True)
113+
return filtered
114+
115+
116+
def print_issues(issues: List[Dict], min_upvotes: int):
117+
"""
118+
Print filtered issues in a readable format.
119+
120+
Args:
121+
issues: List of issue dictionaries to print
122+
min_upvotes: Minimum upvotes threshold (for display)
123+
"""
124+
print(f"\nFound {len(issues)} issues with {min_upvotes}+ upvotes:\n")
125+
print("=" * 80)
126+
127+
for issue in issues:
128+
upvotes = get_upvotes(issue)
129+
number = issue['number']
130+
title = issue['title']
131+
url = issue['html_url']
132+
state = issue['state']
133+
labels = [label['name'] for label in issue.get('labels', [])]
134+
135+
print(f"\n#{number} - {title}")
136+
print(f"Upvotes: 👍 {upvotes}")
137+
print(f"State: {state}")
138+
if labels:
139+
print(f"Labels: {', '.join(labels)}")
140+
print(f"URL: {url}")
141+
print("-" * 80)
142+
143+
144+
def export_to_json(issues: List[Dict], filename: str):
145+
"""
146+
Export filtered issues to a JSON file.
147+
148+
Args:
149+
issues: List of issue dictionaries
150+
filename: Output filename
151+
"""
152+
simplified_issues = []
153+
for issue in issues:
154+
simplified_issues.append({
155+
'number': issue['number'],
156+
'title': issue['title'],
157+
'state': issue['state'],
158+
'upvotes': get_upvotes(issue),
159+
'url': issue['html_url'],
160+
'labels': [label['name'] for label in issue.get('labels', [])],
161+
'created_at': issue['created_at'],
162+
'updated_at': issue['updated_at']
163+
})
164+
165+
with open(filename, 'w') as f:
166+
json.dump(simplified_issues, f, indent=2)
167+
168+
print(f"\nExported {len(issues)} issues to {filename}")
169+
170+
171+
def main():
172+
parser = argparse.ArgumentParser(
173+
description='Filter GitHub issues by upvote count',
174+
formatter_class=argparse.RawDescriptionHelpFormatter,
175+
epilog='''
176+
Examples:
177+
python filter_popular_issues.py
178+
python filter_popular_issues.py --min-upvotes 10
179+
python filter_popular_issues.py --state all --output popular_issues.json
180+
python filter_popular_issues.py --token ghp_xxxxx
181+
'''
182+
)
183+
184+
parser.add_argument(
185+
'--min-upvotes',
186+
type=int,
187+
default=5,
188+
help='Minimum number of upvotes (default: 5)'
189+
)
190+
191+
parser.add_argument(
192+
'--state',
193+
choices=['open', 'closed', 'all'],
194+
default='open',
195+
help='Issue state to filter (default: open)'
196+
)
197+
198+
parser.add_argument(
199+
'--token',
200+
help='GitHub personal access token (or set GITHUB_TOKEN env var)'
201+
)
202+
203+
parser.add_argument(
204+
'--output',
205+
'-o',
206+
help='Export results to JSON file'
207+
)
208+
209+
args = parser.parse_args()
210+
211+
# Get token from args or environment
212+
token = args.token or os.environ.get('GITHUB_TOKEN')
213+
214+
if not token:
215+
print("Warning: No GitHub token provided. Rate limits will be lower.", file=sys.stderr)
216+
print("Consider setting GITHUB_TOKEN environment variable or using --token flag.\n", file=sys.stderr)
217+
218+
print(f"Fetching {args.state} issues from FasterXML/jackson-databind...", file=sys.stderr)
219+
220+
issues = fetch_issues('FasterXML', 'jackson-databind', state=args.state, token=token)
221+
print(f"Total issues fetched: {len(issues)}", file=sys.stderr)
222+
223+
filtered_issues = filter_by_upvotes(issues, args.min_upvotes)
224+
225+
print_issues(filtered_issues, args.min_upvotes)
226+
227+
if args.output:
228+
export_to_json(filtered_issues, args.output)
229+
230+
231+
if __name__ == '__main__':
232+
main()

0 commit comments

Comments
 (0)