pagure_hook.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. #!/usr/bin/env python
  2. """Pagure specific hook to add comment on issues if the commits fixes or
  3. relates to an issue.
  4. """
  5. from __future__ import print_function, unicode_literals
  6. import logging
  7. import os
  8. import sys
  9. import pygit2
  10. from sqlalchemy.exc import SQLAlchemyError
  11. if 'PAGURE_CONFIG' not in os.environ \
  12. and os.path.exists('/etc/pagure/pagure.cfg'):
  13. os.environ['PAGURE_CONFIG'] = '/etc/pagure/pagure.cfg'
  14. import pagure.config # noqa: E402
  15. import pagure.exceptions # noqa: E402
  16. import pagure.lib.link # noqa: E402
  17. _log = logging.getLogger(__name__)
  18. _config = pagure.config.config
  19. abspath = os.path.abspath(os.environ['GIT_DIR'])
  20. def generate_revision_change_log(new_commits_list):
  21. print('Detailed log of new commits:\n\n')
  22. commitid = None
  23. for line in pagure.lib.git.read_git_lines(
  24. ['log', '--no-walk'] + new_commits_list + ['--'], abspath):
  25. if line.startswith('commit'):
  26. commitid = line.split('commit ')[-1]
  27. line = line.strip()
  28. session = pagure.lib.create_session(_config['DB_URL'])
  29. print('*', line)
  30. for relation in pagure.lib.link.get_relation(
  31. session,
  32. pagure.lib.git.get_repo_name(abspath),
  33. pagure.lib.git.get_username(abspath),
  34. pagure.lib.git.get_repo_namespace(abspath),
  35. line,
  36. 'fixes',
  37. include_prs=True):
  38. if _config.get('HOOK_DEBUG', False):
  39. print(commitid, relation)
  40. fixes_relation(commitid, relation, session,
  41. _config.get('APP_URL'))
  42. for issue in pagure.lib.link.get_relation(
  43. session,
  44. pagure.lib.git.get_repo_name(abspath),
  45. pagure.lib.git.get_username(abspath),
  46. pagure.lib.git.get_repo_namespace(abspath),
  47. line,
  48. 'relates'):
  49. if _config.get('HOOK_DEBUG', False):
  50. print(commitid, issue)
  51. relates_commit(commitid, issue, session, _config.get('APP_URL'))
  52. session.close()
  53. def relates_commit(commitid, issue, session, app_url=None):
  54. ''' Add a comment to an issue that this commit relates to it. '''
  55. url = '../%s' % commitid[:8]
  56. if app_url:
  57. if app_url.endswith('/'):
  58. app_url = app_url[:-1]
  59. project = issue.project.fullname
  60. if issue.project.is_fork:
  61. project = 'fork/%s' % project
  62. url = '%s/%s/c/%s' % (app_url, project, commitid[:8])
  63. comment = ''' Commit [%s](%s) relates to this ticket''' % (
  64. commitid[:8], url)
  65. user = os.environ.get(
  66. 'GL_USER', pagure.lib.git.get_author_email(commitid, abspath))
  67. try:
  68. pagure.lib.add_issue_comment(
  69. session,
  70. issue=issue,
  71. comment=comment,
  72. user=user,
  73. ticketfolder=_config['TICKETS_FOLDER'],
  74. )
  75. session.commit()
  76. except pagure.exceptions.PagureException as err:
  77. print(err)
  78. except SQLAlchemyError as err: # pragma: no cover
  79. session.rollback()
  80. _log.exception(err)
  81. def fixes_relation(commitid, relation, session, app_url=None):
  82. ''' Add a comment to an issue or PR that this commit fixes it and update
  83. the status if the commit is in the master branch. '''
  84. url = '../c/%s' % commitid[:8]
  85. if app_url:
  86. if app_url.endswith('/'):
  87. app_url = app_url[:-1]
  88. project = relation.project.fullname
  89. if relation.project.is_fork:
  90. project = 'fork/%s' % project
  91. url = '%s/%s/c/%s' % (app_url, project, commitid[:8])
  92. comment = ''' Commit [%s](%s) fixes this %s''' % (
  93. commitid[:8], url, relation.isa)
  94. user = os.environ.get(
  95. 'GL_USER', pagure.lib.git.get_author_email(commitid, abspath))
  96. try:
  97. if relation.isa == 'issue':
  98. pagure.lib.add_issue_comment(
  99. session,
  100. issue=relation,
  101. comment=comment,
  102. user=user,
  103. ticketfolder=_config['TICKETS_FOLDER'],
  104. )
  105. elif relation.isa == 'pull-request':
  106. pagure.lib.add_pull_request_comment(
  107. session,
  108. request=relation,
  109. commit=None,
  110. tree_id=None,
  111. filename=None,
  112. row=None,
  113. comment=comment,
  114. user=user,
  115. requestfolder=_config['REQUESTS_FOLDER'],
  116. )
  117. session.commit()
  118. except pagure.exceptions.PagureException as err:
  119. print(err)
  120. except SQLAlchemyError as err: # pragma: no cover
  121. session.rollback()
  122. _log.exception(err)
  123. try:
  124. if relation.isa == 'issue':
  125. pagure.lib.edit_issue(
  126. session,
  127. relation,
  128. ticketfolder=_config['TICKETS_FOLDER'],
  129. user=user,
  130. status='Closed', close_status='Fixed')
  131. elif relation.isa == 'pull-request':
  132. pagure.lib.close_pull_request(
  133. session,
  134. relation,
  135. requestfolder=_config['REQUESTS_FOLDER'],
  136. user=user,
  137. merged=True)
  138. session.commit()
  139. except pagure.exceptions.PagureException as err:
  140. print(err)
  141. except SQLAlchemyError as err: # pragma: no cover
  142. session.rollback()
  143. print('ERROR', err)
  144. _log.exception(err)
  145. def run_as_post_receive_hook():
  146. for line in sys.stdin:
  147. if _config.get('HOOK_DEBUG', False):
  148. print(line)
  149. (oldrev, newrev, refname) = line.strip().split(' ', 2)
  150. if _config.get('HOOK_DEBUG', False):
  151. print(' -- Old rev')
  152. print(oldrev)
  153. print(' -- New rev')
  154. print(newrev)
  155. print(' -- Ref name')
  156. print(refname)
  157. # Retrieve the default branch
  158. repo_obj = pygit2.Repository(abspath)
  159. default_branch = None
  160. if not repo_obj.is_empty and not repo_obj.head_is_unborn:
  161. default_branch = repo_obj.head.shorthand
  162. # Skip all branch but the default one
  163. refname = refname.replace('refs/heads/', '')
  164. if refname != default_branch:
  165. continue
  166. if set(newrev) == set(['0']):
  167. print("Deleting a reference/branch, so we won't run the "
  168. "pagure hook")
  169. return
  170. generate_revision_change_log(
  171. pagure.lib.git.get_revs_between(oldrev, newrev, abspath, refname))
  172. if _config.get('HOOK_DEBUG', False):
  173. print('ns :', pagure.lib.git.get_repo_namespace(abspath))
  174. print('repo:', pagure.lib.git.get_repo_name(abspath))
  175. print('user:', pagure.lib.git.get_username(abspath))
  176. def main(args):
  177. run_as_post_receive_hook()
  178. if __name__ == '__main__':
  179. main(sys.argv[1:])