feat: add git pull subcommand
Some checks failed
checks / tests-10 (push) Failing after 2m56s
checks / pre-commit (push) Successful in 4m28s
checks / tests-11 (push) Failing after 4m8s
checks / tests-12 (push) Failing after 2m47s

This commit is contained in:
cătălin 2024-09-06 20:51:03 +02:00
commit 9dd2405c47
No known key found for this signature in database
10 changed files with 101 additions and 15 deletions

View file

@ -1 +1 @@
__version__ = "0.5.1a2" __version__ = "0.6.0"

View file

@ -2,6 +2,10 @@ from halig.commands.git.base import GitBaseCommand
class GitCommitCommand(GitBaseCommand): class GitCommitCommand(GitBaseCommand):
def __init__(self, message: str | None = None, *args, **kwargs):
super().__init__(*args, **kwargs)
self.message = message or self.settings.default_commit_message
def run(self): def run(self):
"""Add all .age files to git and commit them using gitpython""" """Add all .age files to git and commit them using gitpython"""
self.repo.index.add( self.repo.index.add(

View file

@ -0,0 +1,19 @@
from halig.commands.git.base import GitBaseCommand
class GitPullCommand(GitBaseCommand):
def __init__(
self, remotes: list[str] | None = None, ref: str | None = None, *args, **kwargs
):
super().__init__(*args, **kwargs)
self.remotes = remotes
self.ref = ref
def run(self):
"""Pull all changes from the remote git repo"""
if not self.remotes:
self.repo.remotes.origin.pull(self.ref or "main")
return
for remote in self.remotes:
self.repo.remotes[remote].pull(self.ref or "main")

View file

@ -2,11 +2,15 @@ from halig.commands.git.base import GitBaseCommand
class GitPushCommand(GitBaseCommand): class GitPushCommand(GitBaseCommand):
def run(self, remotes: list[str] | None = None): def __init__(self, remotes: list[str] | None = None, *args, **kwargs):
super().__init__(*args, **kwargs)
self.remotes = remotes
def run(self):
"""Push all changes to the remote git repo""" """Push all changes to the remote git repo"""
if not remotes: if not self.remotes:
self.repo.remotes.origin.push() self.repo.remotes.origin.push()
return return
for remote in remotes: for remote in self.remotes:
self.repo.remotes[remote].push() self.repo.remotes[remote].push()

View file

@ -14,6 +14,7 @@ when new public keys have been added to the config file and you want the notes
to be seen by the new pairing private keys""" to be seen by the new pairing private keys"""
COMMANDS_GIT_COMMIT_HELP = "Commit all .age files to git" COMMANDS_GIT_COMMIT_HELP = "Commit all .age files to git"
COMMANDS_GIT_PUSH_HELP = "Push all .age files to git" COMMANDS_GIT_PUSH_HELP = "Push all .age files to git"
COMMANDS_GIT_PULL_HELP = "Pull all .age files from git"
# OPTIONS # OPTIONS
OPTION_CONFIG_HELP = "Configuration file. Must be YAML and schema compatible" OPTION_CONFIG_HELP = "Configuration file. Must be YAML and schema compatible"

View file

@ -10,6 +10,7 @@ from halig import literals
from halig.__version__ import __version__ from halig.__version__ import __version__
from halig.commands.edit import EditCommand from halig.commands.edit import EditCommand
from halig.commands.git.commit import GitCommitCommand from halig.commands.git.commit import GitCommitCommand
from halig.commands.git.pull import GitPullCommand
from halig.commands.git.push import GitPushCommand from halig.commands.git.push import GitPushCommand
from halig.commands.import_unencrypted import ImportCommand from halig.commands.import_unencrypted import ImportCommand
from halig.commands.notebooks import NotebooksCommand from halig.commands.notebooks import NotebooksCommand
@ -168,10 +169,21 @@ def git_commit(
@git_app.command(name="push", help=literals.COMMANDS_GIT_PUSH_HELP) @git_app.command(name="push", help=literals.COMMANDS_GIT_PUSH_HELP)
def git_push( def git_push(
remotes: list[str] | None = None,
config: Path | None = config_option, config: Path | None = config_option,
): ):
settings = load_from_file(config) settings = load_from_file(config)
command = GitPushCommand(settings=settings) command = GitPushCommand(settings=settings, remotes=remotes)
command.run()
@git_app.command(name="pull", help=literals.COMMANDS_GIT_PULL_HELP)
def git_pull(
remotes: list[str] | None = None,
config: Path | None = config_option,
):
settings = load_from_file(config)
command = GitPullCommand(settings=settings, remotes=remotes)
command.run() command.run()

View file

@ -8,7 +8,7 @@ from halig.settings import Settings
@pytest.fixture @pytest.fixture
def command(settings: Settings): def command(settings: Settings):
return GitCommitCommand(settings) return GitCommitCommand(settings=settings)
def test_repo_is_not_initialized(settings): def test_repo_is_not_initialized(settings):
@ -16,7 +16,7 @@ def test_repo_is_not_initialized(settings):
initializes the repo upon instantiation""" initializes the repo upon instantiation"""
assert not (settings.notebooks_root_path / ".git").is_dir() assert not (settings.notebooks_root_path / ".git").is_dir()
GitCommitCommand(settings) GitCommitCommand(settings=settings)
assert (settings.notebooks_root_path / ".git").is_dir() assert (settings.notebooks_root_path / ".git").is_dir()
@ -27,7 +27,7 @@ def test_repo_is_initialized(settings):
p = subprocess.Popen(["git", "init"], cwd=settings.notebooks_root_path) p = subprocess.Popen(["git", "init"], cwd=settings.notebooks_root_path)
p.wait() p.wait()
assert (settings.notebooks_root_path / ".git").is_dir() assert (settings.notebooks_root_path / ".git").is_dir()
GitCommitCommand(settings) GitCommitCommand(settings=settings)
assert (settings.notebooks_root_path / ".git").is_dir() assert (settings.notebooks_root_path / ".git").is_dir()

View file

@ -0,0 +1,37 @@
import shutil
import pytest
from git import Repo
from halig.commands.git.pull import GitPullCommand
@pytest.fixture
def command(settings, faker):
"""Configure a local remote for testing located at settings.notebooks_root_path/../remote, push some .age files to
that remote
"""
command = GitPullCommand(settings=settings)
new_path = shutil.copytree(settings.notebooks_root_path, settings.notebooks_root_path / "../remote")
new_path = new_path.resolve()
command.repo.create_remote("origin", str(new_path))
remote_repo = Repo(new_path)
for _ in range(10):
random_age_file = new_path / f"{faker.word()}.age"
random_age_file.touch()
remote_repo.index.add([str(random_age_file)])
remote_repo.index.commit("Update notebooks")
return command
def test_pull_from_origin(command):
command.run()
def test_pull_from_custom_origin(settings, command):
remote_path = settings.notebooks_root_path / "../remote"
command.repo.create_remote("custom", str(remote_path.resolve()))
command.remotes = ["custom"]
command.run()

View file

@ -9,29 +9,30 @@ from halig.commands.git.push import GitPushCommand
@pytest.fixture @pytest.fixture
def command(settings, faker): def command(settings, faker):
"""Configure a local remote for testing""" """Configure a local remote for testing"""
commit_command = GitCommitCommand(settings) commit_command = GitCommitCommand(settings=settings)
new_path = shutil.copytree(settings.notebooks_root_path , settings.notebooks_root_path / "../remote") new_path = shutil.copytree(settings.notebooks_root_path, settings.notebooks_root_path / "../remote")
new_path = new_path.resolve() new_path = new_path.resolve()
for _ in range(10): for _ in range(10):
random_age_file = settings.notebooks_root_path / f"{faker.word()}.age" random_age_file = settings.notebooks_root_path / f"{faker.word()}.age"
random_age_file.touch() random_age_file.touch()
commit_command.run() commit_command.run()
push_command = GitPushCommand(settings) push_command = GitPushCommand(settings=settings)
push_command.repo.create_remote("origin", str(new_path)) push_command.repo.create_remote("origin", str(new_path))
return push_command return push_command
def test_push_to_origin(settings, command): def test_push_to_origin(command):
"""Test that the command pushes to the origin remote""" """Test that the command pushes to the origin remote"""
command.run() command.run()
def test_push_to_custom_remote(settings, command): def test_push_to_custom_remote(settings, command):
"""Test that the command pushes to a custom remote""" """Test that the command pushes to a custom remote"""
remote_path = settings.notebooks_root_path / "../remote" remote_path = settings.notebooks_root_path / "../remote"
command.repo.create_remote("custom", str(remote_path.resolve())) command.repo.create_remote("custom", str(remote_path.resolve()))
command.remotes = ["custom"]
command.run(remotes=["custom"]) command.run()

View file

@ -6,7 +6,8 @@ from halig.settings import Settings, load_from_file
def test_settings_from_env(settings: Settings, notebooks_root_path_envvar): def test_settings_from_env(settings: Settings, notebooks_root_path_envvar):
from_env_settings = Settings(recipient_paths=settings.recipient_paths, identity_paths=settings.identity_paths) # type: ignore[call-arg] from_env_settings = Settings(recipient_paths=settings.recipient_paths,
identity_paths=settings.identity_paths) # type: ignore[call-arg]
assert from_env_settings.notebooks_root_path == settings.notebooks_root_path assert from_env_settings.notebooks_root_path == settings.notebooks_root_path
@ -29,3 +30,10 @@ def test_load_from_non_existing_file_path_raises_file_not_found_error(halig_conf
file = halig_config_path / "some_invalid_file.yml" file = halig_config_path / "some_invalid_file.yml"
with pytest.raises(FileNotFoundError, match=f"File {file} does not exist"): with pytest.raises(FileNotFoundError, match=f"File {file} does not exist"):
load_from_file(file) load_from_file(file)
def test_settings_identity_paths_is_not_list_is_converted(settings):
s = Settings(identity_paths=settings.identity_paths[0], recipient_paths=settings.recipient_paths[0],
notebooks_root_path=settings.notebooks_root_path)
assert s.identity_paths == [settings.identity_paths[0]]
assert s.recipient_paths == [settings.recipient_paths[0]]