From 3d354bcbc82918adba66edba6d1689b558d35d7d Mon Sep 17 00:00:00 2001 From: d33bs Date: Sun, 27 Oct 2024 15:21:08 -0600 Subject: [PATCH 1/3] add measure for repo default branch as not master --- src/almanack/metrics/data.py | 23 ++++++++++++++++ src/almanack/metrics/metrics.yml | 7 +++++ tests/data/almanack/repo_setup/create_repo.py | 17 ++++++++---- tests/metrics/test_data.py | 26 +++++++++++++++++++ 4 files changed, 68 insertions(+), 5 deletions(-) diff --git a/src/almanack/metrics/data.py b/src/almanack/metrics/data.py index 01d282c7..f176b167 100644 --- a/src/almanack/metrics/data.py +++ b/src/almanack/metrics/data.py @@ -166,6 +166,28 @@ def is_citable(repo: pygit2.Repository) -> bool: return False +def default_branch_is_not_master(repo: pygit2.Repository) -> bool: + """ + Checks if the default branch of the specified + repository is "master". + + Args: + repo (Repository): + A pygit2.Repository object representing the Git repository. + + Returns: + bool: + True if the default branch is "master", False otherwise. + """ + # Get the symbolic reference to HEAD, which should point to the default branch + head_ref = repo.head.shorthand + + print(head_ref) + + # Check if the default branch is not "master" + return head_ref != "master" + + def compute_repo_data(repo_path: str) -> None: """ Computes comprehensive data for a GitHub repository. @@ -235,6 +257,7 @@ def compute_repo_data(repo_path: str) -> None: expected_file_name="license", ), "is-citable": is_citable(repo=repo), + "default-branch-not-master": default_branch_is_not_master(repo=repo), "normalized_total_entropy": normalized_total_entropy, "file_level_entropy": file_entropy, } diff --git a/src/almanack/metrics/metrics.yml b/src/almanack/metrics/metrics.yml index f7f85975..ee60bffe 100644 --- a/src/almanack/metrics/metrics.yml +++ b/src/almanack/metrics/metrics.yml @@ -59,6 +59,13 @@ metrics: description: >- Boolean value indicating the presence of a CITATION file or some other means of indicating how to cite the work. + - name: "default-branch-not-master" + id: "SGA-GL-0006" + result-type: "bool" + result-data-key: "default-branch-not-master" + description: >- + Boolean value indicating that the repo uses a + default branch name besides 'master'. - name: "agg-info-entropy" id: "SGA-VS-0001" result-type: "float" diff --git a/tests/data/almanack/repo_setup/create_repo.py b/tests/data/almanack/repo_setup/create_repo.py index 58c335dc..b652abd4 100644 --- a/tests/data/almanack/repo_setup/create_repo.py +++ b/tests/data/almanack/repo_setup/create_repo.py @@ -155,13 +155,20 @@ def create_entropy_repositories(base_path: pathlib.Path) -> None: commit_changes(repo_path, "Commit with added lines of code") -def repo_setup(repo_path: pathlib.Path, files: dict) -> pygit2.Repository: +def repo_setup( + repo_path: pathlib.Path, files: dict, branch_name: str = "main" +) -> pygit2.Repository: """ Set up a temporary repository with specified files. Args: - tmp_path (Path): The temporary directory where the repo will be created. - files (dict): A dictionary where keys are filenames and values are their content. + tmp_path (Path): + The temporary directory where the repo will be created. + files (dict): + A dictionary where keys are filenames and values are their content. + branch_name (str): + A string with the name of the branch which will be used for + committing changes. Defaults to "main". Returns: pygit2.Repository: The initialized repository with files. @@ -185,7 +192,7 @@ def repo_setup(repo_path: pathlib.Path, files: dict) -> pygit2.Repository: tree = repo.index.write_tree() repo.create_commit( - "refs/heads/main", + f"refs/heads/{branch_name}", author, author, "Initial commit with setup files", @@ -194,6 +201,6 @@ def repo_setup(repo_path: pathlib.Path, files: dict) -> pygit2.Repository: ) # Set the head to the main branch - repo.set_head("refs/heads/main") + repo.set_head(f"refs/heads/{branch_name}") return repo diff --git a/tests/metrics/test_data.py b/tests/metrics/test_data.py index 430a6845..d176d84a 100644 --- a/tests/metrics/test_data.py +++ b/tests/metrics/test_data.py @@ -14,6 +14,7 @@ from almanack.metrics.data import ( METRICS_TABLE, compute_repo_data, + default_branch_is_not_master, file_exists_in_repo, get_table, is_citable, @@ -225,3 +226,28 @@ def test_is_citable(tmp_path, files, expected): repo = pygit2.Repository(str(repo_path)) assert is_citable(repo) == expected + + +def test_default_branch_is_not_master(tmp_path): + """ + Tests default_branch_is_not_master + """ + + # create paths for example repos + # (so they aren't in the same dir and overlapping) + pathlib.Path((example1 := tmp_path / "example1")).mkdir() + pathlib.Path((example2 := tmp_path / "example2")).mkdir() + + # test with a master branch + repo = repo_setup( + repo_path=example1, files={"example.txt": "example"}, branch_name="master" + ) + + assert not default_branch_is_not_master(repo) + + # test with a main branch + repo = repo_setup( + repo_path=example2, files={"example.txt": "example"}, branch_name="main" + ) + + assert default_branch_is_not_master(repo) From 6d28d22428f1340edf1679de96870c082ace10cd Mon Sep 17 00:00:00 2001 From: d33bs Date: Sun, 27 Oct 2024 15:25:16 -0600 Subject: [PATCH 2/3] remove print --- src/almanack/metrics/data.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/almanack/metrics/data.py b/src/almanack/metrics/data.py index f176b167..44cb7959 100644 --- a/src/almanack/metrics/data.py +++ b/src/almanack/metrics/data.py @@ -182,8 +182,6 @@ def default_branch_is_not_master(repo: pygit2.Repository) -> bool: # Get the symbolic reference to HEAD, which should point to the default branch head_ref = repo.head.shorthand - print(head_ref) - # Check if the default branch is not "master" return head_ref != "master" From 0be532e5f2a8412591baca17e42a64d5856a1289 Mon Sep 17 00:00:00 2001 From: d33bs Date: Mon, 28 Oct 2024 17:17:58 -0600 Subject: [PATCH 3/3] update to check remote head and related --- src/almanack/metrics/data.py | 15 +++++++--- tests/metrics/test_data.py | 56 ++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 4 deletions(-) diff --git a/src/almanack/metrics/data.py b/src/almanack/metrics/data.py index 72556fe0..29bd17df 100644 --- a/src/almanack/metrics/data.py +++ b/src/almanack/metrics/data.py @@ -179,11 +179,18 @@ def default_branch_is_not_master(repo: pygit2.Repository) -> bool: bool: True if the default branch is "master", False otherwise. """ - # Get the symbolic reference to HEAD, which should point to the default branch - head_ref = repo.head.shorthand + # Access the "refs/remotes/origin/HEAD" reference to find the default branch + try: + # check whether remote head and remote master are the same + return ( + repo.references.get("refs/remotes/origin/HEAD").target + == repo.references.get("refs/remotes/origin/master").target + ) - # Check if the default branch is not "master" - return head_ref != "master" + except AttributeError: + # If "refs/remotes/origin/HEAD" or "refs/remotes/origin/master" doesn't exist, + # fall back to the local HEAD check + return repo.head.shorthand != "master" def compute_repo_data(repo_path: str) -> None: diff --git a/tests/metrics/test_data.py b/tests/metrics/test_data.py index f8c2c5a8..aa80a360 100644 --- a/tests/metrics/test_data.py +++ b/tests/metrics/test_data.py @@ -236,6 +236,9 @@ def test_default_branch_is_not_master(tmp_path): # (so they aren't in the same dir and overlapping) pathlib.Path((example1 := tmp_path / "example1")).mkdir() pathlib.Path((example2 := tmp_path / "example2")).mkdir() + pathlib.Path((example3 := tmp_path / "example3")).mkdir() + pathlib.Path((example4 := tmp_path / "example4")).mkdir() + pathlib.Path((example5 := tmp_path / "example5")).mkdir() # test with a master branch repo = repo_setup( @@ -250,3 +253,56 @@ def test_default_branch_is_not_master(tmp_path): ) assert default_branch_is_not_master(repo) + + # test with a simulated remote head pointed at remote master + repo = repo_setup( + repo_path=example3, files={"example.txt": "example"}, branch_name="main" + ) + + # simulate having a remote head pointed at a branch named master + repo.create_reference( + "refs/remotes/origin/master", repo[repo.head.target].id, force=True + ) + repo.create_reference( + "refs/remotes/origin/HEAD", "refs/remotes/origin/master", force=True + ) + + # create a local branch which is named something besides master + repo.create_branch("something_else", repo[repo.head.target]) + repo.set_head("refs/heads/something_else") + + assert not default_branch_is_not_master(repo) + + # test with a simulated remote head pointed at remote main + repo = repo_setup( + repo_path=example4, files={"example.txt": "example"}, branch_name="main" + ) + + # simulate having a remote head pointed at a branch named master + repo.create_reference( + "refs/remotes/origin/main", repo[repo.head.target].id, force=True + ) + repo.create_reference( + "refs/remotes/origin/HEAD", "refs/remotes/origin/main", force=True + ) + + # create a local branch which is named something besides master + repo.create_branch("something_else", repo[repo.head.target]) + repo.set_head("refs/heads/something_else") + + assert default_branch_is_not_master(repo) + + # test with a simulated remote head pointed at remote main but with local branch master + repo = repo_setup( + repo_path=example5, files={"example.txt": "example"}, branch_name="master" + ) + + # simulate having a remote head pointed at a branch named master + repo.create_reference( + "refs/remotes/origin/main", repo[repo.head.target].id, force=True + ) + repo.create_reference( + "refs/remotes/origin/HEAD", "refs/remotes/origin/main", force=True + ) + + assert not default_branch_is_not_master(repo)