git-notes-hooks 0.1.0__tar.gz → 0.1.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,114 @@
1
+ Metadata-Version: 2.4
2
+ Name: git-notes-hooks
3
+ Version: 0.1.6
4
+ Summary: Automatic Git hooks to keep refs/notes/* synchronized across all remotes on push and pull
5
+ Author-email: Bimo <i.s41m0011@gmail.com>
6
+ License: MIT OR Apache-2.0
7
+ Project-URL: Homepage, https://github.com/isaim0011/git-notes
8
+ Project-URL: Repository, https://github.com/isaim0011/git-notes
9
+ Project-URL: Issues, https://github.com/isaim0011/git-notes/issues
10
+ Project-URL: Documentation, https://github.com/isaim0011/git-notes#readme
11
+ Project-URL: Changelog, https://github.com/isaim0011/git-notes/blob/main/docs/CHANGELOG.md
12
+ Keywords: git,git-notes,git-hooks,code-review,decentralized,developer-tools
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: License :: OSI Approved :: Apache Software License
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3.14
24
+ Classifier: Topic :: Software Development :: Version Control :: Git
25
+ Requires-Python: >=3.11
26
+ Description-Content-Type: text/markdown
27
+ Requires-Dist: click>=8.1
28
+ Requires-Dist: rich>=13.0
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest>=8; extra == "dev"
31
+ Requires-Dist: pytest-mock; extra == "dev"
32
+ Requires-Dist: ruff; extra == "dev"
33
+
34
+ # git-notes-hooks
35
+
36
+ > **Automatic Git hooks to keep `refs/notes/*` seamlessly synchronized across all remotes on every push and pull.**
37
+
38
+ [![PyPI Version](https://img.shields.io/pypi/v/git-notes-hooks.svg)](https://pypi.org/project/git-notes-hooks/)
39
+ [![License](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue)](https://github.com/isaim0011/git-notes)
40
+ [![Python Versions](https://img.shields.io/pypi/pyversions/git-notes-hooks.svg)](https://pypi.org/project/git-notes-hooks/)
41
+
42
+ `git-notes-hooks` provides automated git lifecycle integration for the **[git-notes](https://github.com/isaim0011/git-notes)** ecosystem. It installs zero-friction client-side git hooks into your repositories to ensure decentralized code review comments and notes travel with your commits automatically.
43
+
44
+ ---
45
+
46
+ ## ⚡ Quick Installation
47
+
48
+ Install from PyPI via pip:
49
+
50
+ ```bash
51
+ pip install git-notes-hooks
52
+ ```
53
+
54
+ Or using pipx:
55
+
56
+ ```bash
57
+ pipx install git-notes-hooks
58
+ ```
59
+
60
+ ---
61
+
62
+ ## 🚀 Usage
63
+
64
+ Navigate to any Git repository and run:
65
+
66
+ ### 1. Install Hooks
67
+ Install the automated push/pull synchronization hooks into `.git/hooks`:
68
+
69
+ ```bash
70
+ git-notes-hooks install
71
+ ```
72
+
73
+ This installs:
74
+ - `post-commit`: Updates local note indices on every commit
75
+ - `pre-push`: Pushes `refs/notes/*` to `origin` whenever you run `git push`
76
+ - `post-merge`: Fetches and merges remote notes from `origin` on `git pull`
77
+
78
+ ### 2. Check Hook Status
79
+ Verify active git-notes hooks in your current repository:
80
+
81
+ ```bash
82
+ git-notes-hooks status
83
+ ```
84
+
85
+ ### 3. Uninstall Hooks
86
+ Safely remove git-notes hooks at any time:
87
+
88
+ ```bash
89
+ git-notes-hooks uninstall
90
+ ```
91
+
92
+ ---
93
+
94
+ ## 🔒 History-Safe & Non-Destructive
95
+
96
+ `git-notes-hooks` operates strictly on Git's native note references (`refs/notes/comments`, `refs/notes/review`, `refs/notes/todos`). It **never modifies commit SHAs, git history, or working tree files**.
97
+
98
+ ---
99
+
100
+ ## 🔗 Links & Resources
101
+
102
+ - **GitHub Repository**: [https://github.com/isaim0011/git-notes](https://github.com/isaim0011/git-notes)
103
+ - **Issue Tracker**: [https://github.com/isaim0011/git-notes/issues](https://github.com/isaim0011/git-notes/issues)
104
+ - **Documentation**: [https://github.com/isaim0011/git-notes/blob/main/docs/ARCHITECTURE.md](https://github.com/isaim0011/git-notes/blob/main/docs/ARCHITECTURE.md)
105
+ - **Release Downloads**: [https://github.com/isaim0011/git-notes/releases](https://github.com/isaim0011/git-notes/releases)
106
+
107
+ ---
108
+
109
+ ## 📄 License
110
+
111
+ Licensed under either of:
112
+ - Apache License, Version 2.0
113
+ - MIT License
114
+ at your option.
@@ -0,0 +1,81 @@
1
+ # git-notes-hooks
2
+
3
+ > **Automatic Git hooks to keep `refs/notes/*` seamlessly synchronized across all remotes on every push and pull.**
4
+
5
+ [![PyPI Version](https://img.shields.io/pypi/v/git-notes-hooks.svg)](https://pypi.org/project/git-notes-hooks/)
6
+ [![License](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue)](https://github.com/isaim0011/git-notes)
7
+ [![Python Versions](https://img.shields.io/pypi/pyversions/git-notes-hooks.svg)](https://pypi.org/project/git-notes-hooks/)
8
+
9
+ `git-notes-hooks` provides automated git lifecycle integration for the **[git-notes](https://github.com/isaim0011/git-notes)** ecosystem. It installs zero-friction client-side git hooks into your repositories to ensure decentralized code review comments and notes travel with your commits automatically.
10
+
11
+ ---
12
+
13
+ ## ⚡ Quick Installation
14
+
15
+ Install from PyPI via pip:
16
+
17
+ ```bash
18
+ pip install git-notes-hooks
19
+ ```
20
+
21
+ Or using pipx:
22
+
23
+ ```bash
24
+ pipx install git-notes-hooks
25
+ ```
26
+
27
+ ---
28
+
29
+ ## 🚀 Usage
30
+
31
+ Navigate to any Git repository and run:
32
+
33
+ ### 1. Install Hooks
34
+ Install the automated push/pull synchronization hooks into `.git/hooks`:
35
+
36
+ ```bash
37
+ git-notes-hooks install
38
+ ```
39
+
40
+ This installs:
41
+ - `post-commit`: Updates local note indices on every commit
42
+ - `pre-push`: Pushes `refs/notes/*` to `origin` whenever you run `git push`
43
+ - `post-merge`: Fetches and merges remote notes from `origin` on `git pull`
44
+
45
+ ### 2. Check Hook Status
46
+ Verify active git-notes hooks in your current repository:
47
+
48
+ ```bash
49
+ git-notes-hooks status
50
+ ```
51
+
52
+ ### 3. Uninstall Hooks
53
+ Safely remove git-notes hooks at any time:
54
+
55
+ ```bash
56
+ git-notes-hooks uninstall
57
+ ```
58
+
59
+ ---
60
+
61
+ ## 🔒 History-Safe & Non-Destructive
62
+
63
+ `git-notes-hooks` operates strictly on Git's native note references (`refs/notes/comments`, `refs/notes/review`, `refs/notes/todos`). It **never modifies commit SHAs, git history, or working tree files**.
64
+
65
+ ---
66
+
67
+ ## 🔗 Links & Resources
68
+
69
+ - **GitHub Repository**: [https://github.com/isaim0011/git-notes](https://github.com/isaim0011/git-notes)
70
+ - **Issue Tracker**: [https://github.com/isaim0011/git-notes/issues](https://github.com/isaim0011/git-notes/issues)
71
+ - **Documentation**: [https://github.com/isaim0011/git-notes/blob/main/docs/ARCHITECTURE.md](https://github.com/isaim0011/git-notes/blob/main/docs/ARCHITECTURE.md)
72
+ - **Release Downloads**: [https://github.com/isaim0011/git-notes/releases](https://github.com/isaim0011/git-notes/releases)
73
+
74
+ ---
75
+
76
+ ## 📄 License
77
+
78
+ Licensed under either of:
79
+ - Apache License, Version 2.0
80
+ - MIT License
81
+ at your option.
@@ -0,0 +1,58 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "git-notes-hooks"
7
+ version = "0.1.6"
8
+ description = "Automatic Git hooks to keep refs/notes/* synchronized across all remotes on push and pull"
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = { text = "MIT OR Apache-2.0" }
12
+ authors = [
13
+ { name = "Bimo", email = "i.s41m0011@gmail.com" }
14
+ ]
15
+ keywords = ["git", "git-notes", "git-hooks", "code-review", "decentralized", "developer-tools"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Environment :: Console",
19
+ "Intended Audience :: Developers",
20
+ "License :: OSI Approved :: MIT License",
21
+ "License :: OSI Approved :: Apache Software License",
22
+ "Operating System :: OS Independent",
23
+ "Programming Language :: Python :: 3",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ "Programming Language :: Python :: 3.13",
27
+ "Programming Language :: Python :: 3.14",
28
+ "Topic :: Software Development :: Version Control :: Git",
29
+ ]
30
+ dependencies = [
31
+ "click>=8.1",
32
+ "rich>=13.0",
33
+ ]
34
+
35
+ [project.urls]
36
+ Homepage = "https://github.com/isaim0011/git-notes"
37
+ Repository = "https://github.com/isaim0011/git-notes"
38
+ Issues = "https://github.com/isaim0011/git-notes/issues"
39
+ Documentation = "https://github.com/isaim0011/git-notes#readme"
40
+ Changelog = "https://github.com/isaim0011/git-notes/blob/main/docs/CHANGELOG.md"
41
+
42
+ [project.scripts]
43
+ git-notes-hooks = "gn_hooks.cli:main"
44
+
45
+ [project.optional-dependencies]
46
+ dev = [
47
+ "pytest>=8",
48
+ "pytest-mock",
49
+ "ruff",
50
+ ]
51
+
52
+ [tool.setuptools.packages.find]
53
+ where = [".."]
54
+ include = ["gn_hooks*"]
55
+
56
+ [tool.pytest.ini_options]
57
+ pythonpath = ["."]
58
+ testpaths = ["tests"]
@@ -0,0 +1,94 @@
1
+ from pathlib import Path
2
+ import pytest
3
+
4
+ from gn_hooks.install import find_git_root
5
+
6
+
7
+ def test_find_git_root_at_repo_root(tmp_path: Path):
8
+ """find_git_root returns the path itself when .git dir is directly in path."""
9
+ git_dir = tmp_path / ".git"
10
+ git_dir.mkdir()
11
+
12
+ result = find_git_root(tmp_path)
13
+ assert result == tmp_path.resolve()
14
+
15
+
16
+ def test_find_git_root_from_nested_subdir(tmp_path: Path):
17
+ """find_git_root walks up directory tree from a nested subdirectory to find .git dir."""
18
+ git_dir = tmp_path / ".git"
19
+ git_dir.mkdir()
20
+
21
+ nested_dir = tmp_path / "sub1" / "sub2" / "sub3"
22
+ nested_dir.mkdir(parents=True)
23
+
24
+ result = find_git_root(nested_dir)
25
+ assert result == tmp_path.resolve()
26
+
27
+
28
+ def test_find_git_root_from_file_path(tmp_path: Path):
29
+ """find_git_root works when passed a file path inside a repository."""
30
+ git_dir = tmp_path / ".git"
31
+ git_dir.mkdir()
32
+
33
+ sub_dir = tmp_path / "src"
34
+ sub_dir.mkdir()
35
+ file_path = sub_dir / "main.py"
36
+ file_path.write_text("print('hello')")
37
+
38
+ result = find_git_root(file_path)
39
+ assert result == tmp_path.resolve()
40
+
41
+
42
+ def test_find_git_root_with_relative_path(tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
43
+ """find_git_root handles relative paths correctly by resolving them."""
44
+ git_dir = tmp_path / ".git"
45
+ git_dir.mkdir()
46
+
47
+ sub_dir = tmp_path / "sub"
48
+ sub_dir.mkdir()
49
+
50
+ monkeypatch.chdir(sub_dir)
51
+ result = find_git_root(Path("."))
52
+ assert result == tmp_path.resolve()
53
+
54
+
55
+ def test_find_git_root_when_git_is_a_file(tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
56
+ """find_git_root ignores .git if it is a file instead of a directory."""
57
+ resolved_tmp = tmp_path.resolve()
58
+ sub_dir = resolved_tmp / "sub"
59
+ sub_dir.mkdir()
60
+ git_file = sub_dir / ".git"
61
+ git_file.write_text("gitdir: /path/to/git")
62
+
63
+ # Stop search loop at resolved_tmp to isolate test from outer directory tree
64
+ original_parent_fget = Path.parent.fget
65
+
66
+ def custom_parent(self):
67
+ if self == resolved_tmp:
68
+ return self
69
+ return original_parent_fget(self)
70
+
71
+ monkeypatch.setattr(Path, "parent", property(custom_parent))
72
+
73
+ with pytest.raises(FileNotFoundError, match="Not a git repository"):
74
+ find_git_root(sub_dir)
75
+
76
+
77
+ def test_find_git_root_not_found_raises_file_not_found_error(tmp_path: Path, monkeypatch: pytest.MonkeyPatch):
78
+ """find_git_root raises FileNotFoundError when no parent directory contains a .git directory."""
79
+ resolved_tmp = tmp_path.resolve()
80
+ no_git_dir = resolved_tmp / "no_git_dir"
81
+ no_git_dir.mkdir()
82
+
83
+ # Stop search loop at resolved_tmp to guarantee clean test isolation
84
+ original_parent_fget = Path.parent.fget
85
+
86
+ def custom_parent(self):
87
+ if self == resolved_tmp:
88
+ return self
89
+ return original_parent_fget(self)
90
+
91
+ monkeypatch.setattr(Path, "parent", property(custom_parent))
92
+
93
+ with pytest.raises(FileNotFoundError, match="Not a git repository"):
94
+ find_git_root(no_git_dir)
@@ -1,12 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: git-notes-hooks
3
- Version: 0.1.0
4
- Summary: Auto-install git hooks that sync refs/notes/* on push/pull
5
- License: MIT OR Apache-2.0
6
- Requires-Python: >=3.11
7
- Requires-Dist: click>=8.1
8
- Requires-Dist: rich>=13.0
9
- Provides-Extra: dev
10
- Requires-Dist: pytest>=8; extra == "dev"
11
- Requires-Dist: pytest-mock; extra == "dev"
12
- Requires-Dist: ruff; extra == "dev"
@@ -1,21 +0,0 @@
1
- [build-system]
2
- requires = ["setuptools>=68", "wheel"]
3
- build-backend = "setuptools.build_meta"
4
-
5
- [project]
6
- name = "git-notes-hooks"
7
- version = "0.1.0"
8
- description = "Auto-install git hooks that sync refs/notes/* on push/pull"
9
- license = { text = "MIT OR Apache-2.0" }
10
- requires-python = ">=3.11"
11
- dependencies = ["click>=8.1", "rich>=13.0"]
12
-
13
- [project.scripts]
14
- git-notes-hooks = "gn_hooks.cli:main"
15
-
16
- [project.optional-dependencies]
17
- dev = ["pytest>=8", "pytest-mock", "ruff"]
18
-
19
- [tool.setuptools.packages.find]
20
- where = [".."]
21
- include = ["gn_hooks*"]