test_pr_title_escaping.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. import os
  2. import subprocess
  3. import tempfile
  4. from openhands.resolver.github_issue import GithubIssue
  5. from openhands.resolver.send_pull_request import make_commit
  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.core.config import LLMConfig
  130. from openhands.resolver.send_pull_request import send_pull_request
  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. )