Skip to content

Commit 3d9fce9

Browse files
authored
Merge branch 'master' into feature/la-vectors
2 parents 830cf42 + 6d10a15 commit 3d9fce9

File tree

100 files changed

+5088
-700
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

100 files changed

+5088
-700
lines changed

.devcontainer/devcontainer.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
"extensions": [
4242
"ms-vscode.cpptools",
4343
"ms-vscode.cpptools-extension-pack",
44-
"VisualStudioExptTeam.vscodeintellicode",
4544
"VisualStudioExptTeam.intellicode-api-usage-examples",
4645
"ms-vscode.cmake-tools",
4746
"fredericbonnet.cmake-test-adapter",

.github/generate-job-matrix.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,6 @@ def make_msvc_config(release: str, version: int) -> Configuration:
9797
# arm64 runners are expensive; only consider one version
9898
if ver == 18 or platform != "arm64"
9999
]
100-
+ [
101-
make_apple_clang_config("macos-13", ver, std_format_support=False)
102-
for ver in ["15.2"]
103-
]
104100
# std::format is available in Xcode 16.1 or later
105101
+ [
106102
make_apple_clang_config("macos-14", ver, std_format_support=True)

.github/pull_request_template.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# 📋 Pull Request Description
2+
3+
<!-- Provide a brief description of what this PR does -->
4+
5+
## Type of Change
6+
<!-- Mark the relevant option with an "x" -->
7+
8+
- [ ] 🐛 Bug fix (non-breaking change which fixes an issue)
9+
- [ ] ✨ New feature (non-breaking change which adds functionality)
10+
- [ ] 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
11+
- [ ] 📚 Documentation update
12+
- [ ] 🔧 Build system / CI changes
13+
- [ ] 🧪 Test improvements
14+
- [ ] ♻️ Code refactoring
15+
- [ ] 🎨 Code style improvements
16+
17+
## 🔗 Related Issues
18+
<!-- Link any related issues using "Closes #xxx", "Resolves #xxx", or "Relates to #xxx" -->
19+
20+
## 📝 Changes Made
21+
<!-- Describe the changes you've made -->
22+
23+
## 🌟 Additional Context
24+
<!-- Add any additional context, screenshots, or notes for reviewers -->
25+
26+
## ✅ Checklist
27+
<!-- Final checklist before submitting -->
28+
29+
- [ ] I have read the [Contributing Guidelines](https://mpusz.github.io/mp-units/latest/getting_started/contributing/)
30+
- [ ] I have commented my code, particularly in hard-to-understand areas
31+
- [ ] I have added tests that prove my fix is effective or that my feature works
32+
- [ ] I have updated the project's documentation to cover the modified or new functionality
33+
(if this change affects user-facing features)
34+
35+
---
36+
37+
**By submitting this pull request, I confirm that my contribution is made under the terms
38+
of the project's MIT license.**
Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Update CONTRIBUTORS.md with current GitHub contributors
4+
This script fetches contributor information from GitHub API and updates the contributors list
5+
"""
6+
7+
import subprocess
8+
import sys
9+
from pathlib import Path
10+
from typing import Dict, List, Optional
11+
12+
try:
13+
import requests
14+
except ImportError:
15+
print("Error: requests library not found. Install with: pip install requests")
16+
sys.exit(1)
17+
18+
19+
class ContributorUpdater:
20+
"""Manages updating the contributors list"""
21+
22+
def __init__(self, repo_owner: str, repo_name: str, token: Optional[str] = None):
23+
self.repo_owner = repo_owner
24+
self.repo_name = repo_name
25+
self.token = token
26+
self.headers = {}
27+
if token:
28+
self.headers["Authorization"] = f"token {token}"
29+
30+
def fetch_contributors(self) -> List[Dict]:
31+
"""Fetch contributors from GitHub API"""
32+
url = f"https://api.github.com/repos/{self.repo_owner}/{self.repo_name}/contributors"
33+
34+
all_contributors = []
35+
page = 1
36+
37+
while True:
38+
params = {"page": page, "per_page": 100}
39+
response = requests.get(url, headers=self.headers, params=params)
40+
41+
if response.status_code != 200:
42+
print(f"Error fetching contributors: {response.status_code}")
43+
print(response.text)
44+
break
45+
46+
contributors = response.json()
47+
if not contributors:
48+
break
49+
50+
all_contributors.extend(contributors)
51+
page += 1
52+
53+
return all_contributors
54+
55+
def get_contributor_details(self, username: str) -> Dict:
56+
"""Get detailed information about a contributor"""
57+
url = f"https://api.github.com/users/{username}"
58+
response = requests.get(url, headers=self.headers)
59+
60+
if response.status_code == 200:
61+
return response.json()
62+
return {}
63+
64+
def categorize_contributors(
65+
self, contributors: List[Dict]
66+
) -> Dict[str, List[Dict]]:
67+
"""Categorize contributors by contribution level"""
68+
# Core team members (manually maintained)
69+
core_team = {"mpusz", "JohelEGP", "chiphogg"}
70+
core_team_lower = {name.lower() for name in core_team}
71+
72+
# Categorize by contribution count
73+
major_contributors = [] # 50+ contributions
74+
regular_contributors = [] # 10-49 contributions
75+
occasional_contributors = [] # 1-9 contributions
76+
77+
for contributor in contributors:
78+
username = contributor["login"]
79+
contributions = contributor["contributions"]
80+
81+
# Skip core team members (handled separately)
82+
if username.lower() in core_team_lower:
83+
continue
84+
85+
# Skip bots
86+
if contributor.get("type") == "Bot":
87+
continue
88+
89+
if contributions >= 50:
90+
major_contributors.append(contributor)
91+
elif contributions >= 10:
92+
regular_contributors.append(contributor)
93+
else:
94+
occasional_contributors.append(contributor)
95+
96+
return {
97+
"major": major_contributors,
98+
"regular": regular_contributors,
99+
"occasional": occasional_contributors,
100+
}
101+
102+
def generate_contributor_section(
103+
self, contributors: List[Dict], include_contributions: bool = True
104+
) -> str:
105+
"""Generate markdown for a list of contributors"""
106+
if not contributors:
107+
return "*No contributors in this category yet.*\n"
108+
109+
lines = []
110+
for contributor in contributors:
111+
username = contributor["login"]
112+
profile_url = contributor["html_url"]
113+
contributions = contributor["contributions"]
114+
115+
if include_contributions:
116+
line = (
117+
f"- **[{username}]({profile_url})** ({contributions} contributions)"
118+
)
119+
else:
120+
line = f"- **[{username}]({profile_url})**"
121+
122+
lines.append(line)
123+
124+
return "\n".join(lines) + "\n"
125+
126+
def update_contributors_file(self, contributors: List[Dict]):
127+
"""Update the CONTRIBUTORS.md file"""
128+
contributors_file = Path("CONTRIBUTORS.md")
129+
130+
if not contributors_file.exists():
131+
print("CONTRIBUTORS.md not found!")
132+
return
133+
134+
# Read current content
135+
content = contributors_file.read_text()
136+
137+
# Categorize contributors
138+
categorized = self.categorize_contributors(contributors)
139+
140+
# Generate new contributor sections
141+
major_section = self.generate_contributor_section(categorized["major"])
142+
regular_section = self.generate_contributor_section(categorized["regular"])
143+
occasional_section = self.generate_contributor_section(
144+
categorized["occasional"], include_contributions=False
145+
)
146+
147+
# Generate statistics (excluding core team)
148+
core_team = {"mpusz", "JohelEGP", "chiphogg"}
149+
core_team_lower = {name.lower() for name in core_team}
150+
non_core_contributors = [
151+
c
152+
for c in contributors
153+
if c["login"].lower() not in core_team_lower and c.get("type") != "Bot"
154+
]
155+
total_contributors = len(non_core_contributors)
156+
total_contributions = sum(c["contributions"] for c in non_core_contributors)
157+
158+
stats_section = f"""## Statistics
159+
160+
- **Total Contributors**: {total_contributors}
161+
- **Total Contributions**: {total_contributions}
162+
- **Major Contributors** (50+ contributions): {len(categorized['major'])}
163+
- **Regular Contributors** (10-49 contributions): {len(categorized['regular'])}
164+
- **Occasional Contributors** (1-9 contributions): {len(categorized['occasional'])}
165+
166+
_Last updated: {self.get_current_date()}_
167+
"""
168+
169+
# Update the contributors section
170+
# Look for the CONTRIBUTORS_START/END markers
171+
start_marker = "<!-- CONTRIBUTORS_START -->"
172+
end_marker = "<!-- CONTRIBUTORS_END -->"
173+
174+
if start_marker in content and end_marker in content:
175+
# Replace the content between markers
176+
before = content.split(start_marker)[0]
177+
after = content.split(end_marker)[1]
178+
179+
new_content = f"""{before}{start_marker}
180+
181+
{stats_section}
182+
183+
### Major Contributors
184+
185+
_50+ contributions_
186+
187+
{major_section}
188+
189+
### Regular Contributors
190+
191+
_10-49 contributions_
192+
193+
{regular_section}
194+
195+
### All Contributors
196+
197+
_Everyone who has contributed to mp-units_
198+
199+
{occasional_section}
200+
201+
{end_marker}{after}"""
202+
203+
contributors_file.write_text(new_content)
204+
print(f"Updated CONTRIBUTORS.md with {total_contributors} contributors")
205+
else:
206+
print("Could not find contributor markers in CONTRIBUTORS.md")
207+
208+
def get_current_date(self) -> str:
209+
"""Get current date in a readable format"""
210+
from datetime import datetime
211+
212+
return datetime.now().strftime("%Y-%m-%d")
213+
214+
215+
def get_github_token() -> Optional[str]:
216+
"""Try to get GitHub token from various sources"""
217+
import os
218+
219+
# Try environment variable
220+
token = os.getenv("GITHUB_TOKEN")
221+
if token:
222+
return token
223+
224+
# Try git config
225+
try:
226+
result = subprocess.run(
227+
["git", "config", "--get", "github.token"], capture_output=True, text=True
228+
)
229+
if result.returncode == 0:
230+
return result.stdout.strip()
231+
except Exception:
232+
pass
233+
234+
return None
235+
236+
237+
def main():
238+
"""Main function"""
239+
# Get GitHub token (optional but recommended to avoid rate limits)
240+
token = get_github_token()
241+
if not token:
242+
print("Warning: No GitHub token found. You may hit API rate limits.")
243+
print("Set GITHUB_TOKEN environment variable for better performance.")
244+
245+
# Initialize updater
246+
updater = ContributorUpdater("mpusz", "units", token)
247+
248+
try:
249+
# Fetch contributors
250+
print("Fetching contributors from GitHub...")
251+
contributors = updater.fetch_contributors()
252+
print(f"Found {len(contributors)} contributors")
253+
254+
# Update contributors file
255+
updater.update_contributors_file(contributors)
256+
257+
except Exception as e:
258+
print(f"Error updating contributors: {e}")
259+
sys.exit(1)
260+
261+
262+
if __name__ == "__main__":
263+
main()

.github/workflows/ci-conan.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,5 +239,5 @@ jobs:
239239
- name: Do housekeeping on conan-mpusz-oss
240240
shell: bash
241241
run: |
242-
conan remove mp-units/*#!latest --confirm -r conan-mpusz-oss
243-
conan remove mp-units/*:*#!latest --confirm -r conan-mpusz-oss
242+
conan remove mp-units/*#~latest --confirm -r conan-mpusz-oss
243+
conan remove mp-units/*:*#~latest --confirm -r conan-mpusz-oss

0 commit comments

Comments
 (0)