rtd.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. # -*- coding: utf-8 -*-
  2. """
  3. (c) 2016 - Copyright Red Hat Inc
  4. Authors:
  5. Pierre-Yves Chibon <pingou@pingoured.fr>
  6. """
  7. from __future__ import absolute_import, unicode_literals
  8. import requests
  9. import sqlalchemy as sa
  10. import wtforms
  11. try:
  12. from flask_wtf import FlaskForm
  13. except ImportError:
  14. from flask_wtf import Form as FlaskForm
  15. from sqlalchemy.orm import backref, relation
  16. import pagure
  17. from pagure.hooks import BaseHook, BaseRunner
  18. from pagure.lib.model import BASE, Project
  19. _config = pagure.config.config
  20. class RtdTable(BASE):
  21. """Stores information about the pagure hook deployed on a project.
  22. Table -- hook_rtd
  23. """
  24. __tablename__ = "hook_rtd"
  25. id = sa.Column(sa.Integer, primary_key=True)
  26. project_id = sa.Column(
  27. sa.Integer,
  28. sa.ForeignKey("projects.id", onupdate="CASCADE", ondelete="CASCADE"),
  29. nullable=False,
  30. unique=True,
  31. index=True,
  32. )
  33. active = sa.Column(sa.Boolean, nullable=False, default=False)
  34. branches = sa.Column(sa.Text, nullable=True)
  35. api_url = sa.Column(sa.Text, nullable=False, default="")
  36. api_token = sa.Column(sa.Text, nullable=False, default="")
  37. project = relation(
  38. "Project",
  39. remote_side=[Project.id],
  40. backref=backref(
  41. "rtd_hook",
  42. cascade="delete, delete-orphan",
  43. single_parent=True,
  44. uselist=False,
  45. ),
  46. )
  47. class RtdForm(FlaskForm):
  48. """Form to configure the pagure hook."""
  49. api_url = wtforms.StringField(
  50. "URL endpoint used to trigger the builds",
  51. [wtforms.validators.Optional()],
  52. )
  53. api_token = wtforms.StringField(
  54. "API token provided by readthedocs", [wtforms.validators.Optional()]
  55. )
  56. branches = wtforms.StringField(
  57. "Restrict build to these branches only (comma separated)",
  58. [wtforms.validators.Optional()],
  59. )
  60. active = wtforms.BooleanField("Active", [wtforms.validators.Optional()])
  61. DESCRIPTION = """
  62. Git hook to trigger building documentation on the readthedocs.org service
  63. when a commit is pushed to the repository.
  64. If you specify one or more branches (using commas `,` to separate them) only
  65. pushes made to these branches will trigger a new build of the documentation.
  66. To set up this hook, you will need to log in to https://readthedocs.org/
  67. Go to your project's admin settings, and in the ``Integrations`` section
  68. add a new ``Generic API incoming webhook``.
  69. This will give you access to one URL and one API token, both of which you
  70. will have to provide below.
  71. """
  72. class RtdRunner(BaseRunner):
  73. @staticmethod
  74. def post_receive(session, username, project, repotype, repodir, changes):
  75. """Perform the RTD Post Receive hook.
  76. For arguments, see BaseRunner.runhook.
  77. """
  78. # Get the list of branches
  79. branches = [
  80. branch.strip() for branch in project.rtd_hook.branches.split(",")
  81. ]
  82. # Remove empty branches
  83. branches = [branch.strip() for branch in branches if branch]
  84. url = project.rtd_hook.api_url
  85. if not url:
  86. print(
  87. "No API url specified to trigger the build, please update "
  88. "the configuration"
  89. )
  90. if not project.rtd_hook.api_token:
  91. print(
  92. "No API token specified to trigger the build, please update "
  93. "the configuration"
  94. )
  95. for refname in changes:
  96. oldrev, newrev = changes[refname]
  97. if _config.get("HOOK_DEBUG", False):
  98. print("%s: %s -> %s" % (refname, oldrev, newrev))
  99. refname = refname.replace("refs/heads/", "")
  100. if branches:
  101. if refname in branches:
  102. print("Starting RTD build at %s" % (url))
  103. requests.post(
  104. url,
  105. data={
  106. "branches": refname,
  107. "token": project.rtd_hook.api_token,
  108. },
  109. timeout=60,
  110. )
  111. else:
  112. print("Starting RTD build at %s" % (url))
  113. requests.post(
  114. url,
  115. data={
  116. "branches": refname,
  117. "token": project.rtd_hook.api_token,
  118. },
  119. timeout=60,
  120. )
  121. class RtdHook(BaseHook):
  122. """Read The Doc hook."""
  123. name = "Read the Doc"
  124. description = DESCRIPTION
  125. form = RtdForm
  126. db_object = RtdTable
  127. runner = RtdRunner
  128. backref = "rtd_hook"
  129. form_fields = ["active", "api_url", "api_token", "branches"]