test_pr_title_escaping.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. from openhands.resolver.github_issue import GithubIssue
  2. from openhands.resolver.send_pull_request import make_commit
  3. import os
  4. import tempfile
  5. import subprocess
  6. def test_commit_message_with_quotes():
  7. # Create a temporary directory and initialize git repo
  8. with tempfile.TemporaryDirectory() as temp_dir:
  9. subprocess.run(["git", "init", temp_dir], check=True)
  10. # Create a test file and add it to git
  11. test_file = os.path.join(temp_dir, "test.txt")
  12. with open(test_file, "w") as f:
  13. f.write("test content")
  14. subprocess.run(["git", "-C", temp_dir, "add", "test.txt"], check=True)
  15. # Create a test issue with problematic title
  16. issue = GithubIssue(
  17. owner="test-owner",
  18. repo="test-repo",
  19. number=123,
  20. title="Issue with 'quotes' and \"double quotes\" and <class 'ValueError'>",
  21. body="Test body",
  22. labels=[],
  23. assignees=[],
  24. state="open",
  25. created_at="2024-01-01T00:00:00Z",
  26. updated_at="2024-01-01T00:00:00Z",
  27. closed_at=None,
  28. head_branch=None,
  29. thread_ids=None,
  30. )
  31. # Make the commit
  32. make_commit(temp_dir, issue, "issue")
  33. # Get the commit message
  34. result = subprocess.run(
  35. ["git", "-C", temp_dir, "log", "-1", "--pretty=%B"],
  36. capture_output=True,
  37. text=True,
  38. check=True,
  39. )
  40. commit_msg = result.stdout.strip()
  41. # The commit message should contain the quotes without excessive escaping
  42. expected = "Fix issue #123: Issue with 'quotes' and \"double quotes\" and <class 'ValueError'>"
  43. assert commit_msg == expected, f"Expected: {expected}\nGot: {commit_msg}"
  44. def test_pr_title_with_quotes(monkeypatch):
  45. # Mock requests.post to avoid actual API calls
  46. class MockResponse:
  47. def __init__(self, status_code=201):
  48. self.status_code = status_code
  49. self.text = ""
  50. def json(self):
  51. return {"html_url": "https://github.com/test/test/pull/1"}
  52. def raise_for_status(self):
  53. pass
  54. def mock_post(*args, **kwargs):
  55. # Verify that the PR title is not over-escaped
  56. data = kwargs.get("json", {})
  57. title = data.get("title", "")
  58. expected = "Fix issue #123: Issue with 'quotes' and \"double quotes\" and <class 'ValueError'>"
  59. assert (
  60. title == expected
  61. ), f"PR title was incorrectly escaped.\nExpected: {expected}\nGot: {title}"
  62. return MockResponse()
  63. class MockGetResponse:
  64. def __init__(self, status_code=200):
  65. self.status_code = status_code
  66. self.text = ""
  67. def json(self):
  68. return {"default_branch": "main"}
  69. def raise_for_status(self):
  70. pass
  71. monkeypatch.setattr("requests.post", mock_post)
  72. monkeypatch.setattr("requests.get", lambda *args, **kwargs: MockGetResponse())
  73. monkeypatch.setattr(
  74. "openhands.resolver.send_pull_request.branch_exists",
  75. lambda *args, **kwargs: False,
  76. )
  77. # Mock subprocess.run to avoid actual git commands
  78. original_run = subprocess.run
  79. def mock_run(*args, **kwargs):
  80. print(f"Running command: {args[0] if args else kwargs.get('args', [])}")
  81. if isinstance(args[0], list) and args[0][0] == "git":
  82. if "push" in args[0]:
  83. return subprocess.CompletedProcess(
  84. args[0], returncode=0, stdout="", stderr=""
  85. )
  86. return original_run(*args, **kwargs)
  87. return original_run(*args, **kwargs)
  88. monkeypatch.setattr("subprocess.run", mock_run)
  89. # Create a temporary directory and initialize git repo
  90. with tempfile.TemporaryDirectory() as temp_dir:
  91. print("Initializing git repo...")
  92. subprocess.run(["git", "init", temp_dir], check=True)
  93. # Add these lines to configure git
  94. subprocess.run(
  95. ["git", "-C", temp_dir, "config", "user.name", "Test User"], check=True
  96. )
  97. subprocess.run(
  98. ["git", "-C", temp_dir, "config", "user.email", "test@example.com"],
  99. check=True,
  100. )
  101. # Create a test file and add it to git
  102. test_file = os.path.join(temp_dir, "test.txt")
  103. with open(test_file, "w") as f:
  104. f.write("test content")
  105. print("Adding and committing test file...")
  106. subprocess.run(["git", "-C", temp_dir, "add", "test.txt"], check=True)
  107. subprocess.run(
  108. ["git", "-C", temp_dir, "commit", "-m", "Initial commit"], check=True
  109. )
  110. # Create a test issue with problematic title
  111. print("Creating test issue...")
  112. issue = GithubIssue(
  113. owner="test-owner",
  114. repo="test-repo",
  115. number=123,
  116. title="Issue with 'quotes' and \"double quotes\" and <class 'ValueError'>",
  117. body="Test body",
  118. labels=[],
  119. assignees=[],
  120. state="open",
  121. created_at="2024-01-01T00:00:00Z",
  122. updated_at="2024-01-01T00:00:00Z",
  123. closed_at=None,
  124. head_branch=None,
  125. thread_ids=None,
  126. )
  127. # Try to send a PR - this will fail if the title is incorrectly escaped
  128. print("Sending PR...")
  129. from openhands.resolver.send_pull_request import send_pull_request
  130. from openhands.core.config import LLMConfig
  131. send_pull_request(
  132. github_issue=issue,
  133. github_token="dummy-token",
  134. github_username="test-user",
  135. patch_dir=temp_dir,
  136. llm_config=LLMConfig(model="test-model", api_key="test-key"),
  137. pr_type="ready",
  138. )