init github pages

This commit is contained in:
Lukas Mestan
2019-12-16 13:22:07 +01:00
parent 85b7fb1cdf
commit c2d3d798b2
29 changed files with 852 additions and 1868 deletions

1
.gitignore vendored
View File

@@ -7,3 +7,4 @@
.Spotlight*
.Trash*
**/*~
/nbproject/*

View File

@@ -1,3 +0,0 @@
Lukas Mestan <lukas.mestan@gmail.com> Lukáš Mešťan <arzzen@users.noreply.github.com>
Lukas Mestan <lukas.mestan@gmail.com> arzzen

View File

@@ -1,32 +0,0 @@
language: generic
sudo: required
addons:
apt:
packages:
- libcurl4-openssl-dev
- libelf-dev
- libdw-dev
- cmake
install:
- git rev-parse HEAD
script: make test
after_success: |
wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz &&
tar xzf master.tar.gz &&
cd kcov-master &&
mkdir build &&
cd build &&
cmake .. &&
make &&
sudo make install &&
cd ../.. &&
rm -rf kcov-master &&
mkdir -p coverage &&
kcov coverage git-quick-stats suggestReviewers && bash <(curl -s https://codecov.io/bash) -cF suggestReviewers &&
kcov coverage git-quick-stats detailedGitStats && bash <(curl -s https://codecov.io/bash) -cF detailedGitStats &&
kcov coverage git-quick-stats commitsPerDay && bash <(curl -s https://codecov.io/bash) -cF commitsPerDay

View File

View File

@@ -1,46 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at lukas.mestan@googlemail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

View File

@@ -1,27 +0,0 @@
FROM alpine
# Copy sources
COPY . /app
# Install required packages & build git-quick-stats
RUN apk add --no-cache bash git make ncurses util-linux \
&& cd /app \
&& make install \
&& rm -rf /app \
&& apk del --no-cache make \
&& mkdir -p /usr/local/bin \
&& echo -en "#!/bin/bash\nset -e\n[[ \"\${1::1}\" == '-' ]] && set -- /usr/bin/git quick-stats \"\$@\"\nexec \"\$@\"" \
> /usr/local/bin/docker-entrypoint \
&& chmod +x /usr/local/bin/docker-entrypoint
# Declare all variables usables by git-quick-stats
ENV _GIT_SINCE= \
_GIT_UNTIL= \
_GIT_LIMIT= \
_GIT_PATHSPEC= \
_MENU_THEME=default \
TERM=xterm-256color
WORKDIR /git
ENTRYPOINT [ "/usr/local/bin/docker-entrypoint" ]
CMD [ "/usr/bin/git", "quick-stats" ]

21
LICENSE
View File

@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2019 Lukáš Mešťan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,43 +0,0 @@
PREFIX ?= /usr/local
_INSTDIR ?= $(DESTDIR)$(PREFIX)
BINDIR ?= $(_INSTDIR)/bin
MANDIR ?= $(_INSTDIR)/share/man
TASK_DONE = echo -e "\n✓ $@ done\n"
.PHONY: test
all:
@echo "Usage:"
@echo " make install"
@echo " make reinstall"
@echo " make uninstall"
@echo " make test"
help:
$(MAKE) all
@$(TASK_DONE)
install:
install -d -m 0755 $(BINDIR)
install -m 0755 git-quick-stats $(BINDIR)/git-quick-stats
$(MAKE) man
@$(TASK_DONE)
uninstall:
rm -f $(BINDIR)/git-quick-stats
rm -f $(MANDIR)/man1/git-quick-stats.1
@$(TASK_DONE)
reinstall:
@curl -sO https://raw.githubusercontent.com/arzzen/git-quick-stats/master/git-quick-stats
@curl -sO https://raw.githubusercontent.com/arzzen/git-quick-stats/master/git-quick-stats.1
$(MAKE) install
@$(TASK_DONE)
man:
install -d -m 0755 $(MANDIR)/man1/
install -m 0644 git-quick-stats.1 $(MANDIR)/man1/
test:
tests/commands_test.sh
@$(TASK_DONE)

BIN
assets/GitHub-Mark.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

552
assets/base.css Normal file
View File

@@ -0,0 +1,552 @@
/*! normalize.css v3.0.2 | MIT License | git.io/normalize */
/**
* 1. Set default font family to sans-serif.
* 2. Prevent iOS text size adjust after orientation change, without disabling
* user zoom.
*/
html {
font-family: sans-serif; /* 1 */
-ms-text-size-adjust: 100%; /* 2 */
-webkit-text-size-adjust: 100%; /* 2 */
}
/**
* Remove default margin.
*/
body {
margin: 0;
}
/* HTML5 display definitions
========================================================================== */
/**
* Correct `block` display not defined for any HTML5 element in IE 8/9.
* Correct `block` display not defined for `details` or `summary` in IE 10/11
* and Firefox.
* Correct `block` display not defined for `main` in IE 11.
*/
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
main,
menu,
nav,
section,
summary {
display: block;
}
/**
* 1. Correct `inline-block` display not defined in IE 8/9.
* 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
*/
audio,
canvas,
progress,
video {
display: inline-block; /* 1 */
vertical-align: baseline; /* 2 */
}
/**
* Prevent modern browsers from displaying `audio` without controls.
* Remove excess height in iOS 5 devices.
*/
audio:not([controls]) {
display: none;
height: 0;
}
/**
* Address `[hidden]` styling not present in IE 8/9/10.
* Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
*/
[hidden],
template {
display: none;
}
/* Links
========================================================================== */
/**
* Remove the gray background color from active links in IE 10.
*/
a {
background-color: transparent;
}
/**
* Improve readability when focused and also mouse hovered in all browsers.
*/
a:active,
a:hover {
outline: 0;
}
/* Text-level semantics
========================================================================== */
/**
* Address styling not present in IE 8/9/10/11, Safari, and Chrome.
*/
abbr[title] {
border-bottom: 1px dotted;
}
/**
* Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
*/
b,
strong {
font-weight: bold;
}
/**
* Address styling not present in Safari and Chrome.
*/
dfn {
font-style: italic;
}
/**
* Address variable `h1` font-size and margin within `section` and `article`
* contexts in Firefox 4+, Safari, and Chrome.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/**
* Address styling not present in IE 8/9.
*/
mark {
background: #ff0;
color: #000;
}
/**
* Address inconsistent and variable font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` affecting `line-height` in all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sup {
top: -0.5em;
}
sub {
bottom: -0.25em;
}
/* Embedded content
========================================================================== */
/**
* Remove border when inside `a` element in IE 8/9/10.
*/
img {
border: 0;
}
/**
* Correct overflow not hidden in IE 9/10/11.
*/
svg:not(:root) {
overflow: hidden;
}
/* Grouping content
========================================================================== */
/**
* Address margin not present in IE 8/9 and Safari.
*/
figure {
margin: 1em 40px;
}
/**
* Address differences between Firefox and other browsers.
*/
hr {
-moz-box-sizing: content-box;
box-sizing: content-box;
height: 0;
}
/**
* Contain overflow in all browsers.
*/
pre {
overflow: auto;
}
/**
* Address odd `em`-unit font size rendering in all browsers.
*/
code,
kbd,
pre,
samp {
font-family: monospace, monospace;
font-size: 1em;
}
/* Forms
========================================================================== */
/**
* Known limitation: by default, Chrome and Safari on OS X allow very limited
* styling of `select`, unless a `border` property is set.
*/
/**
* 1. Correct color not being inherited.
* Known issue: affects color of disabled elements.
* 2. Correct font properties not being inherited.
* 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
*/
button,
input,
optgroup,
select,
textarea {
color: inherit; /* 1 */
font: inherit; /* 2 */
margin: 0; /* 3 */
}
/**
* Address `overflow` set to `hidden` in IE 8/9/10/11.
*/
button {
overflow: visible;
}
/**
* Address inconsistent `text-transform` inheritance for `button` and `select`.
* All other form control elements do not inherit `text-transform` values.
* Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
* Correct `select` style inheritance in Firefox.
*/
button,
select {
text-transform: none;
}
/**
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
* and `video` controls.
* 2. Correct inability to style clickable `input` types in iOS.
* 3. Improve usability and consistency of cursor style between image-type
* `input` and others.
*/
button,
html input[type="button"], /* 1 */
input[type="reset"],
input[type="submit"] {
-webkit-appearance: button; /* 2 */
cursor: pointer; /* 3 */
}
/**
* Re-set default cursor for disabled elements.
*/
button[disabled],
html input[disabled] {
cursor: default;
}
/**
* Remove inner padding and border in Firefox 4+.
*/
button::-moz-focus-inner,
input::-moz-focus-inner {
border: 0;
padding: 0;
}
/**
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
* the UA stylesheet.
*/
input {
line-height: normal;
}
/**
* It's recommended that you don't attempt to style these elements.
* Firefox's implementation doesn't respect box-sizing, padding, or width.
*
* 1. Address box sizing set to `content-box` in IE 8/9/10.
* 2. Remove excess padding in IE 8/9/10.
*/
input[type="checkbox"],
input[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* Fix the cursor style for Chrome's increment/decrement buttons. For certain
* `font-size` values of the `input`, it causes the cursor style of the
* decrement button to change from `default` to `text`.
*/
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
height: auto;
}
/**
* 1. Address `appearance` set to `searchfield` in Safari and Chrome.
* 2. Address `box-sizing` set to `border-box` in Safari and Chrome
* (include `-moz` to future-proof).
*/
input[type="search"] {
-webkit-appearance: textfield; /* 1 */
-moz-box-sizing: content-box;
-webkit-box-sizing: content-box; /* 2 */
box-sizing: content-box;
}
/**
* Remove inner padding and search cancel button in Safari and Chrome on OS X.
* Safari (but not Chrome) clips the cancel button when the search input has
* padding (and `textfield` appearance).
*/
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* Define consistent border, margin, and padding.
*/
fieldset {
border: 1px solid #c0c0c0;
margin: 0 2px;
padding: 0.35em 0.625em 0.75em;
}
/**
* 1. Correct `color` not being inherited in IE 8/9/10/11.
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
*/
legend {
border: 0; /* 1 */
padding: 0; /* 2 */
}
/**
* Remove default vertical scrollbar in IE 8/9/10/11.
*/
textarea {
overflow: auto;
}
/**
* Don't inherit the `font-weight` (applied by a rule above).
* NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
*/
optgroup {
font-weight: bold;
}
/* Tables
========================================================================== */
/**
* Remove most spacing between table cells.
*/
table {
border-collapse: collapse;
border-spacing: 0;
}
td,
th {
padding: 0;
}
.container {
position: relative;
width: 100%;
max-width: 960px;
margin: 0 auto;
padding: 0 20px;
box-sizing: border-box; }
.column,
.columns {
width: 100%;
float: left;
box-sizing: border-box; }
@media (max-width: 1000px) {
.container {
margin: 30px;
width: 90%;
padding: 0;
}
.row .column, .row .columns {
float: none;
width: 100% !important;
margin: 0 0 30px 0;
}
}
/* For devices larger than 400px */
@media (min-width: 400px) {
.container {
width: 85%;
padding: 0; }
}
/* For devices larger than 550px */
@media (min-width: 550px) {
.container {
width: 80%; }
.column,
.columns {
margin-left: 4%; }
.column:first-child,
.columns:first-child {
margin-left: 0; }
.one.column,
.one.columns { width: 4.66666666667%; }
.two.columns { width: 13.3333333333%; }
.three.columns { width: 22%; }
.four.columns { width: 30.6666666667%; }
.five.columns { width: 39.3333333333%; }
.six.columns { width: 48%; }
.seven.columns { width: 56.6666666667%; }
.eight.columns { width: 65.3333333333%; }
.nine.columns { width: 74.0%; }
.ten.columns { width: 82.6666666667%; }
.eleven.columns { width: 91.3333333333%; }
.twelve.columns { width: 100%; margin-left: 0; }
.one-third.column { width: 30.6666666667%; }
.two-thirds.column { width: 65.3333333333%; }
.one-half.column { width: 48%; }
/* Offsets */
.offset-by-one.column,
.offset-by-one.columns { margin-left: 8.66666666667%; }
.offset-by-two.column,
.offset-by-two.columns { margin-left: 17.3333333333%; }
.offset-by-three.column,
.offset-by-three.columns { margin-left: 26%; }
.offset-by-four.column,
.offset-by-four.columns { margin-left: 34.6666666667%; }
.offset-by-five.column,
.offset-by-five.columns { margin-left: 43.3333333333%; }
.offset-by-six.column,
.offset-by-six.columns { margin-left: 52%; }
.offset-by-seven.column,
.offset-by-seven.columns { margin-left: 60.6666666667%; }
.offset-by-eight.column,
.offset-by-eight.columns { margin-left: 69.3333333333%; }
.offset-by-nine.column,
.offset-by-nine.columns { margin-left: 78.0%; }
.offset-by-ten.column,
.offset-by-ten.columns { margin-left: 86.6666666667%; }
.offset-by-eleven.column,
.offset-by-eleven.columns { margin-left: 95.3333333333%; }
.offset-by-one-third.column,
.offset-by-one-third.columns { margin-left: 34.6666666667%; }
.offset-by-two-thirds.column,
.offset-by-two-thirds.columns { margin-left: 69.3333333333%; }
.offset-by-one-half.column,
.offset-by-one-half.columns { margin-left: 52%; }
}
.container:after,
.row:after,
.u-cf {
content: "";
display: table;
clear: both; }
@font-face {
font-family: 'Inter';
font-display: auto;
font-style: normal;
font-weight: 400;
src: url("https://rsms.me/inter/font-files/Inter-Regular.woff2") format("woff2"),
url("https://rsms.me/inter/font-files/Inter-Regular.woff") format("woff");
}
@font-face {
font-family: 'Inter';
font-display: auto;
font-style: normal;
font-weight: 500;
src: url("https://rsms.me/inter/font-files/Inter-Medium.woff2") format("woff2"),
url("https://rsms.me/inter/font-files/Inter-Medium.woff") format("woff");
}

1
assets/icon-color.svg Normal file
View File

@@ -0,0 +1 @@
<svg data-v-29081953="" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300"><!----><defs data-v-29081953=""><!----></defs><rect data-v-29081953="" fill="#FFF7EC" x="0" y="0" width="300px" height="300px" class="logo-background-square"></rect><!----><defs data-v-29081953=""><linearGradient data-v-29081953="" gradientTransform="rotate(25)" id="b4bd9a4d-3879-4954-8296-66d4749af5c2" x1="0%" y1="0%" x2="100%" y2="0%"><stop data-v-29081953="" offset="0%" stop-color="#FF4B03" stop-opacity="1"></stop><stop data-v-29081953="" offset="100%" stop-color="#FCFF65" stop-opacity="1"></stop></linearGradient></defs><g data-v-29081953="" id="47723a31-5e2c-4996-a5a1-600c4efe3066" fill="url(#b4bd9a4d-3879-4954-8296-66d4749af5c2)" stroke="none" transform="matrix(2.749999761581421,0,0,2.749999761581421,12.500002622604121,12.500015735624721)"><path d="M83.338 49.999c-2.464 0-4.591 1.351-5.745 3.333H50v6.67h27.593c1.154 1.982 3.281 3.33 5.745 3.33a6.667 6.667 0 0 0 0-13.333zM83.338 23.332c-2.464 0-4.591 1.351-5.745 3.334H50v6.665h27.593c1.154 1.986 3.281 3.334 5.745 3.334A6.664 6.664 0 0 0 90 30a6.668 6.668 0 0 0-6.662-6.668zM23.333 53.332h19.999v6.67H23.333zM23.333 66.666h19.999v6.668H23.333zM23.333 40h19.999v6.668H23.333zM23.333 26.666h19.999v6.665H23.333zM63.336 63.332c-2.464 0-4.588 1.354-5.745 3.334H50v6.668h7.591c1.157 1.986 3.281 3.334 5.745 3.334A6.666 6.666 0 0 0 70.002 70a6.67 6.67 0 0 0-6.666-6.668zM70.004 36.665c-2.464 0-4.591 1.351-5.745 3.334H50v6.668h14.259c1.154 1.983 3.281 3.331 5.745 3.331a6.662 6.662 0 0 0 6.663-6.665 6.669 6.669 0 0 0-6.663-6.668z"></path><path d="M56.668 19.998A6.666 6.666 0 0 0 50 13.332H16.665A6.666 6.666 0 0 0 10 19.998V80a6.665 6.665 0 0 0 6.665 6.668H50A6.666 6.666 0 0 0 56.668 80H16.665V19.998h40.003z"></path></g><!----></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

1
assets/icon.svg Normal file
View File

@@ -0,0 +1 @@
<svg data-v-d3f97b9e="" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 65.45217292517833 60"><!----><!----><!----><!----><g data-v-d3f97b9e="" id="8575c8ef-d4bf-4990-a029-ca75ee806ebf" transform="matrix(0.8181520700454712,0,0,0.8181520700454712,-8.18152141571045,-10.90760326385498)" stroke="none" fill="black"><path d="M83.338 49.999c-2.464 0-4.591 1.351-5.745 3.333H50v6.67h27.593c1.154 1.982 3.281 3.33 5.745 3.33a6.667 6.667 0 0 0 0-13.333zM83.338 23.332c-2.464 0-4.591 1.351-5.745 3.334H50v6.665h27.593c1.154 1.986 3.281 3.334 5.745 3.334A6.664 6.664 0 0 0 90 30a6.668 6.668 0 0 0-6.662-6.668zM23.333 53.332h19.999v6.67H23.333zM23.333 66.666h19.999v6.668H23.333zM23.333 40h19.999v6.668H23.333zM23.333 26.666h19.999v6.665H23.333zM63.336 63.332c-2.464 0-4.588 1.354-5.745 3.334H50v6.668h7.591c1.157 1.986 3.281 3.334 5.745 3.334A6.666 6.666 0 0 0 70.002 70a6.67 6.67 0 0 0-6.666-6.668zM70.004 36.665c-2.464 0-4.591 1.351-5.745 3.334H50v6.668h14.259c1.154 1.983 3.281 3.331 5.745 3.331a6.662 6.662 0 0 0 6.663-6.665 6.669 6.669 0 0 0-6.663-6.668z"></path><path d="M56.668 19.998A6.666 6.666 0 0 0 50 13.332H16.665A6.666 6.666 0 0 0 10 19.998V80a6.665 6.665 0 0 0 6.665 6.668H50A6.666 6.666 0 0 0 56.668 80H16.665V19.998h40.003z"></path></g><!----></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

1
assets/logo-color.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.2 KiB

1
assets/logo.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.9 KiB

130
assets/style.css Normal file
View File

@@ -0,0 +1,130 @@
body {
font-family: "Inter", sans-serif;
font-size: 16px;
font-weight: 400;
line-height: 28px;
}
.container {
max-width: 1200px;
}
.header {
margin: 60px 0 90px 0;
text-align: left;
}
nav {
text-align: right;
}
nav a {
margin: 0 0 0 30px;
}
nav .github img {
max-width: 32px;
height: auto;
vertical-align: middle;
display: inline-block;
}
.features .columns {
margin-bottom: 30px;
}
.download a {
margin: 0 0 0 15px;
}
.footer {
padding-top: 30px;
margin: 30px 0;
border-top: 1px solid #ddd;
color: #777;
}
.button {
background: #7f2aff;
display: inline-block;
text-align: center;
font-weight: 500;
font-size: 1.3em;
color: #fff;
border-radius: 100px;
padding: 15px 30px;
min-width: 200px;
}
.button:hover {
background: #000;
color: #fff;
}
.notice {
background: #fafafa;
border-left: 4px solid #ddd;
color: #666;
padding: 5px 15px;
}
h1,
h2,
h3,
h4,
h5 {
font-weight: 400;
/*color: #7f2aff;*/
margin: 15px 0 15px 0;
}
h1 {
font-weight: 500;
font-size: 2.5em;
line-height: 1.5em;
}
h2 {
font-size: 2em;
line-height: 1.4em;
}
h3 {
font-size: 1.6em;
line-height: 1.6em;
color: #888;
}
section {
margin-bottom: 100px;
}
code {
color: #c63370;
}
a {
color: #c68933;
font-weight: bold;
text-decoration: none;
}
a:hover {
color: inherit;
}
img {
max-width: 100%;
}
.center {
text-align: center;
}
.logo {
padding-top: 3px;
}
@media screen and (max-width: 490px) {
.header {
margin: 0;
}
nav {
text-align: left;
}
nav a {
margin: 0 10px 0 0;
}
.container {
width: auto;
padding: 0;
margin: 30px;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

View File

@@ -1,25 +0,0 @@
Contributing
============
Want to contribute? Great! First, read this page.
# Code reviews
All submissions, including submissions by project members, require review. We
use Github pull requests for this purpose.
# Some tips for good pull requests:
* Use our code
When in doubt, try to stay true to the existing code of the project.
* Write a descriptive commit message. What problem are you solving and what
are the consequences? Where and what did you test? Some good tips:
[here](http://robots.thoughtbot.com/5-useful-tips-for-a-better-commit-message)
and [here](https://www.kernel.org/doc/Documentation/SubmittingPatches).
* If your PR consists of multiple commits which are successive improvements /
fixes to your first commit, consider squashing them into a single commit
(`git rebase -i`) such that your PR is a single commit on top of the current
HEAD. This make reviewing the code so much easier, and our history more
readable.
# Formatting
This documentation is written using standard [markdown syntax](https://help.github.com/articles/markdown-basics/). Please submit your changes using the same syntax.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,509 +0,0 @@
/*!
* Start Bootstrap - Creative Bootstrap Theme (http://startbootstrap.com)
* Code licensed under the Apache License v2.0.
* For details, see http://www.apache.org/licenses/LICENSE-2.0.
*/
html,
body {
width: 100%;
height: 100%;
}
body {
font-family: Merriweather,'Helvetica Neue',Arial,sans-serif;
}
hr {
max-width: 50px;
border-color: #f05f40;
border-width: 3px;
}
hr.light {
border-color: #fff;
}
a {
color: #f05f40;
-webkit-transition: all .35s;
-moz-transition: all .35s;
transition: all .35s;
}
a:hover,
a:focus {
color: #eb3812;
}
#about a {
color: rgba(52, 52, 52, .7);
}
#about a:hover,
#about a:focus {
color: rgb(52, 52, 52);
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-family: 'Open Sans','Helvetica Neue',Arial,sans-serif;
}
p {
margin-bottom: 20px;
font-size: 16px;
line-height: 1.5;
}
.bg-primary {
background-color: #f05f40;
}
.bg-dark {
color: #fff;
background-color: #222;
}
.text-faded {
color: rgba(255,255,255,.7);
}
section {
padding: 100px 0;
}
aside {
padding: 50px 0;
}
.no-padding {
padding: 0;
}
.navbar-default {
border-color: rgba(34,34,34,.05);
font-family: 'Open Sans','Helvetica Neue',Arial,sans-serif;
background-color: #fff;
-webkit-transition: all .35s;
-moz-transition: all .35s;
transition: all .35s;
}
.navbar-default .navbar-header .navbar-brand {
text-transform: uppercase;
font-family: 'Open Sans','Helvetica Neue',Arial,sans-serif;
font-weight: 700;
color: #2d8888;
}
.navbar-default .navbar-header .navbar-brand:hover,
.navbar-default .navbar-header .navbar-brand:focus {
color: #eb3812;
}
.navbar-default .nav > li>a,
.navbar-default .nav>li>a:focus {
text-transform: uppercase;
font-size: 13px;
font-weight: 700;
color: #222;
}
.navbar-default .nav > li>a:hover,
.navbar-default .nav>li>a:focus:hover {
color: #f05f40;
}
.navbar-default .nav > li.active>a,
.navbar-default .nav>li.active>a:focus {
color: #f05f40!important;
background-color: transparent;
}
.navbar-default .nav > li.active>a:hover,
.navbar-default .nav>li.active>a:focus:hover {
background-color: transparent;
}
@media(min-width:768px) {
.navbar-default {
border-color: rgba(255,255,255,.3);
background-color: transparent;
}
.navbar-default .navbar-header .navbar-brand {
color: rgba(255,255,255,.7);
}
.navbar-default .navbar-header .navbar-brand:hover,
.navbar-default .navbar-header .navbar-brand:focus {
color: #fff;
}
.navbar-default .nav > li>a,
.navbar-default .nav>li>a:focus {
color: rgba(255,255,255,.7);
}
.navbar-default .nav > li>a:hover,
.navbar-default .nav>li>a:focus:hover {
color: #fff;
}
.navbar-default.affix {
border-color: rgba(34,34,34,.05);
background-color: #fff;
}
.navbar-default.affix .navbar-header .navbar-brand {
font-size: 14px;
color: #f05f40;
}
.navbar-default.affix .navbar-header .navbar-brand:hover,
.navbar-default.affix .navbar-header .navbar-brand:focus {
color: #eb3812;
}
.navbar-default.affix .nav > li>a,
.navbar-default.affix .nav>li>a:focus {
color: #222;
}
.navbar-default.affix .nav > li>a:hover,
.navbar-default.affix .nav>li>a:focus:hover {
color: #f05f40;
}
}
header {
position: relative;
width: 100%;
min-height: auto;
text-align: center;
color: #fff;
background-color: #2f2d2f;
/*background-color: #2c3333;*/
/*background-image: url(../img/header.jpg);*/
/*background-position: center;*/
/*-webkit-background-size: cover;*/
/*-moz-background-size: cover;*/
/*background-size: cover;*/
/*-o-background-size: cover;*/
}
header .header-content {
position: relative;
width: 100%;
padding: 100px 15px;
text-align: center;
}
header .header-content .header-content-inner h1 {
margin-top: 0;
margin-bottom: 0;
/* text-transform: uppercase; */
font-weight: 700;
font-size: 120px;
}
header .header-content .header-content-inner hr {
margin: 30px auto;
}
header .header-content .header-content-inner p {
margin-bottom: 50px;
font-size: 16px;
font-weight: 300;
color: rgba(255,255,255,.7);
}
@media(min-width:768px) {
header {
min-height: 100%;
}
header .header-content {
position: absolute;
top: 50%;
padding: 0 50px;
-webkit-transform: translateY(-50%);
-ms-transform: translateY(-50%);
transform: translateY(-50%);
}
header .header-content .header-content-inner {
margin-right: auto;
margin-left: auto;
max-width: 1000px;
}
header .header-content .header-content-inner p {
margin-right: auto;
margin-left: auto;
max-width: 80%;
font-size: 18px;
}
}
.section-heading {
margin-top: 0;
}
.service-box {
margin: 50px auto 0;
max-width: 400px;
}
@media(min-width:992px) {
.service-box {
margin: 20px auto 0;
}
}
.service-box p {
margin-bottom: 0;
}
.portfolio-box {
display: block;
position: relative;
margin: 0 auto;
max-width: 650px;
}
.portfolio-box .portfolio-box-caption {
display: block;
position: absolute;
bottom: 0;
width: 100%;
height: 100%;
text-align: center;
color: #fff;
opacity: 0;
background: rgba(240,95,64,.9);
-webkit-transition: all .35s;
-moz-transition: all .35s;
transition: all .35s;
}
.portfolio-box .portfolio-box-caption .portfolio-box-caption-content {
position: absolute;
top: 50%;
width: 100%;
text-align: center;
transform: translateY(-50%);
}
.portfolio-box .portfolio-box-caption .portfolio-box-caption-content .project-category,
.portfolio-box .portfolio-box-caption .portfolio-box-caption-content .project-name {
padding: 0 15px;
font-family: 'Open Sans','Helvetica Neue',Arial,sans-serif;
}
.portfolio-box .portfolio-box-caption .portfolio-box-caption-content .project-category {
text-transform: uppercase;
font-size: 14px;
font-weight: 600;
}
.portfolio-box .portfolio-box-caption .portfolio-box-caption-content .project-name {
font-size: 18px;
}
.portfolio-box:hover .portfolio-box-caption {
opacity: 1;
}
@media(min-width:768px) {
.portfolio-box .portfolio-box-caption .portfolio-box-caption-content .project-category {
font-size: 16px;
}
.portfolio-box .portfolio-box-caption .portfolio-box-caption-content .project-name {
font-size: 22px;
}
}
.call-to-action h2 {
margin: 0 auto 20px;
}
.text-primary {
color: #f05f40;
}
.no-gutter > [class*=col-] {
padding-right: 0;
padding-left: 0;
}
.btn-default {
border-color: #fff;
color: #222;
background-color: #fff;
-webkit-transition: all .35s;
-moz-transition: all .35s;
transition: all .35s;
}
.btn-default:hover,
.btn-default:focus,
.btn-default.focus,
.btn-default:active,
.btn-default.active,
.open > .dropdown-toggle.btn-default {
border-color: #ededed;
color: #222;
background-color: #f2f2f2;
}
.btn-default:active,
.btn-default.active,
.open > .dropdown-toggle.btn-default {
background-image: none;
}
.btn-default.disabled,
.btn-default[disabled],
fieldset[disabled] .btn-default,
.btn-default.disabled:hover,
.btn-default[disabled]:hover,
fieldset[disabled] .btn-default:hover,
.btn-default.disabled:focus,
.btn-default[disabled]:focus,
fieldset[disabled] .btn-default:focus,
.btn-default.disabled.focus,
.btn-default[disabled].focus,
fieldset[disabled] .btn-default.focus,
.btn-default.disabled:active,
.btn-default[disabled]:active,
fieldset[disabled] .btn-default:active,
.btn-default.disabled.active,
.btn-default[disabled].active,
fieldset[disabled] .btn-default.active {
border-color: #fff;
background-color: #fff;
}
.btn-default .badge {
color: #fff;
background-color: #222;
}
.btn-primary {
border-color: #f05f40;
color: #fff;
background-color: #2d8888;
-webkit-transition: all .35s;
-moz-transition: all .35s;
transition: all .35s;
}
.btn-primary:hover,
.btn-primary:focus,
.btn-primary.focus,
.btn-primary:active,
.btn-primary.active,
.open > .dropdown-toggle.btn-primary {
color: #fff;
background-color: #68a9a9;
}
.btn-primary:active,
.btn-primary.active,
.open > .dropdown-toggle.btn-primary {
background-image: none;
}
.btn-primary.disabled,
.btn-primary[disabled],
fieldset[disabled] .btn-primary,
.btn-primary.disabled:hover,
.btn-primary[disabled]:hover,
fieldset[disabled] .btn-primary:hover,
.btn-primary.disabled:focus,
.btn-primary[disabled]:focus,
fieldset[disabled] .btn-primary:focus,
.btn-primary.disabled.focus,
.btn-primary[disabled].focus,
fieldset[disabled] .btn-primary.focus,
.btn-primary.disabled:active,
.btn-primary[disabled]:active,
fieldset[disabled] .btn-primary:active,
.btn-primary.disabled.active,
.btn-primary[disabled].active,
fieldset[disabled] .btn-primary.active {
border-color: #f05f40;
background-color: #f05f40;
}
.btn-primary .badge {
color: #f05f40;
background-color: #fff;
}
.btn {
border: 0;
border-radius: 300px;
text-transform: uppercase;
font-family: 'Open Sans','Helvetica Neue',Arial,sans-serif;
font-weight: 700;
font-size: 1.4em;
}
.btn-xl {
padding: 15px 30px;
}
::-moz-selection {
text-shadow: none;
color: #fff;
background: #222;
}
::selection {
text-shadow: none;
color: #fff;
background: #222;
}
img::selection {
color: #fff;
background: 0 0;
}
img::-moz-selection {
color: #fff;
background: 0 0;
}
body {
webkit-tap-highlight-color: #222;
}
#map {
height: 300px;
overflow: visible;
position: relative;
}
.subtitle {
color: #b1b1b1;
}
.logo {
width: 50%;
padding-bottom: 5px;
}
.screencap {
width: 80%;
padding-top: 20px;
padding-bottom: 30px;
}

View File

@@ -1,81 +0,0 @@
/*!
* The code below adds the modal functionality of the Freelancer Bootstrap Theme
* and was originally part of this theme.
*
*
* Start Bootstrap - Freelancer Bootstrap Theme (http://startbootstrap.com)
* Code licensed under the Apache License v2.0.
* For details, see http://www.apache.org/licenses/LICENSE-2.0.
*/
body {
overflow-x: hidden;
}
.img-centered {
margin: 0 auto;
}
.portfolio-modal .modal-content {
padding: 100px 0;
min-height: 100%;
border: 0;
border-radius: 0;
text-align: center;
background-clip: border-box;
-webkit-box-shadow: none;
box-shadow: none;
}
.portfolio-modal .modal-content h2 {
margin: 0;
font-size: 3em;
}
.portfolio-modal .modal-content img {
margin-bottom: 30px;
}
.portfolio-modal .modal-content .item-details {
margin: 30px 0;
}
.portfolio-modal .close-modal {
position: absolute;
top: 25px;
right: 25px;
width: 75px;
height: 75px;
background-color: transparent;
cursor: pointer;
}
.portfolio-modal .close-modal:hover {
opacity: .3;
}
.portfolio-modal .close-modal .lr {
z-index: 1051;
width: 1px;
height: 75px;
margin-left: 35px;
background-color: #2c3e50;
-webkit-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg);
}
.portfolio-modal .close-modal .lr .rl {
z-index: 1052;
width: 1px;
height: 75px;
background-color: #2c3e50;
-webkit-transform: rotate(90deg);
-ms-transform: rotate(90deg);
transform: rotate(90deg);
}
.portfolio-modal .modal-backdrop {
display: none;
opacity: 0;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -1,35 +0,0 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="author" content="Lukas Mestan">
<meta name="description" content="Commandline GIT statistics">
<title>git quick stats</title>
<link rel="shortcut icon" href="favicon.ico?v=1" type="image/x-icon">
<link rel="stylesheet" href="css/bootstrap.min.css" type="text/css">
<link href="https://fonts.googleapis.com/css?family=Montserrat" rel="stylesheet">
<link rel="stylesheet" href="css/animate.min.css" type="text/css">
<link rel="stylesheet" href="css/creative.css" type="text/css">
<link rel="stylesheet" href="css/modals.css" type="text/css">
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
<meta http-equiv="refresh" content="0;url=https://lukasmestan.com/git-quick-stats/">
</head>
<body id="page-top">
<header>
<div class="header-content">
<div class="header-content-inner">
<h1>git quick stats</h1>
<h3 class="subtitle"> simple and efficient way to access various statistics in git repository</h3>
<img class="screencap" src="bg.png" \>
<br>
<a href="https://github.com/arzzen/git-quick-stats" class="btn btn-primary btn-xl page-scroll">download</a>
</div>
</div>
</header>
</body>
</html>

View File

@@ -1,9 +0,0 @@
#### Expected behavior and actual behavior.
#### Steps to reproduce the problem.
#### Specifications like the version of the project, operating system, or hardware.

View File

@@ -1,668 +0,0 @@
#!/usr/bin/env bash
#
# Simple and efficient way to access various statistics in a git repository
################################################################################
# GLOBALS AND SHELL OPTIONS
set -o nounset
set -o errexit
_since=${_GIT_SINCE:-}
[[ -n "${_since}" ]] && _since="--since=$_since"
_until=${_GIT_UNTIL:-}
[[ -n "${_until}" ]] && _until="--until=$_until"
_pathspec=${_GIT_PATHSPEC:-}
[[ -n "${_pathspec}" ]] && _pathspec="-- $_pathspec"
_limit=${_GIT_LIMIT:-}
if [[ -n "${_limit}" ]];
then _limit=$_limit
else
_limit=10
fi
# Default menu theme
# Set the legacy theme by typing "export _MENU_THEME=legacy"
_theme="${_MENU_THEME:=default}"
################################################################################
# DESC: Checks to make sure the user has the appropriate utilities installed
# ARGS: None
# OUTS: None
################################################################################
function checkUtils() {
local -r msg="not found. Please make sure this is installed and in PATH."
declare -ar utils=("awk" "basename" "cat" "column" "echo" "git" "grep" "head"
"seq" "sort" "tput" "tr" "uniq" "wc")
for u in "${utils[@]}"
do
command -v "$u" >/dev/null 2>&1 || { echo >&2 "$u ${msg}"; exit 1; }
done
}
################################################################################
# DESC: Help information printed to stdout during non-interactive mode
# ARGS: None
# OUTS: None
################################################################################
function usage() {
local -r program=$(basename "$0")
echo "
NAME
${program} - Simple and efficient way to access various stats in a git repo
SYNOPSIS
For non-interactive mode: ${program} [OPTIONS]
For interactive mode: ${program}
DESCRIPTION
Any git repository contains tons of information about commits, contributors,
and files. Extracting this information is not always trivial, mostly because
of a gadzillion options to a gadzillion git commands.
This program allows you to see detailed information about a git repository.
OPTIONS
-r, --suggest-reviewers
show the best people to contact to review code
-T, --detailed-git-stats
give a detailed list of git stats
-R, --git-stats-by-branch
see detailed list of git stats by branch
-d, --commits-per-day
displays a list of commits per day
-m, --commits-by-month
displays a list of commits per month
-w, --commits-by-weekday
displays a list of commits per weekday
-o, --commits-by-hour
displays a list of commits per hour
-A, --commits-by-author-by-hour
displays a list of commits per hour by author
-a, --commits-per-author
displays a list of commits per author
-S, --my-daily-stats
see your current daily stats
-C, --contributors
see a list of everyone who contributed to the repo
-b, --branch-tree
show an ASCII graph of the git repo branch history
-D, --branches-by-date
show branches by date
-c, --changelogs
see changelogs
-L, --changelogs-by-author
see changelogs by author
-j, --json-output
save git log as a JSON formatted file to a specified area
-h, -?, --help
display this help text in the terminal
ADDITIONAL USAGE
You can set _GIT_SINCE and _GIT_UNTIL to limit the git time log
ex: export _GIT_SINCE=\"2017-01-20\"
You can set _GIT_LIMIT for limited output log
ex: export _GIT_LIMIT=20
You can exclude directories or files from the stats by using pathspec
ex: export _GIT_PATHSPEC=':!pattern'
You can set _MENU_THEME to display the legacy color scheme
ex: export _MENU_THEME=legacy"
}
################################################################################
# DESC: Displays the interactive menu and saves the user supplied option
# ARGS: None
# OUTS: $opt: Option selected by the user based on menu choice
################################################################################
function showMenu() {
local -r normal=$(tput sgr0)
local -r cyan=$(tput setaf 6)
local -r bold=$(tput bold)
local -r red=$(tput setaf 1)
local -r yellow=$(tput setaf 3)
local -r white=$(tput setaf 7)
local titles=""
local text=""
local nums=""
local help_txt=""
local exit_txt=""
# Adjustable color menu option
if [[ "${_theme}" == "legacy" ]]; then
titles="${bold}${red}" && readonly titles
text="${normal}${cyan}" && readonly text
nums="${bold}${yellow}" && readonly nums
help_txt="${normal}${yellow}" && readonly help_txt
exit_txt="${bold}${red}" && readonly exit_txt
else
titles="${bold}${cyan}" && readonly titles
text="${normal}${white}" && readonly text
nums="${normal}${bold}${white}" && readonly nums
help_txt="${normal}${cyan}" && readonly help_txt
exit_txt="${bold}${cyan}" && readonly exit_txt
fi
echo -e "\n${titles} Generate:${normal}"
echo -e "${nums} 1)${text} Contribution stats (by author)"
echo -e "${nums} 2)${text} Contribution stats (by author) on a specific branch"
echo -e "${nums} 3)${text} Git changelogs (last $_limit days)"
echo -e "${nums} 4)${text} Git changelogs by author"
echo -e "${nums} 5)${text} My daily status"
echo -e "${nums} 6)${text} Save git log output in JSON format"
echo -e "\n${titles} List:"
echo -e "${nums} 7)${text} Branch tree view (last $_limit)"
echo -e "${nums} 8)${text} All branches (sorted by most recent commit)"
echo -e "${nums} 9)${text} All contributors (sorted by name)"
echo -e "${nums} 10)${text} Git commits per author"
echo -e "${nums} 11)${text} Git commits per date"
echo -e "${nums} 12)${text} Git commits per month"
echo -e "${nums} 13)${text} Git commits per weekday"
echo -e "${nums} 14)${text} Git commits per hour"
echo -e "${nums} 15)${text} Git commits by author per hour"
echo -e "\n${titles} Suggest:"
echo -e "${nums} 16)${text} Code reviewers (based on git history)"
echo -e "\n${help_txt}Please enter a menu option or ${exit_txt}press Enter to exit."
echo -n "${text}> ${normal}"
read -r opt
}
################################################################################
# DESC: Prints a formatted message of the selected option by the user to stdout
# ARGS: $* (required): String to print (usually provided by other functions)
# OUTS: None
################################################################################
function optionPicked() {
local -r bold=$(tput bold)
local -r red=$(tput setaf 1)
local -r reset=$(tput sgr0)
local msg=${*:-"${reset}Error: No message passed"}
echo -e "${bold}${red}${msg}${reset}\n"
}
################################################################################
# DESC: Shows detailed contribution stats per author by parsing every commit in
# the repo and outputting their contribution stats
# ARGS: $branch (optional): Users can specify an alternative branch instead of
# the current default one
# OUTS: None
################################################################################
function detailedGitStats() {
local is_branch_existing=false
local branch="${1:-}"
local _branch=""
# Check if requesting for a specific branch
if [[ -n "${branch}" ]]; then
# Check if branch exist
if [[ $(git show-ref refs/heads/"${branch}") ]] ; then
is_branch_existing=true
_branch="${branch}"
else
is_branch_existing=false
_branch=""
fi
fi
# Prompt message
if [[ "${is_branch_existing}" && -n "${_branch}" ]]; then
optionPicked "Contribution stats (by author) on ${_branch} branch:"
elif [[ -n "${branch}" && -z "${_branch}" ]]; then
optionPicked "Branch ${branch} does not exist.\nContribution stats (by author) on the current branch:"
else
optionPicked "Contribution stats (by author) on the current branch:"
fi
git -c log.showSignature=false log ${_branch} --use-mailmap --no-merges --numstat \
--pretty="format:commit %H%nAuthor: %aN <%aE>%nDate: %ad%n%n%w(0,4,4)%B%n" \
$_since $_until $_pathspec | LC_ALL=C awk '
function printStats(author) {
printf "\t%s:\n", author
if(more["total"] > 0) {
printf "\t insertions: %d (%.0f%%)\n", more[author], \
(more[author] / more["total"] * 100)
}
if(less["total"] > 0) {
printf "\t deletions: %d (%.0f%%)\n", less[author], \
(less[author] / less["total"] * 100)
}
if(file["total"] > 0) {
printf "\t files: %d (%.0f%%)\n", file[author], \
(file[author] / file["total"] * 100)
}
if(commits["total"] > 0) {
printf "\t commits: %d (%.0f%%)\n", commits[author], \
(commits[author] / commits["total"] * 100)
}
if (first[author] != "") {
printf "\t lines changed: %s\n", more[author] + less[author]
printf "\t first commit: %s\n", first[author]
printf "\t last commit: %s\n", last[author]
}
printf "\n"
}
/^Author:/ {
$1 = ""
author = $0
commits[author] += 1
commits["total"] += 1
}
/^Date:/ {
$1="";
first[author] = substr($0, 2)
if(last[author] == "" ) { last[author] = first[author] }
}
/^[0-9]/ {
more[author] += $1
less[author] += $2
file[author] += 1
more["total"] += $1
less["total"] += $2
file["total"] += 1
}
END {
for (author in commits) {
if (author != "total") {
printStats(author)
}
}
printStats("total")
}'
}
################################################################################
# DESC: Displays the authors in order of total contribution to the repo
# ARGS: None
# OUTS: None
################################################################################
function suggestReviewers() {
optionPicked "Suggested code reviewers (based on git history):"
git -c log.showSignature=false log --use-mailmap --no-merges $_since $_until \
--pretty=%aN $_pathspec | head -n 100 | sort | uniq -c | sort -nr | LC_ALL=C awk '
{ args[NR] = $0; }
END {
for (i = 1; i <= NR; ++i) {
printf "%s\n", args[i]
}
}' | column -t -s,
}
################################################################################
# DESC: Saves the git log output in a JSON format
# ARGS: $json_path (required): Path to where the file is saved
# OUTS: A JSON formatted file
################################################################################
function jsonOutput() {
optionPicked "Output log saved to file at: ${json_path:?}/output.json"
git -c log.showSignature=false log --use-mailmap --no-merges $_since $_until \
--pretty=format:'{%n "commit": "%H",%n "abbreviated_commit": "%h",%n "tree": "%T",%n "abbreviated_tree": "%t",%n "parent": "%P",%n "abbreviated_parent": "%p",%n "refs": "%D",%n "encoding": "%e",%n "subject": "%s",%n "sanitized_subject_line": "%f",%n "body": "%b",%n "commit_notes": "%N",%n "author": {%n "name": "%aN",%n "email": "%aE",%n "date": "%aD"%n },%n "commiter": {%n "name": "%cN",%n "email": "%cE",%n "date": "%cD"%n }%n},' \
| sed "$ s/,$//" \
| sed ':a;N;$!ba;s/\r\n\([^{]\)/\\n\1/g' \
| awk 'BEGIN { print("[") } { print($0) } END { print("]") }' \
> "${json_path:?}"/output.json
}
################################################################################
# DESC: Displays a horizontal bar graph based on total commits per month
# ARGS: None
# OUTS: None
################################################################################
function commitsByMonth() {
optionPicked "Git commits by month:"
echo -e "\tmonth\tsum"
for i in Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
do
echo -en "\t$i\t"
git -c log.showSignature=false shortlog -n --no-merges --format='%ad %s' \
$_since $_until | grep " $i " | wc -l
done | awk '{
count[$1] = $2
total += $2
}
END{
for (month in count) {
s="|";
if (total > 0) {
percent = ((count[month] / total) * 100) / 1.25;
for (i = 1; i <= percent; ++i) {
s=s"█"
}
printf( "\t%s\t%-0s\t%s\n", month, count[month], s );
}
}
}' | LC_TIME="en_EN.UTF-8" sort -M
}
################################################################################
# DESC: Displays a horizontal bar graph based on total commits per weekday
# ARGS: None
# OUTS: None
################################################################################
function commitsByWeekday() {
optionPicked "Git commits by weekday:"
echo -e "\tday\tsum"
for i in Mon Tue Wed Thu Fri Sat Sun
do
echo -en "\t$i\t"
git -c log.showSignature=false shortlog -n --no-merges --format='%ad %s' \
$_since $_until | grep "$i " | wc -l
done | awk '{
}
NR == FNR {
count[$1] = $2;
total += $2;
next
}
END{
for (day in count) {
s="|";
if (total > 0) {
percent = ((count[day] / total) * 100) / 1.25;
for (i = 1; i <= percent; ++i) {
s=s"█"
}
printf( "\t%s\t%-0s\t%s\n", day, count[day], s );
}
}
}' | sort -k 2 -n -r
}
################################################################################
# DESC: Displays a horizontal bar graph based on total commits per hour
# ARGS: $author (optional): Can focus on a single author. Default is all authors
# OUTS: None
################################################################################
function commitsByHour() {
local author="${1:-}"
local _author=""
if [[ -z "${author}" ]]; then
optionPicked "Git commits by hour:"
_author="--author=**"
else
optionPicked "Git commits by hour for author '${author}':"
_author="--author=${author}"
fi
echo -e "\thour\tsum"
for i in $(seq -w 0 23)
do
echo -ne "\t$i\t"
git -c log.showSignature=false shortlog -n --no-merges --format='%ad %s' \
"${_author}" $_since $_until | grep ' '$i: | wc -l
done | awk '{
count[$1] = $2
total += $2
}
END{
for (hour in count) {
s="|";
if (total > 0) {
percent = ((count[hour] / total) * 100) / 1.25;
for (i = 1; i <= percent; ++i) {
s=s"█"
}
printf( "\t%s\t%-0s\t%s\n", hour, count[hour], s );
}
}
}' | sort
}
################################################################################
# DESC: Shows the number of commits that were committed per date recorded in the
# repo's log history
# ARGS: None
# OUTS: None
################################################################################
function commitsPerDay() {
optionPicked "Git commits per date:";
git -c log.showSignature=false log --use-mailmap --no-merges $_since $_until \
--date=short --format='%ad' $_pathspec | sort | uniq -c
}
################################################################################
# DESC: Displays the number of commits and percentage contributed to the repo
# per author and sorts them by contribution percentage
# ARGS: None
# OUTS: None
################################################################################
function commitsPerAuthor() {
optionPicked "Git commits per author:"
local authorCommits=$(git -c log.showSignature=false log --use-mailmap --no-merges \
$_since $_until | grep -i Author: | cut -c9-)
local coAuthorCommits=$(git -c log.showSignature=false log --use-mailmap --no-merges \
$_since $_until | grep -i Co-Authored-by: | cut -c21-)
if [[ -z "${coAuthorCommits}" ]]
then
allCommits="${authorCommits}"
else
allCommits="${authorCommits}\n${coAuthorCommits}"
fi
echo -e "${allCommits}" | awk '
{ $NF=""; author[NR] = $0 }
END {
for(i in author) {
sum[author[i]]++; name[author[i]] = author[i]; total++;
}
for(i in sum) {
printf "\t%d,%s,%2.1f%%\n", sum[i], name[i], (100 * sum[i] / total)
}
}' | sort -n -r | column -t -s,
}
################################################################################
# DESC: Shows git shortstats on the current user's changes for current day
# ARGS: None
# OUTS: None
################################################################################
function myDailyStats() {
optionPicked "My daily status:"
git diff --shortstat '@{0 day ago}' | sort -nr | tr ',' '\n' | LC_ALL=C awk '
{ args[NR] = $0; }
END {
for (i = 1; i <= NR; ++i) {
printf "\t%s\n", args[i]
}
}'
echo -e "\t" $(git -c log.showSignature=false log --use-mailmap \
--author="$(git config user.name)" --no-merges \
--since=$(date "+%Y-%m-%dT00:00:00") \
--until=$(date "+%Y-%m-%dT23:59:59") --reverse \
| grep commit | wc -l) "commits"
}
################################################################################
# DESC: Lists all contributors to a repo sorted by alphabetical order
# ARGS: None
# OUTS: None
################################################################################
function contributors() {
optionPicked "All contributors (sorted by name):"
git -c log.showSignature=false log --use-mailmap --no-merges $_since $_until \
--format='%aN' $_pathspec | sort -u | cat -n
}
################################################################################
# DESC: Shows an abbreviated ASCII graph based off of commit history
# ARGS: None
# OUTS: None
################################################################################
function branchTree() {
optionPicked "Branching tree view:"
git -c log.showSignature=false log --use-mailmap --graph --abbrev-commit \
$_since $_until --decorate \
--format=format:'--+ Commit: %h %n | Date: %aD (%ar) %n'' | Message: %s %d %n'' + Author: %aN %n' \
--all | head -n $((_limit*5))
}
################################################################################
# DESC: Lists all branches sorted by their most recent commit
# ARGS: None
# OUTS: None
################################################################################
function branchesByDate() {
optionPicked "All branches (sorted by most recent commit):"
git for-each-ref --sort=committerdate refs/heads/ \
--format='[%(authordate:relative)] %(authorname) %(refname:short)' | cat -n
}
################################################################################
# DESC: Displays the latest commit history in an easy to read format by date
# ARGS: $author (optional): Can focus on a single author. Default is all authors
# OUTS: None
################################################################################
function changelogs() {
local author="${1:-}"
local _author=""
local next=$(date +%F)
if [[ -z "${author}" ]]; then
optionPicked "Git changelogs:"
_author="--author=**"
else
optionPicked "Git changelogs for author '${author}':"
_author="--author=${author}"
fi
git -c log.showSignature=false log \
--use-mailmap \
--no-merges \
--format="%cd" \
--date=short "${_author}" $_since $_until $_pathspec \
| sort -u -r | head -n $_limit \
| while read DATE; do
echo -e "\n[$DATE]"
GIT_PAGER=cat git -c log.showSignature=false log \
--use-mailmap --no-merges \
--format=" * %s (%aN)" "${_author}" \
--since=$DATE --until=$next
next=$DATE
done
}
################################################################################
# MAIN
# Check to make sure all utilities required for this script are installed
checkUtils
# Check if we are currently in a git repo.
git rev-parse --is-inside-work-tree > /dev/null
# Parse non-interative commands
if [[ "$#" -eq 1 ]]; then
case "$1" in
-r|--suggest-reviewers) suggestReviewers;;
-T|--detailed-git-stats) detailedGitStats;;
-R|--git-stats-by-branch)
branch=""
while [[ -z "${branch}" ]]; do
read -r -p "Which branch? " branch
done
detailedGitStats "${branch}";;
-b|--branch-tree) branchTree;;
-d|--commits-per-day) commitsPerDay;;
-a|--commits-per-author) commitsPerAuthor;;
-S|--my-daily-stats) myDailyStats;;
-C|--contributors) contributors;;
-D|--branches-by-date) branchesByDate;;
-c|--changelogs) changelogs;;
-L|--changelogs-by-author)
author="${_GIT_AUTHOR:-}"
while [[ -z "${author}" ]]; do
read -r -p "Which author? " author
done
changelogs "${author}";;
-w|--commits-by-weekday) commitsByWeekday;;
-o|--commits-by-hour) commitsByHour;;
-A|--commits-by-author-by-hour)
author="${_GIT_AUTHOR:-}"
while [[ -z "${author}" ]]; do
read -r -p "Which author? " author
done
commitsByHour "${author}";;
-m|--commits-by-month) commitsByMonth;;
-j|--json-output)
json_path=""
while [[ -z "${json_path}" ]]; do
read -r -p "Path to save JSON file: " json_path
if [[ ! -w "${json_path}" ]]; then
echo "Invalid path or permission denied to write to given area."
json_path=""
fi
done
jsonOutput "${json_path}";;
-h|-\?|--help) usage;;
*) echo "Invalid argument"; usage; exit 1;;
esac
exit 0;
fi
[[ "$#" -gt 1 ]] && { echo "Invalid arguments"; usage; exit 1; }
# Parse interactive commands
clear
showMenu
while [[ "${opt}" != "" ]]; do
clear
case "${opt}" in
1) detailedGitStats; showMenu;;
2) branch=""
while [[ -z "${branch}" ]]; do
read -r -p "Which branch? " branch
done
detailedGitStats "${branch}"; showMenu;;
3) changelogs; showMenu;;
4) author=""
while [[ -z "${author}" ]]; do
read -r -p "Which author? " author
done
changelogs "${author}"; showMenu;;
5) myDailyStats; showMenu;;
6) json_path=""
while [[ -z "${json_path}" ]]; do
read -r -p "Path to save JSON file: " json_path
if [[ ! -w "${json_path}" ]]; then
echo "Invalid path or permission denied to write to given area."
json_path=""
fi
done
jsonOutput "${json_path}"; showMenu;;
7) branchTree; showMenu;;
8) branchesByDate; showMenu;;
9) contributors; showMenu;;
10) commitsPerAuthor; showMenu;;
11) commitsPerDay; showMenu;;
12) commitsByMonth; showMenu;;
13) commitsByWeekday; showMenu;;
14) commitsByHour; showMenu;;
15) author=""
while [[ -z "${author}" ]]; do
read -r -p "Which author? " author
done
commitsByHour "${author}"; showMenu;;
16) suggestReviewers; showMenu;;
q|"\n") exit;;
*) clear; optionPicked "Pick an option from the menu"; showMenu;;
esac
done

View File

@@ -1,126 +0,0 @@
.TH git-quick-stats "1" "January 2019" "git-quick-stats" "User Commands"
.SH NAME
.B git\-quick\-stats
\- Simple and efficient way to access various stats in a git repository.
.SH SYNOPSIS
.PP
For non\-interactive mode:
.B git\-quick\-stats [OPTIONS]
.PP
For interactive mode:
.B git-quick-stats
.PP
.SH DESCRIPTION
.PP
Any git repository contains tons of information about commits, contributors,
and files. Extracting this information is not always trivial, mostly because
of a gadzillion options to a gadzillion git commands.
This program allows you to see detailed information about a git repository.
.PP
.SH OPTIONS
.HP
\fB\-r\fR, \fB\-\-suggest\-reviewers\fR
.IP
show the best people to contact to review code
.HP
.PP
\fB\-T\fR, \fB\-\-detailed\-git\-stats\fR
.IP
give a detailed list of git stats
.HP
.PP
\fB\-R\fR, \fB\-\-git\-stats\-by\-branch\fR
.IP
see detailed list of git stats by branch
.HP
.PP
\fB\-d\fR, \fB\-\-commits\-per\-day\fR
.IP
displays a list of commits per day
.HP
.PP
\fB\-m\fR, \fB\-\-commits\-by\-month\fR
.IP
displays a list of commits per month
.HP
.PP
\fB\-w\fR, \fB\-\-commits\-by\-weekday\fR
.IP
displays a list of commits per weekday
.HP
.PP
\fB\-o\fR, \fB\-\-commits\-by\-hour\fR
.IP
displays a list of commits per hour
.HP
.PP
\fB\-A\fR, \fB\-\-commits\-by\-author\-by\-hour\fR
.IP
displays a list of commits per hour by author
.HP
.PP
\fB\-a\fR, \fB\-\-commits\-per\-author\fR
.IP
displays a list of commits per author
.HP
.PP
\fB\-S\fR, \fB\-\-my\-daily\-stats\fR
.IP
see your current daily stats
.HP
.PP
\fB\-C\fR, \fB\-\-contributors\fR
.IP
see a list of everyone who contributed to the repo
.HP
.PP
\fB\-b\fR, \fB\-\-branch\-tree\fR
.IP
show an ASCII graph of the git repo branch history
.HP
.PP
\fB\-D\fR, \fB\-\-branches\-by\-date\fR
.IP
show branches by date
.HP
.PP
\fB\-c\fR, \fB\-\-changelogs\fR
.IP
see changelogs
.HP
.PP
\fB\-L\fR, \fB\-\-changelogs\-by\-author\fR
.IP
see changelogs by author
.HP
.PP
\fB\-j\fR, \fB\-\-json\-output\fR
.IP
save git log as a JSON formatted file to a specified area
.HP
.PP
\fB\-h\fR, \-?, \fB\-\-help\fR
.IP
display this help text in the terminal
.PP
.SH ADDITIONAL USAGE
You can set _GIT_SINCE and _GIT_UNTIL to limit the git time log, example:
.IP
.PP
.B export _GIT_SINCE="2017\-01\-20"
.IP
.PP
You can set _GIT_LIMIT for limited output log, example:
.PP
.B export _GIT_LIMIT=20
.PP
You can exclude directories or files from the stats by using pathspec, example:
.PP
.B export _GIT_PATHSPEC=':!pattern'
.PP
You can switch to the legacy color scheme, example:
.PP
.B export _MENU_THEME=legacy
.
.fi

165
index.html Normal file
View File

@@ -0,0 +1,165 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<title>Git quick statistics is a simple and efficient way to access various statistics in git repository.</title>
<meta name="description" content="▁▅▆▃▅ Any git repository may contain tons of information about commits, contributors, and files. Extracting this information is not always trivial, mostly because there are a gadzillion options to a gadzillion git commands I dont think there is a single person alive who knows them all. Probably not even Linus Torvalds himself :).">
<meta name="keywords" content="git, repository, github, statistics, linux, docker, windows">
<link href="assets/base.css" rel="stylesheet" type="text/css">
<link href="assets/style.css" rel="stylesheet" type="text/css">
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1">
<link rel="shortcut icon" href="assets/icon.svg" type="image/x-icon">
</head>
<body>
<div id="wrap" class="container">
<header class="header">
<div class="row">
<div class="logo six columns">
<a href="https://git-quick-stats.sh/"><img width="40%" src="assets/logo.svg" alt="git-quick-stats logo"></a>
</div>
<nav class="six columns">
<a href="/docs" class="github">Docs</a>
<a href="https://github.com/arzzen/git-quick-stats" class="github">GitHub
<img alt="github" src="assets/GitHub-Mark.png"></a>
</nav>
</div>
</header>
<section class="splash center">
<h1>
<span><u>Simple way</u> to access various <br>statistics in <u>git</u> repository. </span>
</h1>
<br>
<div class="center">
<p class="download">
<strong>Installation</strong>
<a href="https://github.com/arzzen/git-quick-stats#windows">Windows</a>
<a href="https://github.com/arzzen/git-quick-stats#unix-and-linux">Linux</a>
<a href="https://github.com/arzzen/git-quick-stats#macos-homebrew">macOS</a>
<a href="https://github.com/arzzen/git-quick-stats#docker">Docker</a>
</p>
</div>
<div class="center">
<img src="https://user-images.githubusercontent.com/8818630/58364013-61e53800-7e7b-11e9-87f9-790d6744fbd5.png" alt="image">
</div>
</section>
<section class="features">
<div class="row">
<div class="four columns">
<h2>Multiplatform</h2>
Works on Windows, Linux and macOS (or you can use the Docker image).
</div>
<div class="four columns">
<h2>Contribution stats</h2>
List of everyone who contributed to the repository.
</div>
<div class="four columns">
<h2>Code reviewers</h2>
Find the best people to contact to review code.
</div>
</div>
<div class="row">
<div class="four columns">
<h2>Git changelogs</h2>
Easy to fetch git changelogs.
</div>
<div class="four columns">
<h2>Dependency</h2>
You can run on every OS with a Bash shell.
</div>
<div class="four columns">
<h2>Open source</h2>
Git-quick-stats is free, open source software licensed under MIT.
</div>
</div>
</section>
<section>
<div class="row">
<div class="six columns">
<img src="https://user-images.githubusercontent.com/8818630/58364011-61e53800-7e7b-11e9-9417-16cbb241ac2e.png" alt="image">
</div>
<div class="six columns">
<img src="https://user-images.githubusercontent.com/8818630/58364010-61e53800-7e7b-11e9-8711-a40b50aebf52.png" alt="image">
</div>
</div>
</section>
<section>
<h2 id="getting-started">Getting started</h2>
<ul>
<li><strong>Interactive</strong>
<ul>
<li>
git-quick-stats has a built-in interactive menu that can be executed as such:
<br>
<code>git-quick-stats</code>
<br>
Or
<br>
<code>git quick-stats</code>
</li>
</ul>
</li><br>
<li><strong>Non-interactive</strong>
<ul>
<li>
For those who prefer to utilize command-line options, git-quick-stats also has a non-interactive mode supporting both short and long options:
<br>
<code>git-quick-stats [optional-command-to-execute-directly]</code>
<br>
Or
<br>
<code>git quick-stats [optional-command-to-execute-directly]</code>
</li>
<li>
Command-line arguments:
<br>
<code>-r, --suggest-reviewers</code>
show the best people to contact to review code<br>
<code>-T, --detailed-git-stats</code>
- give a detailed list of git stats<br>
<code>-R, --git-stats-by-branch</code>
see detailed list of git stats by branch<br>
<code>-d, --commits-per-day</code>
displays a list of commits per day<br>
<code>-m, --commits-by-month</code>
displays a list of commits per month<br>
<code>-w, --commits-by-weekday</code>
displays a list of commits per weekday<br>
<code>-o, --commits-by-hour</code>
displays a list of commits per hour<br>
<code>-A, --commits-by-author-by-hour</code>
displays a list of commits per hour by author<br>
<code>-a, --commits-per-author</code>
displays a list of commits per author<br>
<code>-S, --my-daily-stats</code>
see your current daily stats<br>
<code>-C, --contributors</code>
see a list of everyone who contributed to the repo<br>
<code>-b, --branch-tree</code>
show an ASCII graph of the git repo branch history<br>
<code>-D, --branches-by-date</code>
show branches by date<br>
<code>-c, --changelogs</code>
see changelogs<br>
<code>-L, --changelogs-by-author</code>
see changelogs by author<br>
<code>-j, --json-output</code>
save git log as a JSON formatted file to a specified area<br>
<code>-h, -?, --help</code>
display this help text in the terminal<br>
</li>
</ul>
</li>
</ul>
</section>
<footer class="footer">
© 2017-2020. All rights reserved
</footer>
</div>
</body>
</html>

View File

@@ -1,214 +0,0 @@
#!/bin/bash
# assert.sh 1.1 - bash unit testing framework
# Copyright (C) 2009-2015 Robert Lehmann
#
# http://github.com/lehmannro/assert.sh
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
export DISCOVERONLY=${DISCOVERONLY:-}
export DEBUG=${DEBUG:-}
export STOP=${STOP:-}
export INVARIANT=${INVARIANT:-}
export CONTINUE=${CONTINUE:-}
args="$(getopt -n "$0" -l \
verbose,help,stop,discover,invariant,continue vhxdic $*)" \
|| exit -1
for arg in $args; do
case "$arg" in
-h)
echo "$0 [-vxidc]" \
"[--verbose] [--stop] [--invariant] [--discover] [--continue]"
echo "`sed 's/./ /g' <<< "$0"` [-h] [--help]"
exit 0;;
--help)
cat <<EOF
Usage: $0 [options]
Language-agnostic unit tests for subprocesses.
Options:
-v, --verbose generate output for every individual test case
-x, --stop stop running tests after the first failure
-i, --invariant do not measure timings to remain invariant between runs
-d, --discover collect test suites only, do not run any tests
-c, --continue do not modify exit code to test suite status
-h show brief usage information and exit
--help show this help message and exit
EOF
exit 0;;
-v|--verbose)
DEBUG=1;;
-x|--stop)
STOP=1;;
-i|--invariant)
INVARIANT=1;;
-d|--discover)
DISCOVERONLY=1;;
-c|--continue)
CONTINUE=1;;
esac
done
_indent=$'\n\t' # local format helper
_assert_reset() {
tests_ran=0
tests_failed=0
tests_errors=()
tests_starttime="$(date +%s%N)" # nanoseconds_since_epoch
}
assert_end() {
# assert_end [suite ..]
tests_endtime="$(date +%s%N)"
# required visible decimal place for seconds (leading zeros if needed)
local tests_time="$( \
printf "%010d" "$(( ${tests_endtime/%N/000000000}
- ${tests_starttime/%N/000000000} ))")" # in ns
tests="$tests_ran ${*:+$* }tests"
[[ -n "$DISCOVERONLY" ]] && echo "collected $tests." && _assert_reset && return
[[ -n "$DEBUG" ]] && echo
# to get report_time split tests_time on 2 substrings:
# ${tests_time:0:${#tests_time}-9} - seconds
# ${tests_time:${#tests_time}-9:3} - milliseconds
[[ -z "$INVARIANT" ]] \
&& report_time=" in ${tests_time:0:${#tests_time}-9}.${tests_time:${#tests_time}-9:3}s" \
|| report_time=
if [[ "$tests_failed" -eq 0 ]]; then
echo "all $tests passed$report_time."
else
for error in "${tests_errors[@]}"; do echo "$error"; done
echo "$tests_failed of $tests failed$report_time."
fi
tests_failed_previous=$tests_failed
[[ $tests_failed -gt 0 ]] && tests_suite_status=1
_assert_reset
}
assert() {
# assert <command> <expected stdout> [stdin]
(( tests_ran++ )) || :
[[ -z "$DISCOVERONLY" ]] || return
expected=$(echo -ne "${2:-}")
result="$(eval 2>/dev/null $1 <<< ${3:-})" || true
if [[ "$result" == "$expected" ]]; then
[[ -z "$DEBUG" ]] || echo -n .
return
fi
result="$(sed -e :a -e '$!N;s/\n/\\n/;ta' <<< "$result")"
[[ -z "$result" ]] && result="nothing" || result="\"$result\""
[[ -z "$2" ]] && expected="nothing" || expected="\"$2\""
_assert_fail "expected $expected${_indent}got $result" "$1" "$3"
}
assert_raises() {
# assert_raises <command> <expected code> [stdin]
(( tests_ran++ )) || :
[[ -z "$DISCOVERONLY" ]] || return
status=0
(eval $1 <<< ${3:-}) > /dev/null 2>&1 || status=$?
expected=${2:-0}
if [[ "$status" -eq "$expected" ]]; then
[[ -z "$DEBUG" ]] || echo -n .
return
fi
_assert_fail "program terminated with code $status instead of $expected" "$1" "$3"
}
# _assert_with_grep <grep modifiers> <command> <expected output...>
_assert_with_grep() {
local grep_modifier="$1"
local output="$($2)"
local exitcode="$4" || 0
shift 2
while [ $# != 0 ]; do
assert_raises "echo '$output' | $GREP $grep_modifier '$1'" $exitcode || return 1
shift
done
}
# assert_startswith <command> <expected start to stdout>
assert_startswith() {
assert_success "[[ '$($1)' == '$2'* ]]"
}
# assert_endswith <command> <expected start to stdout>
assert_endswith() {
assert_success "[[ '$($1)' == *'$2' ]]"
}
# assert_contains <command> <expected output...>
assert_contains() {
_assert_with_grep '-F' "$@"
}
_assert_fail() {
# _assert_fail <failure> <command> <stdin>
[[ -n "$DEBUG" ]] && echo -n X
report="test #$tests_ran \"$2${3:+ <<< $3}\" failed:${_indent}$1"
if [[ -n "$STOP" ]]; then
[[ -n "$DEBUG" ]] && echo
echo "$report"
exit 1
fi
tests_errors[$tests_failed]="$report"
(( tests_failed++ )) || :
}
skip_if() {
# skip_if <command ..>
(eval $@) > /dev/null 2>&1 && status=0 || status=$?
[[ "$status" -eq 0 ]] || return
skip
}
skip() {
# skip (no arguments)
shopt -q extdebug && tests_extdebug=0 || tests_extdebug=1
shopt -q -o errexit && tests_errexit=0 || tests_errexit=1
# enable extdebug so returning 1 in a DEBUG trap handler skips next command
shopt -s extdebug
# disable errexit (set -e) so we can safely return 1 without causing exit
set +o errexit
tests_trapped=0
trap _skip DEBUG
}
_skip() {
if [[ $tests_trapped -eq 0 ]]; then
# DEBUG trap for command we want to skip. Do not remove the handler
# yet because *after* the command we need to reset extdebug/errexit (in
# another DEBUG trap.)
tests_trapped=1
[[ -z "$DEBUG" ]] || echo -n s
return 1
else
trap - DEBUG
[[ $tests_extdebug -eq 0 ]] || shopt -u extdebug
[[ $tests_errexit -eq 1 ]] || set -o errexit
return 0
fi
}
_assert_reset
: ${tests_suite_status:=0} # remember if any of the tests failed so far
_assert_cleanup() {
local status=$?
# modify exit code if it's not already non-zero
[[ $status -eq 0 && -z $CONTINUE ]] && exit $tests_suite_status
}
trap _assert_cleanup EXIT

View File

@@ -1,18 +0,0 @@
#!/bin/bash
. tests/assert.sh -v
src="./git-quick-stats"
assert "$src fail" "Invalid argument\n\nNAME\n git-quick-stats - Simple and efficient way to access various stats in a git repo\n\nSYNOPSIS\n For non-interactive mode: git-quick-stats [OPTIONS]\n For interactive mode: git-quick-stats\n\nDESCRIPTION\n Any git repository contains tons of information about commits, contributors,\n and files. Extracting this information is not always trivial, mostly because\n of a gadzillion options to a gadzillion git commands.\n\n This program allows you to see detailed information about a git repository.\n\nOPTIONS\n -r, --suggest-reviewers\n show the best people to contact to review code\n -T, --detailed-git-stats\n give a detailed list of git stats\n -R, --git-stats-by-branch\n see detailed list of git stats by branch\n -d, --commits-per-day\n displays a list of commits per day\n -m, --commits-by-month\n displays a list of commits per month\n -w, --commits-by-weekday\n displays a list of commits per weekday\n -o, --commits-by-hour\n displays a list of commits per hour\n -A, --commits-by-author-by-hour\n displays a list of commits per hour by author\n -a, --commits-per-author\n displays a list of commits per author\n -S, --my-daily-stats\n see your current daily stats\n -C, --contributors\n see a list of everyone who contributed to the repo\n -b, --branch-tree\n show an ASCII graph of the git repo branch history\n -D, --branches-by-date\n show branches by date\n -c, --changelogs\n see changelogs\n -L, --changelogs-by-author\n see changelogs by author\n -j, --json-output\n save git log as a JSON formatted file to a specified area\n -h, -?, --help\n display this help text in the terminal\n\nADDITIONAL USAGE\n You can set _GIT_SINCE and _GIT_UNTIL to limit the git time log\n ex: export _GIT_SINCE=\"2017-01-20\"\n You can set _GIT_LIMIT for limited output log\n ex: export _GIT_LIMIT=20\n You can exclude directories or files from the stats by using pathspec\n ex: export _GIT_PATHSPEC=':!pattern'\n You can set _MENU_THEME to display the legacy color scheme\n ex: export _MENU_THEME=legacy"
assert_raises "$src fail" 1
assert_contains "$src --suggest-reviewers" "Suggested code reviewers (based on git history)" 127
assert_raises "$src --suggest-reviewers" 0
assert_contains "$src --detailed-git-stats" "Contribution stats" 127
assert_raises "$src --detailed-git-stats" 0
assert_contains "$src --commits-per-day" "Git commits per date" 127
assert_raises "$src --commits-per-day" 0
assert_end