gitstar 1.0.0__tar.gz → 1.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gitstar-1.1.0/LICENSE +22 -0
- gitstar-1.1.0/PKG-INFO +146 -0
- gitstar-1.1.0/README.md +117 -0
- gitstar-1.1.0/gitstar/__init__.py +7 -0
- gitstar-1.1.0/gitstar/__main__.py +5 -0
- gitstar-1.1.0/gitstar/core.py +217 -0
- gitstar-1.1.0/gitstar.egg-info/PKG-INFO +146 -0
- {gitstar-1.0.0 → gitstar-1.1.0}/gitstar.egg-info/SOURCES.txt +4 -1
- gitstar-1.1.0/pyproject.toml +43 -0
- {gitstar-1.0.0 → gitstar-1.1.0}/setup.cfg +4 -4
- gitstar-1.1.0/setup.py +3 -0
- gitstar-1.1.0/tests/test_cli.py +157 -0
- gitstar-1.0.0/PKG-INFO +0 -60
- gitstar-1.0.0/README.md +0 -39
- gitstar-1.0.0/gitstar/__init__.py +0 -1
- gitstar-1.0.0/gitstar/core.py +0 -77
- gitstar-1.0.0/gitstar.egg-info/PKG-INFO +0 -60
- gitstar-1.0.0/pyproject.toml +0 -3
- gitstar-1.0.0/setup.py +0 -27
- {gitstar-1.0.0 → gitstar-1.1.0}/gitstar.egg-info/dependency_links.txt +0 -0
- {gitstar-1.0.0 → gitstar-1.1.0}/gitstar.egg-info/entry_points.txt +0 -0
- {gitstar-1.0.0 → gitstar-1.1.0}/gitstar.egg-info/top_level.txt +0 -0
gitstar-1.1.0/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Imran Pollob
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
gitstar-1.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gitstar
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: Calculate the total stars earned by a GitHub user or organization
|
|
5
|
+
Author-email: Imran Pollob <imranpollob@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/imranpollob/github-star-calculator
|
|
8
|
+
Project-URL: Repository, https://github.com/imranpollob/github-star-calculator.git
|
|
9
|
+
Project-URL: Issues, https://github.com/imranpollob/github-star-calculator/issues
|
|
10
|
+
Keywords: github,stars,stargazers,cli,github-api,developer-tools
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
23
|
+
Classifier: Topic :: Software Development :: Version Control :: Git
|
|
24
|
+
Classifier: Topic :: Utilities
|
|
25
|
+
Requires-Python: >=3.8
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
# Gitstar
|
|
31
|
+
|
|
32
|
+
[](https://pypi.org/project/gitstar/)
|
|
33
|
+
[](https://pypi.org/project/gitstar/)
|
|
34
|
+
[](https://opensource.org/licenses/MIT)
|
|
35
|
+
|
|
36
|
+
A fast, lightweight, zero-dependency command-line tool to calculate the total number of stars earned by any GitHub user or organization.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Features
|
|
41
|
+
|
|
42
|
+
- **Fast & Zero Dependencies**: Built entirely with Python's standard library. No external runtime dependencies.
|
|
43
|
+
- **Cross-Platform**: Full support for Linux, macOS, and Windows (with safe terminal encoding fallbacks).
|
|
44
|
+
- **Authentication & Rate-Limit Friendly**: Supports GitHub Personal Access Tokens (`--token` or `GITHUB_TOKEN` / `GH_TOKEN` environment variables) to bypass the unauthenticated 60 requests/hour limit.
|
|
45
|
+
- **Informative Output**: Clean tabular layout ranking repositories by stars.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
|
|
51
|
+
Install via pip:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install gitstar
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Or upgrade to the latest version:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
pip install --upgrade gitstar
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Usage
|
|
66
|
+
|
|
67
|
+
### Basic Usage
|
|
68
|
+
|
|
69
|
+
Find the total stars for any GitHub user or organization:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
gitstar <username>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Example:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
gitstar torvalds
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Limiting Results
|
|
82
|
+
|
|
83
|
+
Display only the top $N$ starred repositories:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
# Using positional shorthand:
|
|
87
|
+
gitstar torvalds 5
|
|
88
|
+
|
|
89
|
+
# Or using the -l / --limit flag:
|
|
90
|
+
gitstar torvalds --limit 5
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Output Example
|
|
94
|
+
|
|
95
|
+
```text
|
|
96
|
+
Total ⭐️ 234120
|
|
97
|
+
https://github.com/torvalds/linux ⭐️ 186400
|
|
98
|
+
https://github.com/torvalds/subsurface ⭐️ 3150
|
|
99
|
+
https://github.com/torvalds/pesconvert ⭐️ 285
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Authentication & Rate Limits
|
|
105
|
+
|
|
106
|
+
By default, unauthenticated GitHub API requests are limited to **60 requests per hour** per IP address.
|
|
107
|
+
|
|
108
|
+
To increase your limit to **5,000 requests per hour**, provide a GitHub Personal Access Token using either:
|
|
109
|
+
|
|
110
|
+
1. **Environment Variable** (recommended):
|
|
111
|
+
```bash
|
|
112
|
+
export GITHUB_TOKEN="ghp_your_token_here"
|
|
113
|
+
gitstar torvalds
|
|
114
|
+
```
|
|
115
|
+
*(On Windows PowerShell: `$env:GITHUB_TOKEN="ghp_your_token_here"`)*
|
|
116
|
+
|
|
117
|
+
2. **CLI Option**:
|
|
118
|
+
```bash
|
|
119
|
+
gitstar torvalds --token ghp_your_token_here
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## CLI Options Reference
|
|
125
|
+
|
|
126
|
+
```text
|
|
127
|
+
usage: gitstar [-h] [-l LIMIT] [-t TOKEN] [-v] [username] [limit]
|
|
128
|
+
|
|
129
|
+
Calculate the total stars earned by a GitHub user or organization.
|
|
130
|
+
|
|
131
|
+
positional arguments:
|
|
132
|
+
username GitHub username or organization
|
|
133
|
+
limit Number of top repositories to display (positional shorthand)
|
|
134
|
+
|
|
135
|
+
options:
|
|
136
|
+
-h, --help show this help message and exit
|
|
137
|
+
-l, --limit LIMIT Number of top repositories to display
|
|
138
|
+
-t, --token TOKEN GitHub Personal Access Token (defaults to GITHUB_TOKEN or GH_TOKEN)
|
|
139
|
+
-v, --version show program's version number and exit
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## License
|
|
145
|
+
|
|
146
|
+
This project is licensed under the [MIT License](LICENSE).
|
gitstar-1.1.0/README.md
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Gitstar
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/gitstar/)
|
|
4
|
+
[](https://pypi.org/project/gitstar/)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
|
|
7
|
+
A fast, lightweight, zero-dependency command-line tool to calculate the total number of stars earned by any GitHub user or organization.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **Fast & Zero Dependencies**: Built entirely with Python's standard library. No external runtime dependencies.
|
|
14
|
+
- **Cross-Platform**: Full support for Linux, macOS, and Windows (with safe terminal encoding fallbacks).
|
|
15
|
+
- **Authentication & Rate-Limit Friendly**: Supports GitHub Personal Access Tokens (`--token` or `GITHUB_TOKEN` / `GH_TOKEN` environment variables) to bypass the unauthenticated 60 requests/hour limit.
|
|
16
|
+
- **Informative Output**: Clean tabular layout ranking repositories by stars.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
Install via pip:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install gitstar
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Or upgrade to the latest version:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pip install --upgrade gitstar
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Usage
|
|
37
|
+
|
|
38
|
+
### Basic Usage
|
|
39
|
+
|
|
40
|
+
Find the total stars for any GitHub user or organization:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
gitstar <username>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Example:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
gitstar torvalds
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Limiting Results
|
|
53
|
+
|
|
54
|
+
Display only the top $N$ starred repositories:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Using positional shorthand:
|
|
58
|
+
gitstar torvalds 5
|
|
59
|
+
|
|
60
|
+
# Or using the -l / --limit flag:
|
|
61
|
+
gitstar torvalds --limit 5
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Output Example
|
|
65
|
+
|
|
66
|
+
```text
|
|
67
|
+
Total ⭐️ 234120
|
|
68
|
+
https://github.com/torvalds/linux ⭐️ 186400
|
|
69
|
+
https://github.com/torvalds/subsurface ⭐️ 3150
|
|
70
|
+
https://github.com/torvalds/pesconvert ⭐️ 285
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Authentication & Rate Limits
|
|
76
|
+
|
|
77
|
+
By default, unauthenticated GitHub API requests are limited to **60 requests per hour** per IP address.
|
|
78
|
+
|
|
79
|
+
To increase your limit to **5,000 requests per hour**, provide a GitHub Personal Access Token using either:
|
|
80
|
+
|
|
81
|
+
1. **Environment Variable** (recommended):
|
|
82
|
+
```bash
|
|
83
|
+
export GITHUB_TOKEN="ghp_your_token_here"
|
|
84
|
+
gitstar torvalds
|
|
85
|
+
```
|
|
86
|
+
*(On Windows PowerShell: `$env:GITHUB_TOKEN="ghp_your_token_here"`)*
|
|
87
|
+
|
|
88
|
+
2. **CLI Option**:
|
|
89
|
+
```bash
|
|
90
|
+
gitstar torvalds --token ghp_your_token_here
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## CLI Options Reference
|
|
96
|
+
|
|
97
|
+
```text
|
|
98
|
+
usage: gitstar [-h] [-l LIMIT] [-t TOKEN] [-v] [username] [limit]
|
|
99
|
+
|
|
100
|
+
Calculate the total stars earned by a GitHub user or organization.
|
|
101
|
+
|
|
102
|
+
positional arguments:
|
|
103
|
+
username GitHub username or organization
|
|
104
|
+
limit Number of top repositories to display (positional shorthand)
|
|
105
|
+
|
|
106
|
+
options:
|
|
107
|
+
-h, --help show this help message and exit
|
|
108
|
+
-l, --limit LIMIT Number of top repositories to display
|
|
109
|
+
-t, --token TOKEN GitHub Personal Access Token (defaults to GITHUB_TOKEN or GH_TOKEN)
|
|
110
|
+
-v, --version show program's version number and exit
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## License
|
|
116
|
+
|
|
117
|
+
This project is licensed under the [MIT License](LICENSE).
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import datetime
|
|
3
|
+
import json
|
|
4
|
+
import math
|
|
5
|
+
import os
|
|
6
|
+
import sys
|
|
7
|
+
from urllib.error import HTTPError, URLError
|
|
8
|
+
from urllib.parse import quote
|
|
9
|
+
from urllib.request import Request, urlopen
|
|
10
|
+
|
|
11
|
+
VERSION = "1.1.0"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def configure_terminal_encoding():
|
|
15
|
+
"""Ensure standard output streams handle UTF-8 without crashing on Windows."""
|
|
16
|
+
if sys.platform == "win32":
|
|
17
|
+
for stream in (sys.stdout, sys.stderr):
|
|
18
|
+
if hasattr(stream, "reconfigure"):
|
|
19
|
+
try:
|
|
20
|
+
stream.reconfigure(encoding="utf-8", errors="replace")
|
|
21
|
+
except Exception:
|
|
22
|
+
pass
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def get_star_symbol() -> str:
|
|
26
|
+
"""Return a star symbol compatible with the current terminal encoding."""
|
|
27
|
+
for symbol in ("⭐️", "★", "*"):
|
|
28
|
+
try:
|
|
29
|
+
encoding = getattr(sys.stdout, "encoding", None) or "utf-8"
|
|
30
|
+
symbol.encode(encoding)
|
|
31
|
+
return symbol
|
|
32
|
+
except (UnicodeEncodeError, LookupError):
|
|
33
|
+
continue
|
|
34
|
+
return "*"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def fetch(endpoint: str, token: str = None):
|
|
38
|
+
"""Fetch JSON from GitHub API with proper headers, timeout, and error handling."""
|
|
39
|
+
url = f"https://api.github.com/{endpoint.lstrip('/')}"
|
|
40
|
+
headers = {
|
|
41
|
+
"Accept": "application/vnd.github.v3+json",
|
|
42
|
+
"User-Agent": f"gitstar/{VERSION}",
|
|
43
|
+
}
|
|
44
|
+
if token:
|
|
45
|
+
headers["Authorization"] = f"Bearer {token}"
|
|
46
|
+
|
|
47
|
+
request = Request(url, headers=headers)
|
|
48
|
+
|
|
49
|
+
try:
|
|
50
|
+
with urlopen(request, timeout=15) as response:
|
|
51
|
+
return json.loads(response.read().decode("utf-8"))
|
|
52
|
+
except HTTPError as e:
|
|
53
|
+
try:
|
|
54
|
+
e.close()
|
|
55
|
+
except Exception:
|
|
56
|
+
pass
|
|
57
|
+
if e.code == 404:
|
|
58
|
+
print(f"Error: GitHub user or organization not found.", file=sys.stderr)
|
|
59
|
+
elif e.code == 403:
|
|
60
|
+
reset_time = e.headers.get("x-ratelimit-reset")
|
|
61
|
+
if reset_time:
|
|
62
|
+
try:
|
|
63
|
+
reset_dt = datetime.datetime.fromtimestamp(
|
|
64
|
+
int(reset_time), tz=datetime.timezone.utc
|
|
65
|
+
)
|
|
66
|
+
reset_str = reset_dt.strftime("%Y-%m-%d %H:%M:%S UTC")
|
|
67
|
+
except Exception:
|
|
68
|
+
reset_str = reset_time
|
|
69
|
+
print(
|
|
70
|
+
f"Error: GitHub API rate limit exceeded.\n"
|
|
71
|
+
f"Rate limit resets at: {reset_str}\n"
|
|
72
|
+
f"Tip: Provide a GitHub token using --token or the GITHUB_TOKEN environment variable.",
|
|
73
|
+
file=sys.stderr,
|
|
74
|
+
)
|
|
75
|
+
else:
|
|
76
|
+
print(
|
|
77
|
+
f"Error: Access forbidden (HTTP 403).\n"
|
|
78
|
+
f"Reason: {e.reason}\n"
|
|
79
|
+
f"Tip: If you hit the rate limit, provide a GitHub token using --token or GITHUB_TOKEN.",
|
|
80
|
+
file=sys.stderr,
|
|
81
|
+
)
|
|
82
|
+
elif e.code == 401:
|
|
83
|
+
print(
|
|
84
|
+
"Error: Unauthorized (HTTP 401). Please check your GitHub token.",
|
|
85
|
+
file=sys.stderr,
|
|
86
|
+
)
|
|
87
|
+
else:
|
|
88
|
+
print(f"Error: GitHub API request failed ({e.code} {e.reason}).", file=sys.stderr)
|
|
89
|
+
sys.exit(1)
|
|
90
|
+
except URLError as e:
|
|
91
|
+
print(
|
|
92
|
+
f"Error: Network connection failed ({e.reason}). Please check your internet connection.",
|
|
93
|
+
file=sys.stderr,
|
|
94
|
+
)
|
|
95
|
+
sys.exit(1)
|
|
96
|
+
except TimeoutError:
|
|
97
|
+
print("Error: Request timed out while connecting to GitHub.", file=sys.stderr)
|
|
98
|
+
sys.exit(1)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
102
|
+
"""Build command-line argument parser."""
|
|
103
|
+
parser = argparse.ArgumentParser(
|
|
104
|
+
prog="gitstar",
|
|
105
|
+
description="Calculate the total stars earned by a GitHub user or organization.",
|
|
106
|
+
)
|
|
107
|
+
parser.add_argument(
|
|
108
|
+
"username",
|
|
109
|
+
nargs="?",
|
|
110
|
+
default=None,
|
|
111
|
+
help="GitHub username or organization",
|
|
112
|
+
)
|
|
113
|
+
parser.add_argument(
|
|
114
|
+
"pos_limit",
|
|
115
|
+
nargs="?",
|
|
116
|
+
type=int,
|
|
117
|
+
default=None,
|
|
118
|
+
metavar="limit",
|
|
119
|
+
help="Number of top repositories to display (positional shorthand)",
|
|
120
|
+
)
|
|
121
|
+
parser.add_argument(
|
|
122
|
+
"-l",
|
|
123
|
+
"--limit",
|
|
124
|
+
type=int,
|
|
125
|
+
default=None,
|
|
126
|
+
help="Number of top repositories to display",
|
|
127
|
+
)
|
|
128
|
+
parser.add_argument(
|
|
129
|
+
"-t",
|
|
130
|
+
"--token",
|
|
131
|
+
type=str,
|
|
132
|
+
default=None,
|
|
133
|
+
help="GitHub Personal Access Token (defaults to GITHUB_TOKEN or GH_TOKEN environment variable)",
|
|
134
|
+
)
|
|
135
|
+
parser.add_argument(
|
|
136
|
+
"-v",
|
|
137
|
+
"--version",
|
|
138
|
+
action="version",
|
|
139
|
+
version=f"%(prog)s {VERSION}",
|
|
140
|
+
)
|
|
141
|
+
return parser
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def main(argv=None):
|
|
145
|
+
configure_terminal_encoding()
|
|
146
|
+
parser = build_parser()
|
|
147
|
+
|
|
148
|
+
if argv is None:
|
|
149
|
+
argv = sys.argv[1:]
|
|
150
|
+
|
|
151
|
+
# Show friendly help when invoked with no arguments
|
|
152
|
+
if len(argv) == 0:
|
|
153
|
+
parser.print_help()
|
|
154
|
+
sys.exit(0)
|
|
155
|
+
|
|
156
|
+
args = parser.parse_args(argv)
|
|
157
|
+
|
|
158
|
+
if not args.username:
|
|
159
|
+
parser.print_help()
|
|
160
|
+
sys.exit(0)
|
|
161
|
+
|
|
162
|
+
# Determine limit (flag has priority over positional shorthand)
|
|
163
|
+
limit = args.limit if args.limit is not None else args.pos_limit
|
|
164
|
+
if limit is not None and limit < 0:
|
|
165
|
+
parser.error("Limit must be a non-negative integer.")
|
|
166
|
+
|
|
167
|
+
# Determine token: CLI flag -> GITHUB_TOKEN -> GH_TOKEN
|
|
168
|
+
token = (
|
|
169
|
+
args.token
|
|
170
|
+
or os.environ.get("GITHUB_TOKEN")
|
|
171
|
+
or os.environ.get("GH_TOKEN")
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
username = args.username.strip()
|
|
175
|
+
user = fetch(f"users/{quote(username)}", token=token)
|
|
176
|
+
|
|
177
|
+
public_repos = user.get("public_repos", 0)
|
|
178
|
+
if not public_repos:
|
|
179
|
+
print(f"'{username}' does not have any public repositories.")
|
|
180
|
+
sys.exit(0)
|
|
181
|
+
|
|
182
|
+
pages = math.ceil(public_repos / 100)
|
|
183
|
+
total_stars = 0
|
|
184
|
+
repo_star_map = {}
|
|
185
|
+
highest_name = 0
|
|
186
|
+
|
|
187
|
+
for page in range(1, pages + 1):
|
|
188
|
+
repos = fetch(
|
|
189
|
+
f"users/{quote(username)}/repos?per_page=100&page={page}",
|
|
190
|
+
token=token,
|
|
191
|
+
)
|
|
192
|
+
if not repos:
|
|
193
|
+
break
|
|
194
|
+
|
|
195
|
+
for repo in repos:
|
|
196
|
+
repo_url = repo.get("html_url", repo.get("name", "unknown"))
|
|
197
|
+
stars = repo.get("stargazers_count", 0)
|
|
198
|
+
repo_star_map[repo_url] = stars
|
|
199
|
+
total_stars += stars
|
|
200
|
+
highest_name = max(highest_name, len(repo_url))
|
|
201
|
+
|
|
202
|
+
star_symbol = get_star_symbol()
|
|
203
|
+
print(f"Total {star_symbol} {total_stars}")
|
|
204
|
+
|
|
205
|
+
if limit != 0 and repo_star_map:
|
|
206
|
+
sorted_repos = sorted(
|
|
207
|
+
repo_star_map.items(), key=lambda x: x[1], reverse=True
|
|
208
|
+
)
|
|
209
|
+
if limit is not None:
|
|
210
|
+
sorted_repos = sorted_repos[:limit]
|
|
211
|
+
|
|
212
|
+
for repo, stars in sorted_repos:
|
|
213
|
+
print(f"{repo:<{highest_name}} {star_symbol} {stars}")
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
if __name__ == "__main__":
|
|
217
|
+
main()
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gitstar
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: Calculate the total stars earned by a GitHub user or organization
|
|
5
|
+
Author-email: Imran Pollob <imranpollob@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/imranpollob/github-star-calculator
|
|
8
|
+
Project-URL: Repository, https://github.com/imranpollob/github-star-calculator.git
|
|
9
|
+
Project-URL: Issues, https://github.com/imranpollob/github-star-calculator/issues
|
|
10
|
+
Keywords: github,stars,stargazers,cli,github-api,developer-tools
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
23
|
+
Classifier: Topic :: Software Development :: Version Control :: Git
|
|
24
|
+
Classifier: Topic :: Utilities
|
|
25
|
+
Requires-Python: >=3.8
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
# Gitstar
|
|
31
|
+
|
|
32
|
+
[](https://pypi.org/project/gitstar/)
|
|
33
|
+
[](https://pypi.org/project/gitstar/)
|
|
34
|
+
[](https://opensource.org/licenses/MIT)
|
|
35
|
+
|
|
36
|
+
A fast, lightweight, zero-dependency command-line tool to calculate the total number of stars earned by any GitHub user or organization.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Features
|
|
41
|
+
|
|
42
|
+
- **Fast & Zero Dependencies**: Built entirely with Python's standard library. No external runtime dependencies.
|
|
43
|
+
- **Cross-Platform**: Full support for Linux, macOS, and Windows (with safe terminal encoding fallbacks).
|
|
44
|
+
- **Authentication & Rate-Limit Friendly**: Supports GitHub Personal Access Tokens (`--token` or `GITHUB_TOKEN` / `GH_TOKEN` environment variables) to bypass the unauthenticated 60 requests/hour limit.
|
|
45
|
+
- **Informative Output**: Clean tabular layout ranking repositories by stars.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
|
|
51
|
+
Install via pip:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install gitstar
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Or upgrade to the latest version:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
pip install --upgrade gitstar
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Usage
|
|
66
|
+
|
|
67
|
+
### Basic Usage
|
|
68
|
+
|
|
69
|
+
Find the total stars for any GitHub user or organization:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
gitstar <username>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Example:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
gitstar torvalds
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Limiting Results
|
|
82
|
+
|
|
83
|
+
Display only the top $N$ starred repositories:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
# Using positional shorthand:
|
|
87
|
+
gitstar torvalds 5
|
|
88
|
+
|
|
89
|
+
# Or using the -l / --limit flag:
|
|
90
|
+
gitstar torvalds --limit 5
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Output Example
|
|
94
|
+
|
|
95
|
+
```text
|
|
96
|
+
Total ⭐️ 234120
|
|
97
|
+
https://github.com/torvalds/linux ⭐️ 186400
|
|
98
|
+
https://github.com/torvalds/subsurface ⭐️ 3150
|
|
99
|
+
https://github.com/torvalds/pesconvert ⭐️ 285
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Authentication & Rate Limits
|
|
105
|
+
|
|
106
|
+
By default, unauthenticated GitHub API requests are limited to **60 requests per hour** per IP address.
|
|
107
|
+
|
|
108
|
+
To increase your limit to **5,000 requests per hour**, provide a GitHub Personal Access Token using either:
|
|
109
|
+
|
|
110
|
+
1. **Environment Variable** (recommended):
|
|
111
|
+
```bash
|
|
112
|
+
export GITHUB_TOKEN="ghp_your_token_here"
|
|
113
|
+
gitstar torvalds
|
|
114
|
+
```
|
|
115
|
+
*(On Windows PowerShell: `$env:GITHUB_TOKEN="ghp_your_token_here"`)*
|
|
116
|
+
|
|
117
|
+
2. **CLI Option**:
|
|
118
|
+
```bash
|
|
119
|
+
gitstar torvalds --token ghp_your_token_here
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## CLI Options Reference
|
|
125
|
+
|
|
126
|
+
```text
|
|
127
|
+
usage: gitstar [-h] [-l LIMIT] [-t TOKEN] [-v] [username] [limit]
|
|
128
|
+
|
|
129
|
+
Calculate the total stars earned by a GitHub user or organization.
|
|
130
|
+
|
|
131
|
+
positional arguments:
|
|
132
|
+
username GitHub username or organization
|
|
133
|
+
limit Number of top repositories to display (positional shorthand)
|
|
134
|
+
|
|
135
|
+
options:
|
|
136
|
+
-h, --help show this help message and exit
|
|
137
|
+
-l, --limit LIMIT Number of top repositories to display
|
|
138
|
+
-t, --token TOKEN GitHub Personal Access Token (defaults to GITHUB_TOKEN or GH_TOKEN)
|
|
139
|
+
-v, --version show program's version number and exit
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## License
|
|
145
|
+
|
|
146
|
+
This project is licensed under the [MIT License](LICENSE).
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
LICENSE
|
|
1
2
|
README.md
|
|
2
3
|
pyproject.toml
|
|
3
4
|
setup.py
|
|
4
5
|
gitstar/__init__.py
|
|
6
|
+
gitstar/__main__.py
|
|
5
7
|
gitstar/core.py
|
|
6
8
|
gitstar.egg-info/PKG-INFO
|
|
7
9
|
gitstar.egg-info/SOURCES.txt
|
|
8
10
|
gitstar.egg-info/dependency_links.txt
|
|
9
11
|
gitstar.egg-info/entry_points.txt
|
|
10
|
-
gitstar.egg-info/top_level.txt
|
|
12
|
+
gitstar.egg-info/top_level.txt
|
|
13
|
+
tests/test_cli.py
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "gitstar"
|
|
7
|
+
version = "1.1.0"
|
|
8
|
+
description = "Calculate the total stars earned by a GitHub user or organization"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
authors = [
|
|
12
|
+
{ name = "Imran Pollob", email = "imranpollob@gmail.com" }
|
|
13
|
+
]
|
|
14
|
+
requires-python = ">=3.8"
|
|
15
|
+
keywords = ["github", "stars", "stargazers", "cli", "github-api", "developer-tools"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 5 - Production/Stable",
|
|
18
|
+
"Environment :: Console",
|
|
19
|
+
"Intended Audience :: Developers",
|
|
20
|
+
"Operating System :: OS Independent",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3.8",
|
|
23
|
+
"Programming Language :: Python :: 3.9",
|
|
24
|
+
"Programming Language :: Python :: 3.10",
|
|
25
|
+
"Programming Language :: Python :: 3.11",
|
|
26
|
+
"Programming Language :: Python :: 3.12",
|
|
27
|
+
"Programming Language :: Python :: 3.13",
|
|
28
|
+
"Programming Language :: Python :: 3.14",
|
|
29
|
+
"Topic :: Software Development :: Version Control :: Git",
|
|
30
|
+
"Topic :: Utilities",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[project.urls]
|
|
34
|
+
Homepage = "https://github.com/imranpollob/github-star-calculator"
|
|
35
|
+
Repository = "https://github.com/imranpollob/github-star-calculator.git"
|
|
36
|
+
Issues = "https://github.com/imranpollob/github-star-calculator/issues"
|
|
37
|
+
|
|
38
|
+
[project.scripts]
|
|
39
|
+
gitstar = "gitstar.core:main"
|
|
40
|
+
|
|
41
|
+
[tool.setuptools.packages.find]
|
|
42
|
+
where = ["."]
|
|
43
|
+
include = ["gitstar*"]
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
[egg_info]
|
|
2
|
-
tag_build =
|
|
3
|
-
tag_date = 0
|
|
4
|
-
|
|
1
|
+
[egg_info]
|
|
2
|
+
tag_build =
|
|
3
|
+
tag_date = 0
|
|
4
|
+
|
gitstar-1.1.0/setup.py
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import io
|
|
2
|
+
import sys
|
|
3
|
+
import unittest
|
|
4
|
+
from unittest.mock import MagicMock, patch
|
|
5
|
+
from urllib.error import HTTPError, URLError
|
|
6
|
+
|
|
7
|
+
from gitstar.core import (
|
|
8
|
+
VERSION,
|
|
9
|
+
build_parser,
|
|
10
|
+
fetch,
|
|
11
|
+
get_star_symbol,
|
|
12
|
+
main,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class TestGitstarCLI(unittest.TestCase):
|
|
17
|
+
def test_parser_basic(self):
|
|
18
|
+
parser = build_parser()
|
|
19
|
+
args = parser.parse_args(["octocat"])
|
|
20
|
+
self.assertEqual(args.username, "octocat")
|
|
21
|
+
self.assertIsNone(args.pos_limit)
|
|
22
|
+
self.assertIsNone(args.limit)
|
|
23
|
+
self.assertIsNone(args.token)
|
|
24
|
+
|
|
25
|
+
def test_parser_positional_limit(self):
|
|
26
|
+
parser = build_parser()
|
|
27
|
+
args = parser.parse_args(["octocat", "5"])
|
|
28
|
+
self.assertEqual(args.username, "octocat")
|
|
29
|
+
self.assertEqual(args.pos_limit, 5)
|
|
30
|
+
|
|
31
|
+
def test_parser_flag_limit(self):
|
|
32
|
+
parser = build_parser()
|
|
33
|
+
args = parser.parse_args(["octocat", "-l", "10"])
|
|
34
|
+
self.assertEqual(args.username, "octocat")
|
|
35
|
+
self.assertEqual(args.limit, 10)
|
|
36
|
+
|
|
37
|
+
def test_parser_token(self):
|
|
38
|
+
parser = build_parser()
|
|
39
|
+
args = parser.parse_args(["octocat", "--token", "ghp_secret"])
|
|
40
|
+
self.assertEqual(args.token, "ghp_secret")
|
|
41
|
+
|
|
42
|
+
def test_get_star_symbol(self):
|
|
43
|
+
symbol = get_star_symbol()
|
|
44
|
+
self.assertIn(symbol, ("⭐️", "★", "*"))
|
|
45
|
+
|
|
46
|
+
def test_main_no_args_shows_help(self):
|
|
47
|
+
with patch("sys.stdout", new_callable=io.StringIO) as mock_stdout:
|
|
48
|
+
with self.assertRaises(SystemExit) as cm:
|
|
49
|
+
main([])
|
|
50
|
+
self.assertEqual(cm.exception.code, 0)
|
|
51
|
+
self.assertIn("Calculate the total stars", mock_stdout.getvalue())
|
|
52
|
+
|
|
53
|
+
@patch("gitstar.core.fetch")
|
|
54
|
+
def test_main_success(self, mock_fetch):
|
|
55
|
+
# Mock user info and repos
|
|
56
|
+
mock_fetch.side_effect = [
|
|
57
|
+
{"public_repos": 2},
|
|
58
|
+
[
|
|
59
|
+
{"html_url": "https://github.com/test/repo1", "stargazers_count": 25},
|
|
60
|
+
{"html_url": "https://github.com/test/repo2", "stargazers_count": 10},
|
|
61
|
+
],
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
with patch("sys.stdout", new_callable=io.StringIO) as mock_stdout:
|
|
65
|
+
main(["testuser"])
|
|
66
|
+
output = mock_stdout.getvalue()
|
|
67
|
+
self.assertIn("Total", output)
|
|
68
|
+
self.assertIn("35", output)
|
|
69
|
+
self.assertIn("https://github.com/test/repo1", output)
|
|
70
|
+
self.assertIn("25", output)
|
|
71
|
+
self.assertIn("https://github.com/test/repo2", output)
|
|
72
|
+
self.assertIn("10", output)
|
|
73
|
+
|
|
74
|
+
@patch("gitstar.core.fetch")
|
|
75
|
+
def test_main_with_limit(self, mock_fetch):
|
|
76
|
+
mock_fetch.side_effect = [
|
|
77
|
+
{"public_repos": 3},
|
|
78
|
+
[
|
|
79
|
+
{"html_url": "https://github.com/test/repo1", "stargazers_count": 100},
|
|
80
|
+
{"html_url": "https://github.com/test/repo2", "stargazers_count": 50},
|
|
81
|
+
{"html_url": "https://github.com/test/repo3", "stargazers_count": 10},
|
|
82
|
+
],
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
with patch("sys.stdout", new_callable=io.StringIO) as mock_stdout:
|
|
86
|
+
main(["testuser", "1"])
|
|
87
|
+
output = mock_stdout.getvalue()
|
|
88
|
+
self.assertIn("Total", output)
|
|
89
|
+
self.assertIn("160", output)
|
|
90
|
+
self.assertIn("https://github.com/test/repo1", output)
|
|
91
|
+
self.assertNotIn("https://github.com/test/repo2", output)
|
|
92
|
+
self.assertNotIn("https://github.com/test/repo3", output)
|
|
93
|
+
|
|
94
|
+
@patch("gitstar.core.fetch")
|
|
95
|
+
def test_main_no_public_repos(self, mock_fetch):
|
|
96
|
+
mock_fetch.return_value = {"public_repos": 0}
|
|
97
|
+
|
|
98
|
+
with patch("sys.stdout", new_callable=io.StringIO) as mock_stdout:
|
|
99
|
+
with self.assertRaises(SystemExit) as cm:
|
|
100
|
+
main(["emptyuser"])
|
|
101
|
+
self.assertEqual(cm.exception.code, 0)
|
|
102
|
+
self.assertIn("does not have any public repositories", mock_stdout.getvalue())
|
|
103
|
+
|
|
104
|
+
@patch("gitstar.core.urlopen")
|
|
105
|
+
def test_fetch_user_not_found(self, mock_urlopen):
|
|
106
|
+
err = HTTPError(
|
|
107
|
+
url="https://api.github.com/users/nonexistent",
|
|
108
|
+
code=404,
|
|
109
|
+
msg="Not Found",
|
|
110
|
+
hdrs={},
|
|
111
|
+
fp=io.BytesIO(b"{}"),
|
|
112
|
+
)
|
|
113
|
+
mock_urlopen.side_effect = err
|
|
114
|
+
|
|
115
|
+
with patch("sys.stderr", new_callable=io.StringIO) as mock_stderr:
|
|
116
|
+
with self.assertRaises(SystemExit) as cm:
|
|
117
|
+
fetch("users/nonexistent")
|
|
118
|
+
self.assertEqual(cm.exception.code, 1)
|
|
119
|
+
self.assertIn("not found", mock_stderr.getvalue())
|
|
120
|
+
|
|
121
|
+
@patch("gitstar.core.urlopen")
|
|
122
|
+
def test_fetch_rate_limit_exceeded(self, mock_urlopen):
|
|
123
|
+
headers = {
|
|
124
|
+
"x-ratelimit-remaining": "0",
|
|
125
|
+
"x-ratelimit-reset": "1700000000",
|
|
126
|
+
}
|
|
127
|
+
err = HTTPError(
|
|
128
|
+
url="https://api.github.com/users/ratelimited",
|
|
129
|
+
code=403,
|
|
130
|
+
msg="Forbidden",
|
|
131
|
+
hdrs=headers,
|
|
132
|
+
fp=io.BytesIO(b"{}"),
|
|
133
|
+
)
|
|
134
|
+
mock_urlopen.side_effect = err
|
|
135
|
+
|
|
136
|
+
with patch("sys.stderr", new_callable=io.StringIO) as mock_stderr:
|
|
137
|
+
with self.assertRaises(SystemExit) as cm:
|
|
138
|
+
fetch("users/ratelimited")
|
|
139
|
+
self.assertEqual(cm.exception.code, 1)
|
|
140
|
+
stderr_val = mock_stderr.getvalue()
|
|
141
|
+
self.assertIn("rate limit exceeded", stderr_val)
|
|
142
|
+
self.assertIn("Tip:", stderr_val)
|
|
143
|
+
|
|
144
|
+
@patch("gitstar.core.urlopen")
|
|
145
|
+
def test_fetch_network_error(self, mock_urlopen):
|
|
146
|
+
mock_urlopen.side_effect = URLError("DNS lookup failed")
|
|
147
|
+
|
|
148
|
+
with patch("sys.stderr", new_callable=io.StringIO) as mock_stderr:
|
|
149
|
+
with self.assertRaises(SystemExit) as cm:
|
|
150
|
+
fetch("users/test")
|
|
151
|
+
self.assertEqual(cm.exception.code, 1)
|
|
152
|
+
self.assertIn("Network connection failed", mock_stderr.getvalue())
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
if __name__ == "__main__":
|
|
156
|
+
unittest.main()
|
|
157
|
+
|
gitstar-1.0.0/PKG-INFO
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: gitstar
|
|
3
|
-
Version: 1.0.0
|
|
4
|
-
Summary: Find out the total star earned by a github user
|
|
5
|
-
Home-page: https://github.com/imranpollob/gitstar
|
|
6
|
-
Author: Imran Pollob
|
|
7
|
-
Author-email: imranpollob@gmail.com
|
|
8
|
-
Classifier: Programming Language :: Python :: 3
|
|
9
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
-
Classifier: Operating System :: OS Independent
|
|
11
|
-
Requires-Python: >=3.6
|
|
12
|
-
Description-Content-Type: text/markdown
|
|
13
|
-
Dynamic: author
|
|
14
|
-
Dynamic: author-email
|
|
15
|
-
Dynamic: classifier
|
|
16
|
-
Dynamic: description
|
|
17
|
-
Dynamic: description-content-type
|
|
18
|
-
Dynamic: home-page
|
|
19
|
-
Dynamic: requires-python
|
|
20
|
-
Dynamic: summary
|
|
21
|
-
|
|
22
|
-
# Gitstar
|
|
23
|
-
|
|
24
|
-
A command-line tool to calculate the total number of stars earned by a GitHub user.
|
|
25
|
-
|
|
26
|
-
## Installation
|
|
27
|
-
|
|
28
|
-
Install via pip:
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
pip install gitstar
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## Usage
|
|
35
|
-
|
|
36
|
-
Basic usage:
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
gitstar <username>
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
Limit the output to the top N repositories:
|
|
43
|
-
|
|
44
|
-
```bash
|
|
45
|
-
gitstar <username> <limit>
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
### Examples
|
|
49
|
-
|
|
50
|
-
Get total stars for user `pollmix`:
|
|
51
|
-
|
|
52
|
-
```bash
|
|
53
|
-
gitstar pollmix
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
Get total stars and list top 5 repositories:
|
|
57
|
-
|
|
58
|
-
```bash
|
|
59
|
-
gitstar pollmix 5
|
|
60
|
-
```
|
gitstar-1.0.0/README.md
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
# Gitstar
|
|
2
|
-
|
|
3
|
-
A command-line tool to calculate the total number of stars earned by a GitHub user.
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
Install via pip:
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
pip install gitstar
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
## Usage
|
|
14
|
-
|
|
15
|
-
Basic usage:
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
gitstar <username>
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
Limit the output to the top N repositories:
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
gitstar <username> <limit>
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
### Examples
|
|
28
|
-
|
|
29
|
-
Get total stars for user `pollmix`:
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
gitstar pollmix
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
Get total stars and list top 5 repositories:
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
gitstar pollmix 5
|
|
39
|
-
```
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
from .core import main
|
gitstar-1.0.0/gitstar/core.py
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
import math
|
|
3
|
-
import sys
|
|
4
|
-
from urllib.error import HTTPError
|
|
5
|
-
from urllib.request import Request, urlopen
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def fetch(params):
|
|
9
|
-
url = "https://api.github.com/"
|
|
10
|
-
httprequest = Request(url + params, headers={"Accept": "application/json"})
|
|
11
|
-
|
|
12
|
-
try:
|
|
13
|
-
response = urlopen(httprequest)
|
|
14
|
-
return json.loads(response.read().decode())
|
|
15
|
-
except HTTPError as e:
|
|
16
|
-
print(e.reason)
|
|
17
|
-
exit()
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
USAGE = """
|
|
21
|
-
Find out the total star earned by a github user.
|
|
22
|
-
|
|
23
|
-
Basic command:
|
|
24
|
-
gitstar theusername
|
|
25
|
-
|
|
26
|
-
Add printing limit:
|
|
27
|
-
gitstar theusername 5
|
|
28
|
-
"""
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def main():
|
|
32
|
-
# Debug print
|
|
33
|
-
# print(f"DEBUG: sys.argv = {sys.argv}", file=sys.stderr)
|
|
34
|
-
if len(sys.argv) == 1:
|
|
35
|
-
print(USAGE)
|
|
36
|
-
exit()
|
|
37
|
-
|
|
38
|
-
limit = None
|
|
39
|
-
|
|
40
|
-
if len(sys.argv) == 3:
|
|
41
|
-
try:
|
|
42
|
-
limit = int(sys.argv[2])
|
|
43
|
-
except ValueError:
|
|
44
|
-
print("Limit must be an integer")
|
|
45
|
-
exit()
|
|
46
|
-
|
|
47
|
-
username = sys.argv[1]
|
|
48
|
-
|
|
49
|
-
user = fetch(f"users/{username}")
|
|
50
|
-
|
|
51
|
-
if not user["public_repos"]:
|
|
52
|
-
print(f"{username} doesn't have any public repository.")
|
|
53
|
-
exit()
|
|
54
|
-
|
|
55
|
-
pages = math.ceil(user["public_repos"] / 100)
|
|
56
|
-
star = 0
|
|
57
|
-
highest_name = 0
|
|
58
|
-
repo_star_map = {}
|
|
59
|
-
|
|
60
|
-
for i in range(pages):
|
|
61
|
-
repos = fetch(f"users/{username}/repos?per_page=100&page={i+1}")
|
|
62
|
-
|
|
63
|
-
for repo in repos:
|
|
64
|
-
repo_star_map[repo["html_url"]] = repo["stargazers_count"]
|
|
65
|
-
star += repo["stargazers_count"]
|
|
66
|
-
highest_name = max(highest_name, len(repo["html_url"]))
|
|
67
|
-
|
|
68
|
-
print(f"Total ⭐️ {star}")
|
|
69
|
-
|
|
70
|
-
for repo, star in sorted(repo_star_map.items(), key=lambda x: x[1], reverse=True)[
|
|
71
|
-
:limit
|
|
72
|
-
]:
|
|
73
|
-
print(f"{repo:-<{highest_name}} ⭐️ {star}")
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
if __name__ == "__main__":
|
|
77
|
-
main()
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: gitstar
|
|
3
|
-
Version: 1.0.0
|
|
4
|
-
Summary: Find out the total star earned by a github user
|
|
5
|
-
Home-page: https://github.com/imranpollob/gitstar
|
|
6
|
-
Author: Imran Pollob
|
|
7
|
-
Author-email: imranpollob@gmail.com
|
|
8
|
-
Classifier: Programming Language :: Python :: 3
|
|
9
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
-
Classifier: Operating System :: OS Independent
|
|
11
|
-
Requires-Python: >=3.6
|
|
12
|
-
Description-Content-Type: text/markdown
|
|
13
|
-
Dynamic: author
|
|
14
|
-
Dynamic: author-email
|
|
15
|
-
Dynamic: classifier
|
|
16
|
-
Dynamic: description
|
|
17
|
-
Dynamic: description-content-type
|
|
18
|
-
Dynamic: home-page
|
|
19
|
-
Dynamic: requires-python
|
|
20
|
-
Dynamic: summary
|
|
21
|
-
|
|
22
|
-
# Gitstar
|
|
23
|
-
|
|
24
|
-
A command-line tool to calculate the total number of stars earned by a GitHub user.
|
|
25
|
-
|
|
26
|
-
## Installation
|
|
27
|
-
|
|
28
|
-
Install via pip:
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
pip install gitstar
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## Usage
|
|
35
|
-
|
|
36
|
-
Basic usage:
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
gitstar <username>
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
Limit the output to the top N repositories:
|
|
43
|
-
|
|
44
|
-
```bash
|
|
45
|
-
gitstar <username> <limit>
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
### Examples
|
|
49
|
-
|
|
50
|
-
Get total stars for user `pollmix`:
|
|
51
|
-
|
|
52
|
-
```bash
|
|
53
|
-
gitstar pollmix
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
Get total stars and list top 5 repositories:
|
|
57
|
-
|
|
58
|
-
```bash
|
|
59
|
-
gitstar pollmix 5
|
|
60
|
-
```
|
gitstar-1.0.0/pyproject.toml
DELETED
gitstar-1.0.0/setup.py
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
from setuptools import setup, find_packages
|
|
2
|
-
|
|
3
|
-
with open("README.md", "r", encoding="utf-8") as fh:
|
|
4
|
-
long_description = fh.read()
|
|
5
|
-
|
|
6
|
-
setup(
|
|
7
|
-
name="gitstar",
|
|
8
|
-
version="1.0.0",
|
|
9
|
-
author="Imran Pollob",
|
|
10
|
-
author_email="imranpollob@gmail.com",
|
|
11
|
-
description="Find out the total star earned by a github user",
|
|
12
|
-
long_description=long_description,
|
|
13
|
-
long_description_content_type="text/markdown",
|
|
14
|
-
url="https://github.com/imranpollob/gitstar",
|
|
15
|
-
packages=find_packages(),
|
|
16
|
-
classifiers=[
|
|
17
|
-
"Programming Language :: Python :: 3",
|
|
18
|
-
"License :: OSI Approved :: MIT License",
|
|
19
|
-
"Operating System :: OS Independent",
|
|
20
|
-
],
|
|
21
|
-
python_requires=">=3.6",
|
|
22
|
-
entry_points={
|
|
23
|
-
"console_scripts": [
|
|
24
|
-
"gitstar=gitstar.core:main",
|
|
25
|
-
],
|
|
26
|
-
},
|
|
27
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|