Skip to content

Commit 0d3eb8c

Browse files
committed
Button up the last of the functionality
* Handles all of the shell exporting capabilities. Tests adjusted to handle a mock config. * Adds Dockerfile for development purposes similar to the parent proj * Adds legacy menu capabilities
1 parent 32b9292 commit 0d3eb8c

14 files changed

+900
-301
lines changed

Dockerfile

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Use the official Python image as the base image
2+
# and setup the env vars necessary
3+
FROM python:3.9-slim
4+
ENV PYTHONUNBUFFERED=1
5+
ENV PYTHONDONTWRITEBYTECODE=1
6+
7+
# Set the working directory inside the container
8+
WORKDIR /app
9+
10+
# Install git as it's our only dep
11+
RUN apt-get update && apt-get install -y git && apt-get clean
12+
13+
# Copy the requirements and configuration files first for caching
14+
COPY pyproject.toml setup.py MANIFEST.in ./
15+
16+
# Install build dependencies and the project in editable mode
17+
RUN pip install --upgrade pip setuptools
18+
RUN pip install -e .
19+
20+
# Copy the rest of the stuff
21+
COPY . .
22+
23+
# Initialize a basic git repo
24+
RUN git init && \
25+
git config user.name "Docker" && \
26+
git config user.email "[email protected]" && \
27+
git add . && \
28+
git commit -m "Initial commit" || echo "Already a git repository"
29+
30+
# NOTE: Should we add dummy commits?
31+
# Thought - we can dogfood and clone the git-py-stats repo inside here
32+
33+
# Command to run the CLI tool with help option
34+
CMD ["git-py-stats", "--help"]
35+

README.md

Lines changed: 99 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -78,16 +78,16 @@ project's version. Not Yet Implemented means it does not exist yet:
7878
| **Git Commits per Hour by Author** | Completed ✔️ | Shows hourly commit count hour by given author. |
7979
| **Git Commits per Timezone** | Completed ✔️ | Counts commits based on timezones. |
8080
| **Git Commits per Timezone by Author** | Completed ✔️ | Shows timezone-based commit counts by given author. |
81-
| **Since Variable Adjustable by User** | Not Yet Implemented ❌ | Allows users to set the starting point for commit logs. |
82-
| **Until Variable Adjustable by User** | Not Yet Implemented ❌ | Enables users to define the end point for commit logs. |
83-
| **Pathspec Variable Adjustable by User** | Not Yet Implemented ❌ | Filters commits based on specified path patterns. |
84-
| **Merge View Variable Adjustable by User** | Not Yet Implemented ❌ | Controls the inclusion of merge commits in views. |
85-
| **Limit Variable Adjustable by User** | Not Yet Implemented ❌ | Sets the maximum number of commits to display. |
86-
| **Log Options Variable Adjustable by User** | Not Yet Implemented ❌ | Customizes git log command options. |
87-
| **Legacy Theme** | Not Yet Implemented ❌ | Restores the previous visual theme of the application. |
81+
| **Since Variable Adjustable by User** | Completed ✔️ | Allows users to set the starting point for commit logs. |
82+
| **Until Variable Adjustable by User** | Completed ✔️ | Enables users to define the end point for commit logs. |
83+
| **Pathspec Variable Adjustable by User** | Completed ✔️ | Filters commits based on specified path patterns. |
84+
| **Merge View Variable Adjustable by User** | Completed ✔️ | Controls the inclusion of merge commits in views. |
85+
| **Limit Variable Adjustable by User** | Completed ✔️ | Sets the maximum number of commits to display. |
86+
| **Log Options Variable Adjustable by User** | Completed ✔️ | Customizes git log command options. |
87+
| **Legacy Theme** | Completed ✔️ | Restores the previous visual theme of the application. |
8888
| **Linux Package Install** | Not Yet Implemented ❌ | Allows Linux users to install via a package manager. |
8989
| **macOS Package install** | Not Yet Implemented ❌ | Allows macOS users to install via brew. |
90-
| **Docker Development Image** | Not Yet Implemented ❌ | Provides a Docker development image for CI/CD. |
90+
| **Docker Development Image** | Completed ✔️ | Provides a Docker development image for CI/CD. |
9191

9292
## Changes from Original
9393

@@ -96,15 +96,16 @@ there may be instances where this version differs from the base project by desig
9696
The following is a list of differences that this project will maintain compared to
9797
the parent project:
9898

99-
* Author, dates, and branch names can be passed via cmdline without interaction
99+
- Author, dates, and branch names can be passed via cmdline without interaction
100100
by the user. This means you can now do `git-py-stats -L "John Doe"` instead
101101
of being prompted to enter the name after executing the non-interactive cmd.
102-
* CSV output is now saved to a file instead of printing out to the terminal.
102+
- CSV output is now saved to a file instead of printing out to the terminal.
103103
This file will be saved to wherever the process was executed. The name will
104104
be `git_daily_stats.csv`
105-
* JSON output is saved to a file wherever the process was executed instead of
105+
- JSON output is saved to a file wherever the process was executed instead of
106106
one that is provided by the user. The name will be `git_log.json`
107-
* The New Contributors function shows the user's name next to the email in case
107+
- JSON and CSV formatting has changed slightly from the original.
108+
- The New Contributors function shows the user's name next to the email in case
108109
no known mailmap has been implemented for that user.
109110

110111
## Requirements
@@ -216,6 +217,92 @@ For a full list of available options, run:
216217
git-py-stats --help
217218
```
218219
220+
### Advanced Usage
221+
222+
It is possible for `git-py-stats` to read shell environment variables just like
223+
`git-quick-stats` does. As it aims to maintain 1:1 compatibility, all of the
224+
same arguments work the same as the parent project.
225+
226+
#### Git log since and until
227+
228+
You can set the variables `_GIT_SINCE` and/or `_GIT_UNTIL` before running
229+
`git-py-stats` to limit the git log.
230+
These work similar to git's built-in `--since` and `--until` log options.
231+
232+
```bash
233+
export _GIT_SINCE="2017-01-20"
234+
export _GIT_UNTIL="2017-01-22"
235+
```
236+
237+
Once set, run `git-py-stats` as normal. Note that this affects all stats that
238+
parse the git log history until unset.
239+
240+
#### Git log limit
241+
242+
You can set variable `_GIT_LIMIT` for limited output.
243+
It will affect the "changelogs" and "branch tree" options.
244+
The default limit is `10`.
245+
246+
```bash
247+
export _GIT_LIMIT=20
248+
```
249+
250+
#### Git log options
251+
252+
You can set `_GIT_LOG_OPTIONS` for
253+
[git log options](https://git-scm.com/docs/git-log#_options):
254+
255+
```bash
256+
export _GIT_LOG_OPTIONS="--ignore-all-space --ignore-blank-lines"
257+
```
258+
259+
#### Git pathspec
260+
261+
You can exclude a directory from the stats by using
262+
[pathspec](https://git-scm.com/docs/gitglossary#gitglossary-aiddefpathspecapathspec)
263+
264+
```bash
265+
export _GIT_PATHSPEC=':!directory'
266+
```
267+
268+
You can also exclude files from the stats.
269+
Note that it works with any alphanumeric, glob, or regex that git respects.
270+
271+
```bash
272+
export _GIT_PATHSPEC=':!package-lock.json'
273+
```
274+
275+
#### Git merge view strategy
276+
277+
You can set the variable `_GIT_MERGE_VIEW` to enable merge commits to be part
278+
of the stats by setting `_GIT_MERGE_VIEW` to `enable`. You can also choose to
279+
only show merge commits by setting `_GIT_MERGE_VIEW` to `exclusive`.
280+
Default is to not show merge commits.
281+
These work similar to git's built-in `--merges` and `--no-merges` log options.
282+
283+
```bash
284+
export _GIT_MERGE_VIEW="enable"
285+
export _GIT_MERGE_VIEW="exclusive"
286+
```
287+
288+
#### Git branch
289+
290+
You can set the variable `_GIT_BRANCH` to set the branch of the stats.
291+
Works with commands `--git-stats-by-branch` and `--csv-output-by-branch`.
292+
293+
```bash
294+
export _GIT_BRANCH="master"
295+
```
296+
297+
#### Color themes
298+
299+
You can change to the legacy color scheme by toggling the variable
300+
`_MENU_THEME` between `default` and `legacy`
301+
302+
```bash
303+
export _MENU_THEME="legacy"
304+
```
305+
219306
## Development
220307
221308
This section is currently under development and is changing rapidly as we work

git_py_stats/config.py

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
"""
2+
Handles reading configuration settings from environment variables.
3+
"""
4+
5+
import os
6+
from datetime import datetime
7+
from typing import Dict, Union, Optional
8+
from git_py_stats.git_operations import run_git_command
9+
10+
# TODO: This is a rough equivalent of what the original program does.
11+
# However, that doesn't mean this is the correct way to handle
12+
# this type of operation since these are not much different
13+
# from global vars. Granted, they're global in the user's shell env
14+
# to begin with, but since we now have the power of Python, we can
15+
# probably handle this in a more expressive way.
16+
# Context and Decorators? Command Factory to leverage Dependency
17+
# Injection and the Command pattern? Centralized Config Manager?
18+
# Marked as future possible refactor.
19+
def get_config() -> Dict[str, Union[str, int]]:
20+
"""
21+
Reads configuration from environment variables and sets default values.
22+
These are the original program's environment variables:
23+
24+
Environment Variables:
25+
_GIT_SINCE (str): Equivalent to git's --since flag.
26+
If not set, defaults to the first commit date in the repository.
27+
_GIT_UNTIL (str): Equivalent to git's --until flag.
28+
If not set, defaults to the current system date/time upon exec
29+
of the program.
30+
_GIT_PATHSPEC (str): Specifies files or directories to include/exclude in stats.
31+
Defaults to "--" which means to skip over this option.
32+
_GIT_MERGE_VIEW (str): Merge commit view strategy. Options:
33+
- 'exclusive' to show only merge commits.
34+
- 'enable' to use the user's default merge view from the conf.
35+
Default is usually to show both regular and merge commits.
36+
- Any other value defaults to '--no-merges' currently.
37+
_GIT_LIMIT (int): Limits the git log output. Defaults to 10.
38+
_GIT_LOG_OPTIONS (str): Additional git log options. Default is empty.
39+
_MENU_THEME (str): Toggles between the default theme and legacy theme.
40+
- 'legacy' to set the legacy theme
41+
- Empty to set the default theme
42+
43+
Returns:
44+
Dict[str, Union[str, int]]: A dictionary containing the configuration options:
45+
- 'since' (str): Git command option for the start date.
46+
- 'until' (str): Git command option for the end date.
47+
- 'pathspec' (str): Git command option for pathspec.
48+
- 'merges' (str): Git command option for merge commit view strategy.
49+
- 'limit' (int): Git log output limit.
50+
- 'log_options' (str): Additional git log options.
51+
- 'menu_theme' (str): Menu theme color.
52+
"""
53+
config: Dict[str, Union[str, int]] = {}
54+
55+
# _GIT_SINCE
56+
git_since: Optional[str] = os.environ.get('_GIT_SINCE')
57+
if git_since:
58+
config['since'] = f"--since={git_since}"
59+
else:
60+
# Get the earliest commit date in the repo
61+
earliest_commit_date: Optional[str] = run_git_command(['git', 'log', '--reverse', '--format=%ad'])
62+
if earliest_commit_date:
63+
first_commit_date: str = earliest_commit_date.split('\n')[0]
64+
config['since'] = f"--since='{first_commit_date}'"
65+
else:
66+
config['since'] = ''
67+
68+
# _GIT_UNTIL
69+
git_until: Optional[str] = os.environ.get('_GIT_UNTIL')
70+
if git_until:
71+
config['until'] = f"--until={git_until}"
72+
else:
73+
# Get the current date/time upon exec of the program
74+
now: str = datetime.now().strftime('%a, %d %b %Y %H:%M:%S %Z')
75+
config['until'] = f"--until='{now}'"
76+
77+
# _GIT_PATHSPEC
78+
git_pathspec: Optional[str] = os.environ.get('_GIT_PATHSPEC')
79+
if git_pathspec:
80+
config['pathspec'] = f"-- {git_pathspec}"
81+
else:
82+
config['pathspec'] = "--"
83+
84+
# _GIT_MERGE_VIEW
85+
git_merge_view: str = os.environ.get('_GIT_MERGE_VIEW', '').lower()
86+
if git_merge_view == 'exclusive':
87+
config['merges'] = '--merges'
88+
elif git_merge_view == 'enable':
89+
config['merges'] = ''
90+
else:
91+
config['merges'] = '--no-merges'
92+
93+
# _GIT_LIMIT
94+
git_limit: Optional[str] = os.environ.get('_GIT_LIMIT')
95+
if git_limit:
96+
# Slight sanitization, but we're still gonna wild west this a bit
97+
try:
98+
config['limit'] = int(git_limit)
99+
except ValueError:
100+
print("Invalid value for _GIT_LIMIT. Using default value 10.")
101+
config['limit'] = 10
102+
else:
103+
config['limit'] = 10
104+
105+
# _GIT_LOG_OPTIONS
106+
# NOTE: We'll need to sanitize our entire git command
107+
git_log_options: Optional[str] = os.environ.get('_GIT_LOG_OPTIONS')
108+
if git_log_options:
109+
config['log_options'] = git_log_options
110+
else:
111+
config['log_options'] = ''
112+
113+
# _MENU_THEME
114+
menu_theme: Optional[str] = os.environ.get('_MENU_THEME')
115+
if menu_theme == 'legacy':
116+
config['menu_theme'] = 'legacy'
117+
else:
118+
config['menu_theme'] = ''
119+
120+
return config

0 commit comments

Comments
 (0)