From 1e1347270405d4e7b3141945ba0edee09cd479a7 Mon Sep 17 00:00:00 2001 From: subhajitlucky Date: Tue, 12 May 2026 19:39:31 +0530 Subject: [PATCH 1/2] fix: handle missing active milestones --- gitHappens.py | 4 ++- tests/__init__.py | 1 + tests/test_milestones_empty.py | 58 ++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 tests/__init__.py create mode 100644 tests/test_milestones_empty.py diff --git a/gitHappens.py b/gitHappens.py index 27d47f3..fb2ba8e 100755 --- a/gitHappens.py +++ b/gitHappens.py @@ -102,6 +102,8 @@ def list_milestones(current=False): if start_date and due_date and start_date <= today and due_date >= today: active_milestones.append(milestone) active_milestones.sort(key=lambda x: x['due_date']) + if not active_milestones: + return None return active_milestones[0] return milestones @@ -842,4 +844,4 @@ def main(): startIssueCreation(project_id, title, milestone, epic, iteration, selectedSettings, onlyIssue) if __name__ == '__main__': - main() \ No newline at end of file + main() diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1 @@ + diff --git a/tests/test_milestones_empty.py b/tests/test_milestones_empty.py new file mode 100644 index 0000000..6725b46 --- /dev/null +++ b/tests/test_milestones_empty.py @@ -0,0 +1,58 @@ +import importlib.util +import json +import sys +import types +import unittest +from pathlib import Path +from unittest import mock + + +def load_githappens_module(): + root = Path(__file__).resolve().parents[1] + config_dir = root / "configs" + config_dir.mkdir(exist_ok=True) + (config_dir / "config.ini").write_text( + "[DEFAULT]\n" + "base_url=https://gitlab.example\n" + "group_id=42\n" + "custom_template=Custom\n" + "GITLAB_TOKEN=test-token\n" + "squash_commits=true\n" + "delete_branch_after_merge=true\n", + encoding="utf-8", + ) + (config_dir / "templates.json").write_text( + '{"templates": [], "reviewers": []}', + encoding="utf-8", + ) + + sys.modules["inquirer"] = types.SimpleNamespace( + prompt=mock.Mock(), + Text=lambda *args, **kwargs: ("Text", args, kwargs), + List=lambda *args, **kwargs: ("List", args, kwargs), + Checkbox=lambda *args, **kwargs: ("Checkbox", args, kwargs), + ) + + spec = importlib.util.spec_from_file_location("gitHappens_under_test", root / "gitHappens.py") + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module + + +class EmptyMilestonesTest(unittest.TestCase): + def test_current_milestone_returns_none_when_no_active_milestone_exists(self): + git_happens = load_githappens_module() + result = mock.Mock() + result.stdout = json.dumps([ + {"id": 1, "title": "Past", "start_date": "2024-01-01", "due_date": "2024-01-31"}, + {"id": 2, "title": "Future", "start_date": "2099-01-01", "due_date": "2099-01-31"}, + ]).encode() + + with mock.patch.object(git_happens.subprocess, "run", return_value=result): + milestone = git_happens.list_milestones(current=True) + + self.assertIsNone(milestone) + + +if __name__ == "__main__": + unittest.main() From d8dbca25f31cd5ef28611b7e732a677139525bf9 Mon Sep 17 00:00:00 2001 From: subhajitlucky Date: Tue, 12 May 2026 19:50:37 +0530 Subject: [PATCH 2/2] fix: omit missing milestone id --- gitHappens.py | 6 +++++- tests/test_milestones_empty.py | 38 +++++++++++++++++++++++++++------- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/gitHappens.py b/gitHappens.py index fb2ba8e..28d945c 100755 --- a/gitHappens.py +++ b/gitHappens.py @@ -194,6 +194,10 @@ def get_milestone(manual): milestone = list_milestones(True) # select active for today return milestone +def get_milestone_id(manual): + milestone = get_milestone(manual) + return milestone['id'] if milestone else False + def get_iteration(manual): if manual: iterations = list_iterations() @@ -822,7 +826,7 @@ def main(): milestone = False if not args.no_milestone: - milestone = get_milestone(args.milestone)['id'] + milestone = get_milestone_id(args.milestone) iteration = False if not args.no_iteration: diff --git a/tests/test_milestones_empty.py b/tests/test_milestones_empty.py index 6725b46..f25737d 100644 --- a/tests/test_milestones_empty.py +++ b/tests/test_milestones_empty.py @@ -11,7 +11,12 @@ def load_githappens_module(): root = Path(__file__).resolve().parents[1] config_dir = root / "configs" config_dir.mkdir(exist_ok=True) - (config_dir / "config.ini").write_text( + config_path = config_dir / "config.ini" + templates_path = config_dir / "templates.json" + previous_config = config_path.read_text(encoding="utf-8") if config_path.exists() else None + previous_templates = templates_path.read_text(encoding="utf-8") if templates_path.exists() else None + + config_path.write_text( "[DEFAULT]\n" "base_url=https://gitlab.example\n" "group_id=42\n" @@ -21,22 +26,33 @@ def load_githappens_module(): "delete_branch_after_merge=true\n", encoding="utf-8", ) - (config_dir / "templates.json").write_text( + templates_path.write_text( '{"templates": [], "reviewers": []}', encoding="utf-8", ) - sys.modules["inquirer"] = types.SimpleNamespace( + inquirer_stub = types.SimpleNamespace( prompt=mock.Mock(), Text=lambda *args, **kwargs: ("Text", args, kwargs), List=lambda *args, **kwargs: ("List", args, kwargs), Checkbox=lambda *args, **kwargs: ("Checkbox", args, kwargs), ) - spec = importlib.util.spec_from_file_location("gitHappens_under_test", root / "gitHappens.py") - module = importlib.util.module_from_spec(spec) - spec.loader.exec_module(module) - return module + try: + with mock.patch.dict(sys.modules, {"inquirer": inquirer_stub}): + spec = importlib.util.spec_from_file_location("gitHappens_under_test", root / "gitHappens.py") + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module + finally: + if previous_config is None: + config_path.unlink(missing_ok=True) + else: + config_path.write_text(previous_config, encoding="utf-8") + if previous_templates is None: + templates_path.unlink(missing_ok=True) + else: + templates_path.write_text(previous_templates, encoding="utf-8") class EmptyMilestonesTest(unittest.TestCase): @@ -53,6 +69,14 @@ def test_current_milestone_returns_none_when_no_active_milestone_exists(self): self.assertIsNone(milestone) + def test_missing_current_milestone_omits_milestone_id(self): + git_happens = load_githappens_module() + + with mock.patch.object(git_happens, "get_milestone", return_value=None): + milestone_id = git_happens.get_milestone_id(manual=False) + + self.assertFalse(milestone_id) + if __name__ == "__main__": unittest.main()