Skip to content

Commit 7d0598e

Browse files
authored
Merge pull request #112 from casperdcl/svg
2 parents 8e39c3d + 82ae28c commit 7d0598e

File tree

6 files changed

+82
-32
lines changed

6 files changed

+82
-32
lines changed

README.rst

Lines changed: 43 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,18 @@ Pretty-print ``git`` repository collaborators sorted by contributions.
99

1010
|DOI-URI| |LICENCE| |OpenHub-Status| |Sponsor-Casper|
1111

12+
.. code::
13+
14+
https://git-fame.cdcl.ml/gh/{owner}/{repo}
15+
16+
|Contributions|
17+
18+
.. code:: sh
19+
20+
git fame --cost hour,month --loc ins
21+
1222
.. code:: sh
1323
14-
~$ git fame --cost hour,month --loc ins
1524
Processing: 100%|██████████████████████████| 1/1 [00:00<00:00, 2.16repo/s]
1625
Total commits: 1775
1726
Total ctimes: 2770
@@ -116,7 +125,7 @@ Tab completion
116125

117126
Optionally, systems with ``bash-completion`` can install tab completion
118127
support. The
119-
`git-fame_completion.bash <https://raw.githubusercontent.com/casperdcl/git-fame/main/git-fame_completion.bash>`__
128+
`git-fame_completion.bash <https://raw.githubusercontent.com/casperdcl/git-fame/main/git-fame_completion.bash>`_
120129
file needs to be copied to an appropriate folder.
121130

122131
On Ubuntu, the procedure would be:
@@ -137,7 +146,7 @@ followed by a terminal restart.
137146
Changelog
138147
---------
139148

140-
The list of all changes is available on the Releases page: |GitHub-Status|.
149+
The list of all changes is available on the Releases page: |GitHub-Status|
141150

142151

143152
Usage
@@ -165,12 +174,14 @@ It is also possible to run from within a python shell or script.
165174
>>> import gitfame
166175
>>> gitfame.main(['--sort=commits', '-wt', '/path/to/my/repo'])
167176
177+
Finally, there is a live server for public GitHub repositories at `git-fame.cdcl.ml/gh/{owner}/{repo} <https://git-fame.cdcl.ml/docs>`_.
178+
179+
The ``rendered by git-fame.cdcl.ml`` watermark is removed for sponsors of `casperdcl <https://github.com/casperdcl>`_: |Sponsor-Casper|
180+
168181

169182
Documentation
170183
-------------
171184

172-
|Py-Versions| |README-Hits|
173-
174185
.. code::
175186
176187
Usage:
@@ -186,6 +197,7 @@ Documentation
186197
-v, --version Print module version and exit.
187198
--branch=<b> Branch or tag [default: HEAD] up to which to check.
188199
--sort=<key> [default: loc]|commits|files|hours|months.
200+
--min=<val> Minimum value (of `--sort` key) to show [default: 0:int].
189201
--loc=<type> surv(iving)|ins(ertions)|del(etions)
190202
What `loc` represents. Use 'ins,del' to count both.
191203
defaults to 'surviving' unless `--cost` is specified.
@@ -224,7 +236,7 @@ Documentation
224236
--ignore-revs-file=<f> Ignore revisions listed in the given file
225237
(requires `--loc=surviving`).
226238
--format=<format> Table format
227-
[default: pipe]|md|markdown|yaml|yml|json|csv|tsv|tabulate.
239+
svg|[default: pipe]|md|markdown|yaml|yml|json|csv|tsv|tabulate.
228240
May require `git-fame[<format>]`, e.g. `pip install git-fame[yaml]`.
229241
Any `tabulate.tabulate_formats` is also accepted.
230242
--manpath=<path> Directory in which to install git-fame man pages.
@@ -257,14 +269,30 @@ In such cases, ``--excl`` may need to be significantly extended.
257269
On the plus side, it is faster to compute ``ins`` and ``del`` compared to
258270
``surv``.
259271

272+
260273
Examples
261274
--------
262275

276+
Badges
277+
~~~~~~
278+
279+
An SVG image for inclusion in README files and websites:
280+
281+
.. code:: sh
282+
283+
git fame -wMC --format svg --min 1 > docs/authors.svg
284+
285+
Which can also be dynamically created for public GitHub repositories:
286+
287+
.. code:: md
288+
289+
![markdown-image](https://git-fame.cdcl.ml/gh/{owner}/{repo}?min=1)
290+
263291
CODEOWNERS
264292
~~~~~~~~~~
265293

266294
Generating
267-
`CODEOWNERS <https://help.github.com/en/articles/about-code-owners>`__:
295+
`CODEOWNERS <https://help.github.com/en/articles/about-code-owners>`_:
268296

269297
.. code:: sh
270298
@@ -292,7 +320,7 @@ Generating
292320
Zenodo config
293321
~~~~~~~~~~~~~
294322

295-
Generating `.zenodo.json <https://developers.zenodo.org/#deposit-metadata>`__:
323+
Generating `.zenodo.json <https://developers.zenodo.org/#deposit-metadata>`_:
296324

297325
.. code:: sh
298326
@@ -301,14 +329,18 @@ Generating `.zenodo.json <https://developers.zenodo.org/#deposit-metadata>`__:
301329
| sed -r -e 's/(\{"name")/\n \1/g' -e 's/:/: /g' \
302330
> .zenodo.json
303331
332+
304333
Contributions
305334
-------------
306335

307336
|GitHub-Commits| |GitHub-Issues| |GitHub-PRs| |OpenHub-Status|
308337

309-
All source code is hosted on `GitHub <https://github.com/casperdcl/git-fame>`__.
338+
All source code is hosted on `GitHub <https://github.com/casperdcl/git-fame>`_.
310339
Contributions are welcome.
311340

341+
|Contributions|
342+
343+
The ``rendered by git-fame.cdcl.ml`` watermark is removed for sponsors of `casperdcl <https://github.com/casperdcl>`_: |Sponsor-Casper|
312344

313345
LICENCE
314346
-------
@@ -317,16 +349,6 @@ Open Source (OSI approved): |LICENCE|
317349

318350
Citation information: |DOI-URI|
319351

320-
321-
Authors
322-
-------
323-
324-
|OpenHub-Status|
325-
326-
- Casper da Costa-Luis (`casperdcl <https://github.com/casperdcl>`__ |Sponsor-Casper|)
327-
328-
We are grateful for all |GitHub-Contributions|.
329-
330352
|README-Hits|
331353

332354
.. |Build-Status| image:: https://img.shields.io/github/actions/workflow/status/casperdcl/git-fame/test.yml?branch=main&label=git-fame&logo=GitHub
@@ -349,8 +371,8 @@ We are grateful for all |GitHub-Contributions|.
349371
:target: https://github.com/casperdcl/git-fame/issues
350372
.. |GitHub-PRs| image:: https://img.shields.io/github/issues-pr-closed/casperdcl/git-fame.svg?logo=github
351373
:target: https://github.com/casperdcl/git-fame/pulls
352-
.. |GitHub-Contributions| image:: https://img.shields.io/github/contributors/casperdcl/git-fame.svg?logo=github
353-
:target: https://github.com/casperdcl/git-fame/graphs/contributors
374+
.. |Contributions| image:: https://git-fame.cdcl.ml/gh/casperdcl/git-fame
375+
:target: https://git-fame.cdcl.ml/gh/casperdcl/git-fame
354376
.. |GitHub-Updated| image:: https://img.shields.io/github/last-commit/casperdcl/git-fame?label=pushed&logo=github
355377
:target: https://github.com/casperdcl/git-fame/pulse
356378
.. |Sponsor-Casper| image:: https://img.shields.io/badge/sponsor-FOSS-dc10ff.svg?logo=Contactless%20Payment

git-fame_completion.bash

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,13 @@ _git_fame()
1616
COMPREPLY=($(compgen -W 'months cocomo hours commits' -- ${cur}))
1717
;;
1818
--loc)
19-
COMPREPLY=($(compgen -W 'surviving insertions deletions' -- ${cur}))
19+
COMPREPLY=($(compgen -W 'surviving insertions deletions ins,del' -- ${cur}))
2020
;;
2121
--format)
22-
COMPREPLY=($(compgen -W 'pipe markdown yaml json csv tsv tabulate' -- ${cur}))
22+
COMPREPLY=($(compgen -W 'pipe markdown yaml json csv tsv svg tabulate' -- ${cur}))
23+
;;
24+
--show)
25+
COMPREPLY=($(compgen -W 'name email name,email' -- ${cur}))
2326
;;
2427
--log)
2528
COMPREPLY=($(compgen -W 'FATAL CRITICAL ERROR WARNING INFO DEBUG NOTSET' -- ${cur}))
@@ -33,12 +36,12 @@ _git_fame()
3336
--manpath)
3437
COMPREPLY=($(compgen -d -- "${cur}"))
3538
;;
36-
--incl|--excl|--since|--ignore-rev|--until)
39+
--incl|--excl|--since|--ignore-rev|--until|--min)
3740
COMPREPLY=( )
3841
;;
3942
*)
4043
if [ ${COMP_WORDS[1]} == fame ]; then
41-
COMPREPLY=($(compgen -dW '-h --help -v --version --cost --branch --since --until --sort --loc --incl --excl -R --recurse -n --no-regex -s --silent-progress --warn-binary -t --bytype -w --ignore-whitespace -e --show-email --enum -M -C --ignore-rev --ignore-revs-file --format --manpath --log' -- ${cur}))
44+
COMPREPLY=($(compgen -dW '-h --help -v --version --cost --branch --since --until --sort --loc --incl --excl -R --recurse -n --no-regex -s --silent-progress --warn-binary -t --bytype -w --ignore-whitespace --show -e --show-email --enum -M -C --ignore-rev --ignore-revs-file --format --manpath --log' -- ${cur}))
4245
fi
4346
;;
4447
esac

gitfame/_gitfame.py

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
-v, --version Print module version and exit.
1313
--branch=<b> Branch or tag [default: HEAD] up to which to check.
1414
--sort=<key> [default: loc]|commits|files|hours|months.
15+
--min=<val> Minimum value (of `--sort` key) to show [default: 0:int].
1516
--loc=<type> surv(iving)|ins(ertions)|del(etions)
1617
What `loc` represents. Use 'ins,del' to count both.
1718
defaults to 'surviving' unless `--cost` is specified.
@@ -50,7 +51,7 @@
5051
--ignore-revs-file=<f> Ignore revisions listed in the given file
5152
(requires `--loc=surviving`).
5253
--format=<format> Table format
53-
[default: pipe]|md|markdown|yaml|yml|json|csv|tsv|tabulate.
54+
svg|[default: pipe]|md|markdown|yaml|yml|json|csv|tsv|tabulate.
5455
May require `git-fame[<format>]`, e.g. `pip install git-fame[yaml]`.
5556
Any `tabulate.tabulate_formats` is also accepted.
5657
--manpath=<path> Directory in which to install git-fame man pages.
@@ -123,7 +124,7 @@ def hours(dates, maxCommitDiffInSec=120 * 60, firstCommitAdditionInMinutes=120):
123124

124125

125126
def tabulate(auth_stats, stats_tot, sort='loc', bytype=False, backend='md', cost=None,
126-
row_nums=False, width=TERM_WIDTH):
127+
row_nums=False, min_sort_val=0, width=TERM_WIDTH):
127128
"""
128129
backends : [default: md]|yaml|json|csv|tsv|tabulate|
129130
`in tabulate.tabulate_formats`
@@ -154,6 +155,8 @@ def tabulate(auth_stats, stats_tot, sort='loc', bytype=False, backend='md', cost
154155

155156
for i, j in (("commits", "coms"), ("files", "fils"), ("hours", "hrs"), ("months", "mths")):
156157
sort = sort.replace(i, j)
158+
if min_sort_val:
159+
tab = [i for i in tab if i[COL_NAMES.index(sort)] >= min_sort_val]
157160
tab.sort(key=lambda i: i[COL_NAMES.index(sort)], reverse=True)
158161
if row_nums:
159162
tab = [[str(i)] + j for i, j in enumerate(tab, 1)]
@@ -163,6 +166,9 @@ def tabulate(auth_stats, stats_tot, sort='loc', bytype=False, backend='md', cost
163166

164167
if (backend := backend.lower()) in ("tabulate", "md", "markdown"):
165168
backend = "pipe"
169+
svg = backend == 'svg'
170+
if svg:
171+
backend = 'rounded_outline'
166172

167173
if backend in ('yaml', 'yml', 'json', 'csv', 'tsv'):
168174
tab = [i[:-1] + [float(pc.strip()) for pc in i[-1].split('/')] for i in tab]
@@ -194,13 +200,25 @@ def tabulate(auth_stats, stats_tot, sort='loc', bytype=False, backend='md', cost
194200
raise RuntimeError("Should be unreachable")
195201
else:
196202
import tabulate as tabber
203+
197204
if backend not in tabber.tabulate_formats:
198205
raise ValueError(f"Unknown backend:{backend}")
199206
log.debug("backend:tabulate:%s", backend)
200207
COL_LENS = [max(len(Str(i[j])) for i in [COL_NAMES] + tab) for j in range(len(COL_NAMES))]
201208
COL_LENS[0] = min(width - sum(COL_LENS[1:]) - len(COL_LENS) * 3 - 4, COL_LENS[0])
202209
tab = [[i[0][:COL_LENS[0]]] + i[1:] for i in tab]
203-
return totals + tabber.tabulate(tab, COL_NAMES, tablefmt=backend, floatfmt='.0f')
210+
table = tabber.tabulate(tab, COL_NAMES, tablefmt=backend, floatfmt='.0f')
211+
if svg:
212+
rows = table.split('\n')
213+
return ('<svg xmlns="http://www.w3.org/2000/svg"'
214+
f' width="{len(rows[0]) / 2 + 1}em" height="{len(rows)}em">'
215+
'<rect x="0" y="0" width="100%" height="100%"'
216+
' fill="white" fill-opacity="0.5" rx="5"/>'
217+
'<text x="0" y="-0.5em" font-size="15"'
218+
' font-family="monospace" style="white-space: pre">' +
219+
''.join(f'<tspan x="0" dy="1em">{row}</tspan>'
220+
for row in rows) + '</text></svg>')
221+
return totals + table
204222

205223
# from ._utils import tighten
206224
# return totals + tighten(tabber(...), max_width=TERM_WIDTH)
@@ -467,7 +485,8 @@ def run(args):
467485
# log.debug(extns)
468486

469487
print_unicode(
470-
tabulate(auth_stats, stats_tot, args.sort, args.bytype, args.format, cost, args.enum))
488+
tabulate(auth_stats, stats_tot, args.sort, args.bytype, args.format, cost, args.enum,
489+
args.min))
471490

472491

473492
def get_main_parser():

gitfame/git-fame.1

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ Branch or tag [default: HEAD] up to which to check.
4141
\-\-sort=\f[I]key\f[R]
4242
[default: loc]|commits|files|hours|months.
4343
.TP
44+
\-\-min=\f[I]val\f[R]
45+
Minimum value (of \f[CR]\-\-sort\f[R] key) to show [default: 0:int].
46+
.TP
4447
\-\-loc=\f[I]type\f[R]
4548
surv(iving)|ins(ertions)|del(etions) What \f[CR]loc\f[R] represents.
4649
Use `ins,del' to count both.
@@ -118,7 +121,8 @@ Ignore revisions listed in the given file (requires
118121
\f[CR]\-\-loc=surviving\f[R]).
119122
.TP
120123
\-\-format=\f[I]format\f[R]
121-
Table format [default: pipe]|md|markdown|yaml|yml|json|csv|tsv|tabulate.
124+
Table format svg|[default:
125+
pipe]|md|markdown|yaml|yml|json|csv|tsv|tabulate.
122126
May require \f[CR]git\-fame[<format>]\f[R],
123127
e.g.\ \f[CR]pip install git\-fame[yaml]\f[R].
124128
Any \f[CR]tabulate.tabulate_formats\f[R] is also accepted.

snapcraft.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ description: https://github.com/casperdcl/git-fame
44
adopt-info: git-fame
55
grade: stable
66
confinement: strict
7-
base: core22
7+
base: core24
88
license: MPL-2.0
99
parts:
1010
git-fame:

tests/tests_gitfame.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ def test_tabulate():
4040
| Casper da Costa-Luis | 538 | 35 | 10 | 87.8/ 100/71.4 |
4141
| Not Committed Yet | 75 | 0 | 4 | 12.2/ 0.0/28.6 |"""))
4242

43+
assert "Not Committed Yet" not in _gitfame.tabulate(auth_stats, stats_tot, min_sort_val=76)
44+
4345

4446
def test_tabulate_cost():
4547
"""Test cost estimates"""
@@ -160,7 +162,7 @@ def test_tabulate_unknown():
160162
[['--sort', 'commits'], ['--no-regex'], ['--no-regex', '--incl', 'setup.py,README.rst'],
161163
['--excl', r'.*\.py'], ['--loc', 'ins,del'], ['--cost', 'hour'], ['--cost', 'month'],
162164
['--cost', 'month', '--excl', r'.*\.py'], ['-e'], ['-w'], ['-M'], ['-C'], ['-t'],
163-
['--show=name,email']])
165+
['--show=name,email'], ['--format=csv'], ['--format=svg']])
164166
def test_options(params):
165167
"""Test command line options"""
166168
main(['-s'] + params)

0 commit comments

Comments
 (0)