Metadata-Version: 2.4
Name: gerrit-change-list
Version: 0.0.1
Summary: Recursively scan git repos under a path and list commits merged within a time range (by committer date), with Gerrit patch links.
Project-URL: Homepage, https://github.com/Junbo-Zheng/gerrit-change-list
Project-URL: Issues, https://github.com/Junbo-Zheng/gerrit-change-list/issues
Author: Junbo Zheng
License: Apache-2.0
License-File: LICENSE
Keywords: commits,gerrit,git,merge-log,repo
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Version Control :: Git
Requires-Python: >=3.10
Provides-Extra: dev
Requires-Dist: black; extra == 'dev'
Requires-Dist: build; extra == 'dev'
Requires-Dist: pytest-cov; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: twine; extra == 'dev'
Description-Content-Type: text/markdown

# gerrit-change-list

![PyPI](https://img.shields.io/pypi/v/gerrit-change-list)
![PyPI - Downloads](https://img.shields.io/pypi/dm/gerrit-change-list)
![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)
![Python](https://img.shields.io/badge/python-3.10%2B-blue)

Recursively scan git repositories under a path and list commits **merged**
within a time range — by **committer date**, not author date — across every
repo it finds, with Gerrit patch links.

Built for the recurring question: _"a problem showed up; who landed what
into these repos in this window, and what are the patch links?"_

## Why committer date

In a Gerrit workflow the **author date** is when the developer wrote the
patch; the **committer date** is when it actually landed on the branch
(merged / cherry-picked / rebased in). When you `git pull` / `repo sync`
to latest and ask "what got merged on July 5th", you want committer date.
`git log --since`/`--until` filter on committer date, so that is what this
tool uses.

## Features

- **Three time selectors** (pick one): `--day`, `--hour`, or `--since`/`--until`.
- **Cross-repo by default**: recursively finds every `.git` under the path —
  standalone repos **and** `repo`-tool-managed multi-repos. Nested submodules
  are picked up too.
- **Gerrit patch links**: host derived from each repo's `origin` remote;
  link is `https://<host>/q/<Change-Id>` (clickable, no network/auth needed).
- **Two outputs**: a colored terminal table grouped by repo, plus a Markdown
  report file.
- **Zero runtime dependencies** — standard library only.

## Install

Prerequisite: `git` must be on `PATH` (the tool shells out to `git log` /
`git config`). Python ≥ 3.10.

From PyPI:

```bash
pip install gerrit-change-list
gerrit-change-list --version
```

Editable install (for development, with test/lint deps):

```bash
pip install -e ".[dev]"
```

Or run from source with no install:

```bash
./main.py --version
```

## Usage

```bash
# Whole calendar day (local timezone)
gerrit-change-list /path/to/workspace --day 2026-07-05

# Whole calendar hour
gerrit-change-list /path/to/workspace --hour "2026-07-05 14"

# Precise range (--until defaults to now when omitted)
gerrit-change-list /path/to/workspace --since "2026-07-05 14:00" --until "2026-07-05 15:30"

# Force a timezone for the selectors
gerrit-change-list . --day 2026-07-05 --tz Asia/Shanghai

# Filter by submitter; show committer instead of author
gerrit-change-list . --since "2026-07-05" --author "alice" --by-committer
```

> [!NOTE]
> The tool only reads local state — it does not pull. Run `git pull` /
> `repo sync` to latest first.

### Example

Terminal output (colors shown when stdout is a TTY and `NO_COLOR` is unset):

```text
$ gerrit-change-list /path/to/workspace --day 2026-07-05
gerrit-change-list  range: 2026-07-05 .. 2026-07-06
3 commit(s) across 2 repo(s)

platform/native  (2)
  Merge time                Patch                                        Submitter           Subject
  2026-07-05 09:12:33 +0800 https://gerrit.example.com/q/I1a2b3c4d5e6   Alice <a@x.example>  Fix audio underrun on cold start
  2026-07-05 14:45:10 +0800 https://gerrit.example.com/q/I2b3c4d5e6f7   Bob <b@x.example>    Refactor PCM open path

vendor/hal  (1)
  Merge time                Patch                                        Submitter           Subject
  2026-07-05 10:03:55 +0800 https://gerrit.example.com/q/I3c4d5e6f7g8   Carol <c@x.example>  Lower default buffer size
```

A Markdown report with the same content is written next to the run
(`gerrit-change-list-report-<timestamp>.md` by default).

### Output

- **Terminal**: a color table grouped by repo, columns
  `Merge time | Patch | Submitter | Subject`. Color is gated on TTY and
  `NO_COLOR`.
- **Markdown report**: written to `gerrit-change-list-report-<timestamp>.md`
  (override with `-o`, suppress with `--no-markdown`).

> [!TIP]
> To preview the rendered Markdown report: `grip <file.md>` (local server) or
> `pandoc <file.md> -s -o <file.html>` (standalone HTML).

### Options

| Option | Description |
| --- | --- |
| `path` | root path to scan (default: current directory) |
| `--day YYYY-MM-DD` | whole calendar day |
| `--hour "YYYY-MM-DD HH"` | whole calendar hour |
| `--since ...` | start time (inclusive); `--until` defaults to now |
| `--until ...` | end time |
| `--tz ...` | `+0800` \| `+08:00` \| `Z` \| `Asia/Shanghai` (default: system local) |
| `--author REGEX` | match author name/email |
| `--by-committer` | show committer (not author) as the submitter column |
| `--max-count N` | per-repo commit cap |
| `--reverse` | oldest-first within each repo |
| `-o, --output PATH` | Markdown report path |
| `--no-markdown` | do not write a Markdown report file |
| `-V, --version` | show version and exit |

## How it works

- **Repo discovery**: a "repo" is any directory containing a `.git` entry —
  a `.git` directory (normal checkout) or a `.git` file (worktree /
  submodule). The scan never enters `.git/` or `.repo/` metadata, but keeps
  walking a found repo's subdirectories so nested submodules are found.
  Each `repo`-tool project is itself a normal git repo, so it is covered.
- **Time field**: `git log --since`/`--until` filter on the committer date.
  Author date is not used for filtering.
- **Patch link**: the Gerrit host is parsed from each repo's `origin`
  remote URL. For `ssh://` remotes the port (e.g. Gerrit's 29418) is
  dropped — that's the push port; the web UI runs on HTTPS (443). The link
  `https://<host>/q/<Change-Id>` is Gerrit's search-redirect URL. Commits
  without a `Change-Id` fall back to the commit hash.

## Development

```bash
pip install -e ".[dev]"
pytest                   # tests
black --check src tests  # format check (CI-enforced)
python -m build          # build wheel
```

## License

Apache License 2.0 — see [LICENSE](LICENSE).

