get_mute_issues.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. import os
  2. import re
  3. import requests
  4. ORG_NAME = 'ydb-platform'
  5. PROJECT_ID = '45'
  6. query_template = """
  7. {
  8. organization(login: "%s") {
  9. projectV2(number: %s) {
  10. id
  11. title
  12. items(first: 100, after: %s) {
  13. nodes {
  14. content {
  15. ... on Issue {
  16. id
  17. title
  18. url
  19. state
  20. body
  21. createdAt
  22. }
  23. }
  24. fieldValues(first: 20) {
  25. nodes {
  26. ... on ProjectV2ItemFieldSingleSelectValue {
  27. field {
  28. ... on ProjectV2SingleSelectField {
  29. name
  30. }
  31. }
  32. name
  33. id
  34. updatedAt
  35. }
  36. ... on ProjectV2ItemFieldLabelValue {
  37. labels(first: 20) {
  38. nodes {
  39. id
  40. name
  41. }
  42. }
  43. }
  44. ... on ProjectV2ItemFieldTextValue {
  45. text
  46. id
  47. updatedAt
  48. creator {
  49. url
  50. }
  51. }
  52. ... on ProjectV2ItemFieldMilestoneValue {
  53. milestone {
  54. id
  55. }
  56. }
  57. ... on ProjectV2ItemFieldRepositoryValue {
  58. repository {
  59. id
  60. url
  61. }
  62. }
  63. }
  64. }
  65. }
  66. pageInfo {
  67. hasNextPage
  68. endCursor
  69. }
  70. }
  71. }
  72. }
  73. }
  74. """
  75. def run_query(query, headers):
  76. request = requests.post('https://api.github.com/graphql', json={'query': query}, headers=headers)
  77. if request.status_code == 200:
  78. return request.json()
  79. else:
  80. raise Exception(f"Query failed to run by returning code of {request.status_code}. {query}")
  81. def fetch_all_issues(org_name, project_id):
  82. issues = []
  83. has_next_page = True
  84. end_cursor = "null"
  85. while has_next_page:
  86. query = query_template % (org_name, project_id, end_cursor)
  87. GITHUB_TOKEN = os.environ["GITHUB_TOKEN"]
  88. headers = {"Authorization": f"Bearer {GITHUB_TOKEN}"}
  89. result = run_query(query, headers)
  90. if result:
  91. project_items = result['data']['organization']['projectV2']['items']
  92. issues.extend(project_items['nodes'])
  93. page_info = project_items['pageInfo']
  94. has_next_page = page_info['hasNextPage']
  95. end_cursor = f"\"{page_info['endCursor']}\"" if page_info['endCursor'] else "null"
  96. else:
  97. has_next_page = False
  98. return issues
  99. def parse_body(body):
  100. tests = []
  101. branches = []
  102. prepared_body = ''
  103. start_mute_list = "<!--mute_list_start-->"
  104. end_mute_list = "<!--mute_list_end-->"
  105. start_branch_list = "<!--branch_list_start-->"
  106. end_branch_list = "<!--branch_list_end-->"
  107. # tests
  108. if all(x in body for x in [start_mute_list, end_mute_list]):
  109. idx1 = body.find(start_mute_list)
  110. idx2 = body.find(end_mute_list)
  111. lines = body[idx1 + len(start_mute_list) + 1 : idx2].split('\n')
  112. else:
  113. if body.startswith('Mute:'):
  114. prepared_body = body.split('Mute:', 1)[1].strip()
  115. elif body.startswith('Mute'):
  116. prepared_body = body.split('Mute', 1)[1].strip()
  117. elif body.startswith('ydb'):
  118. prepared_body = body
  119. lines = prepared_body.split('**Add line to')[0].split('\n')
  120. tests = [line.strip() for line in lines if line.strip().startswith('ydb/')]
  121. # branch
  122. if all(x in body for x in [start_branch_list, end_branch_list]):
  123. idx1 = body.find(start_branch_list)
  124. idx2 = body.find(end_branch_list)
  125. branches = body[idx1 + len(start_branch_list) + 1 : idx2].split('\n')
  126. else:
  127. branches = ['main']
  128. return tests, branches
  129. def get_issues_and_tests_from_project(ORG_NAME, PROJECT_ID):
  130. issues = fetch_all_issues(ORG_NAME, PROJECT_ID)
  131. issues_prepared = {}
  132. for issue in issues:
  133. content = issue['content']
  134. if content:
  135. body = content['body']
  136. # for debug
  137. if content['id'] == 'I_kwDOGzZjoM6V3BoE':
  138. print(1)
  139. #
  140. tests, branches = parse_body(body)
  141. field_values = issue.get('fieldValues', {}).get('nodes', [])
  142. for field_value in field_values:
  143. field_name = field_value.get('field', {}).get('name', '').lower()
  144. if field_name == "status" and 'name' in field_value:
  145. status = field_value.get('name', 'N/A')
  146. status_updated = field_value.get('updatedAt', '1970-01-0901T00:00:01Z')
  147. elif field_name == "owner" and 'name' in field_value:
  148. owner = field_value.get('name', 'N/A')
  149. print(f"Issue ID: {content['id']}")
  150. print(f"Title: {content['title']}")
  151. print(f"URL: {content['url']}")
  152. print(f"State: {content['state']}")
  153. print(f"CreatedAt: {content['createdAt']}")
  154. print(f"Status: {status}")
  155. print(f"Status updated: {status_updated}")
  156. print(f"Owner: {owner}")
  157. print("Tests:")
  158. issues_prepared[content['id']] = {}
  159. issues_prepared[content['id']]['title'] = content['title']
  160. issues_prepared[content['id']]['url'] = content['url']
  161. issues_prepared[content['id']]['state'] = content['state']
  162. issues_prepared[content['id']]['createdAt'] = content['createdAt']
  163. issues_prepared[content['id']]['status_updated'] = status_updated
  164. issues_prepared[content['id']]['status'] = status
  165. issues_prepared[content['id']]['owner'] = owner
  166. issues_prepared[content['id']]['tests'] = []
  167. issues_prepared[content['id']]['branches'] = branches
  168. for test in tests:
  169. issues_prepared[content['id']]['tests'].append(test)
  170. print(f"- {test}")
  171. print('\n')
  172. return issues_prepared
  173. def get_muted_tests():
  174. issues = get_issues_and_tests_from_project(ORG_NAME, PROJECT_ID)
  175. muted_tests = {}
  176. for issue in issues:
  177. if issues[issue]["status"] == "Muted":
  178. for test in issues[issue]['tests']:
  179. if test not in muted_tests:
  180. muted_tests[test] = []
  181. muted_tests[test].append(
  182. {
  183. 'url': issues[issue]['url'],
  184. 'createdAt': issues[issue]['createdAt'],
  185. 'status_updated': issues[issue]['status_updated'],
  186. }
  187. )
  188. return muted_tests
  189. def main():
  190. if "GITHUB_TOKEN" not in os.environ:
  191. print("Error: Env variable GITHUB_TOKEN is missing, skipping")
  192. return 1
  193. get_muted_tests()
  194. if __name__ == "__main__":
  195. main()