WebHook broker that accepts notifications from multiple platforms and performs simple actions in response
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

main.py 3.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import hashlib
  2. import jenkins
  3. import requests
  4. import os
  5. from bs4 import BeautifulSoup
  6. from flask import Flask, abort
  7. BASE_URL = os.environ["LAS_BASE_URL"]
  8. SECRET = os.environ["LAS_SECRET"]
  9. jenkins_server = jenkins.Jenkins(
  10. os.environ["LAS_JENKINS_URL"],
  11. username=os.environ["LAS_JENKINS_USER"],
  12. password=os.environ["LAS_JENKINS_PASSWORD"],
  13. )
  14. def get_hook_key(service, identifier):
  15. nonce = (service + SECRET + identifier).encode("ascii")
  16. return hashlib.sha256(nonce).hexdigest()
  17. def get_hook_url(service, identifier):
  18. return f"{BASE_URL}hooks/{service}/{identifier}/{get_hook_key(service, identifier)}"
  19. def get_jenkins_jobs():
  20. for job in jenkins_server.get_all_jobs():
  21. config = BeautifulSoup(
  22. jenkins_server.get_job_config(job["fullname"]), features="xml"
  23. )
  24. for git_config in config.find_all("scm", class_="hudson.plugins.git.GitSCM"):
  25. branch_spec = git_config.find("branches").find("name").text
  26. yield job["fullname"], branch_spec, git_config.find("url").text
  27. def gitea_request(method, api_path, **kwargs):
  28. if "params" not in kwargs:
  29. kwargs["params"] = {}
  30. kwargs["params"]["access_token"] = os.environ["LAS_GITEA_TOKEN"]
  31. return requests.request(
  32. method, f"{os.environ['LAS_GITEA_URL']}api/v1/{api_path}", **kwargs
  33. )
  34. def maybe_install_gitea_hook(project):
  35. hook_url = get_hook_url("gitea", project)
  36. path = f"repos/{project}/hooks"
  37. hooks = gitea_request("get", path).json()
  38. if hook_url not in [hook["config"]["url"] for hook in hooks]:
  39. body = {
  40. "active": True,
  41. "config": {"content_type": "json", "url": hook_url},
  42. "events": [
  43. "create",
  44. "delete",
  45. "fork",
  46. "push",
  47. "issues",
  48. "issue_comment",
  49. "pull_request",
  50. "repository",
  51. "release",
  52. ],
  53. "type": "gitea",
  54. }
  55. gitea_request("post", path, json=body).json()
  56. def get_gitea_repos():
  57. repos = gitea_request("get", f"user/repos").json()
  58. for repo in repos:
  59. maybe_install_gitea_hook(repo["full_name"])
  60. yield repo["full_name"], repo["ssh_url"], repo["clone_url"]
  61. repos = dict((name, [ssh, clone]) for name, ssh, clone in get_gitea_repos())
  62. jobs = list(get_jenkins_jobs())
  63. app = Flask(__name__)
  64. @app.route("/")
  65. def handle_index():
  66. return app.send_static_file("index.html")
  67. @app.route("/hooks/gitea/<path:repo>/<hash>", methods=["POST"])
  68. def handle_hook_gitea(repo, hash):
  69. app.logger.info(f"Received hook for repo {repo} with has {hash}")
  70. expected_hash = get_hook_key("gitea", repo)
  71. if hash != expected_hash:
  72. app.logger.info(f"Hash mismatch: expected {expected_hash}")
  73. abort(403)
  74. if repo not in repos:
  75. app.logger.info(f"Repository not found. Known repos: {repos.keys()}")
  76. abort(404)
  77. urls = repos[repo]
  78. for name, spec, url in jobs:
  79. if url in urls:
  80. # TODO: Check branches
  81. app.logger.info(f"Found matching job: {name} with URL {url}")
  82. jenkins_server.build_job(name)
  83. return "", 204
  84. app.run("0.0.0.0")