diff --git a/CMakeLists.txt b/CMakeLists.txt index 940e418..ef6fb9b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,6 +78,8 @@ set(GIT2CPP_SRC ${GIT2CPP_SOURCE_DIR}/subcommand/revparse_subcommand.hpp ${GIT2CPP_SOURCE_DIR}/subcommand/rm_subcommand.cpp ${GIT2CPP_SOURCE_DIR}/subcommand/rm_subcommand.hpp + ${GIT2CPP_SOURCE_DIR}/subcommand/showref_subcommand.cpp + ${GIT2CPP_SOURCE_DIR}/subcommand/showref_subcommand.hpp ${GIT2CPP_SOURCE_DIR}/subcommand/stash_subcommand.cpp ${GIT2CPP_SOURCE_DIR}/subcommand/stash_subcommand.hpp ${GIT2CPP_SOURCE_DIR}/subcommand/status_subcommand.cpp diff --git a/src/main.cpp b/src/main.cpp index 712885e..c1ce04d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,6 +23,7 @@ #include "subcommand/revlist_subcommand.hpp" #include "subcommand/revparse_subcommand.hpp" #include "subcommand/rm_subcommand.hpp" +#include "subcommand/showref_subcommand.hpp" #include "subcommand/stash_subcommand.hpp" #include "subcommand/status_subcommand.hpp" #include "subcommand/tag_subcommand.hpp" @@ -63,6 +64,7 @@ int main(int argc, char** argv) rm_subcommand rm(lg2_obj, app); stash_subcommand stash(lg2_obj, app); tag_subcommand tag(lg2_obj, app); + showref_subcommand showref(lg2_obj, app); app.require_subcommand(/* min */ 0, /* max */ 1); diff --git a/src/subcommand/showref_subcommand.cpp b/src/subcommand/showref_subcommand.cpp new file mode 100644 index 0000000..346acac --- /dev/null +++ b/src/subcommand/showref_subcommand.cpp @@ -0,0 +1,31 @@ +#include "showref_subcommand.hpp" + +#include + +#include "../wrapper/repository_wrapper.hpp" + +showref_subcommand::showref_subcommand(const libgit2_object&, CLI::App& app) +{ + auto* sub = app.add_subcommand("show-ref", "List references in a local repository"); + + sub->callback( + [this]() + { + this->run(); + } + ); +}; + +void showref_subcommand::run() +{ + auto directory = get_current_git_path(); + auto repo = repository_wrapper::open(directory); + + auto repo_refs = repo.refs_list(); + + for (auto r : repo_refs) + { + git_oid oid = repo.ref_name_to_id(r); + std::cout << oid_to_hex(oid) << " " << r << std::endl; + } +} diff --git a/src/subcommand/showref_subcommand.hpp b/src/subcommand/showref_subcommand.hpp new file mode 100644 index 0000000..20af21e --- /dev/null +++ b/src/subcommand/showref_subcommand.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include + +#include "../utils/common.hpp" + +class showref_subcommand +{ +public: + + explicit showref_subcommand(const libgit2_object&, CLI::App& app); + void run(); + +private: +}; diff --git a/src/wrapper/repository_wrapper.hpp b/src/wrapper/repository_wrapper.hpp index f365401..1c5899e 100644 --- a/src/wrapper/repository_wrapper.hpp +++ b/src/wrapper/repository_wrapper.hpp @@ -6,6 +6,7 @@ #include +#include "../utils/common.hpp" #include "../utils/git_exception.hpp" #include "../wrapper/annotated_commit_wrapper.hpp" #include "../wrapper/branch_wrapper.hpp" diff --git a/test/test_fetch.py b/test/test_fetch.py index 4510875..f59ad7e 100644 --- a/test/test_fetch.py +++ b/test/test_fetch.py @@ -1,6 +1,7 @@ -import pytest import subprocess +import pytest + @pytest.mark.parametrize("protocol", ["http", "https"]) def test_fetch_private_repo(git2cpp_path, tmp_path, run_in_tmp_path, private_test_repo, protocol): diff --git a/test/test_showref.py b/test/test_showref.py new file mode 100644 index 0000000..9e08b84 --- /dev/null +++ b/test/test_showref.py @@ -0,0 +1,48 @@ +import re +import subprocess + + +def test_showref_list(repo_init_with_commit, git2cpp_path, tmp_path): + """`show-ref` lists the repository references (heads present after init+commit).""" + cmd = [git2cpp_path, "show-ref"] + p = subprocess.run(cmd, capture_output=True, cwd=tmp_path, text=True) + assert p.returncode == 0 + # repo_init_with_commit in conftest creates the branch "main" + assert "refs/heads/main" in p.stdout + + +def test_showref_includes_tag(repo_init_with_commit, git2cpp_path, tmp_path): + """A created tag appears in show-ref output as refs/tags/.""" + # create a lightweight tag using the CLI under test + subprocess.run([git2cpp_path, "tag", "v1.0"], cwd=tmp_path, check=True) + + p = subprocess.run([git2cpp_path, "show-ref"], capture_output=True, cwd=tmp_path, text=True) + assert p.returncode == 0 + assert "refs/tags/v1.0" in p.stdout + + +def test_showref_line_format(repo_init_with_commit, git2cpp_path, tmp_path): + """Each line of show-ref is: <40-hex-oid> .""" + p = subprocess.run([git2cpp_path, "show-ref"], capture_output=True, cwd=tmp_path, text=True) + assert p.returncode == 0 + print(p.stdout) + + hex_re = re.compile(r"^[0-9a-f]{40}$") + for line in p.stdout.splitlines(): + line = line.strip() + if not line: + continue + parts = line.split() + # Expect at least two tokens: oid and refname + assert len(parts) >= 2 + oid, refname = parts[0], parts[1] + assert hex_re.match(oid), f"OID not a 40-char hex: {oid!r}" + assert refname.startswith("refs/"), f"Refname does not start with refs/: {refname!r}" + + +def test_showref_nogit(git2cpp_path, tmp_path): + """Running show-ref outside a repository returns an error and non-zero exit.""" + cmd = [git2cpp_path, "show-ref"] + p = subprocess.run(cmd, capture_output=True, cwd=tmp_path, text=True) + assert p.returncode != 0 + assert "error: could not find repository at" in p.stderr