You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

145 regels
3.9 KiB

  1. import json
  2. import os
  3. import re
  4. import shlex
  5. import subprocess
  6. import sys
  7. import time
  8. import urllib.request
  9. from functools import cache
  10. from urllib.error import HTTPError
  11. @cache
  12. def fetch_pr_data(pr_number, repo, endpoint=""):
  13. api_url = f"https://api.github.com/repos/{repo}/pulls/{pr_number}"
  14. if endpoint:
  15. api_url += f"/{endpoint}"
  16. res = req(api_url)
  17. return json.loads(res.read().decode("utf8"))
  18. def req(url):
  19. "Simple resilient request call to handle rate limits."
  20. headers = None
  21. token = os.environ.get("GITHUB_TOKEN")
  22. if token:
  23. headers = {"authorization": f"Bearer {token}"}
  24. retries = 0
  25. while True:
  26. try:
  27. req = urllib.request.Request(url, headers=headers)
  28. return urllib.request.urlopen(req)
  29. except HTTPError as exc:
  30. if exc.code == 403 and retries < 5:
  31. retries += 1
  32. time.sleep(retries)
  33. continue
  34. raise
  35. def get_files_list(pr_number, repo="xhiveframework/xhiveframework"):
  36. return [change["filename"] for change in fetch_pr_data(pr_number, repo, "files")]
  37. def get_output(command, shell=True):
  38. print(command)
  39. command = shlex.split(command)
  40. return subprocess.check_output(command, shell=shell, encoding="utf8").strip()
  41. def has_skip_ci_label(pr_number, repo="xhiveframework/xhiveframework"):
  42. return has_label(pr_number, "Skip CI", repo)
  43. def has_run_server_tests_label(pr_number, repo="xhiveframework/xhiveframework"):
  44. return has_label(pr_number, "Run Server Tests", repo)
  45. def has_run_ui_tests_label(pr_number, repo="xhiveframework/xhiveframework"):
  46. return has_label(pr_number, "Run UI Tests", repo)
  47. def has_label(pr_number, label, repo="xhiveframework/xhiveframework"):
  48. return any(
  49. [
  50. fetched_label["name"]
  51. for fetched_label in fetch_pr_data(pr_number, repo)["labels"]
  52. if fetched_label["name"] == label
  53. ]
  54. )
  55. def is_py(file):
  56. return file.endswith("py")
  57. def is_ci(file):
  58. return ".github" in file
  59. def is_frontend_code(file):
  60. return file.lower().endswith((".css", ".scss", ".less", ".sass", ".styl", ".js", ".ts", ".vue", ".html"))
  61. def is_docs(file):
  62. regex = re.compile(r"\.(md|png|jpg|jpeg|csv|svg)$|^.github|LICENSE")
  63. return bool(regex.search(file))
  64. if __name__ == "__main__":
  65. files_list = sys.argv[1:]
  66. build_type = os.environ.get("TYPE")
  67. pr_number = os.environ.get("PR_NUMBER")
  68. repo = os.environ.get("REPO_NAME")
  69. # this is a push build, run all builds
  70. if not pr_number:
  71. os.system('echo "build=strawberry" >> $GITHUB_OUTPUT')
  72. sys.exit(0)
  73. files_list = files_list or get_files_list(pr_number=pr_number, repo=repo)
  74. if not files_list:
  75. print("No files' changes detected. Build is shutting")
  76. sys.exit(0)
  77. ci_files_changed = any(f for f in files_list if is_ci(f))
  78. only_docs_changed = len(list(filter(is_docs, files_list))) == len(files_list)
  79. only_frontend_code_changed = len(list(filter(is_frontend_code, files_list))) == len(files_list)
  80. updated_py_file_count = len(list(filter(is_py, files_list)))
  81. only_py_changed = updated_py_file_count == len(files_list)
  82. if has_skip_ci_label(pr_number, repo):
  83. if build_type == "ui" and has_run_ui_tests_label(pr_number, repo):
  84. print("Running UI tests only.")
  85. elif build_type == "server" and has_run_server_tests_label(pr_number, repo):
  86. print("Running server tests only.")
  87. else:
  88. print("Found `Skip CI` label on pr, stopping build process.")
  89. sys.exit(0)
  90. elif ci_files_changed:
  91. print("CI related files were updated, running all build processes.")
  92. elif only_docs_changed:
  93. print("Only docs were updated, stopping build process.")
  94. sys.exit(0)
  95. elif (
  96. only_frontend_code_changed
  97. and build_type == "server"
  98. and not has_run_server_tests_label(pr_number, repo)
  99. ):
  100. print("Only Frontend code was updated; Stopping Python build process.")
  101. sys.exit(0)
  102. elif build_type == "ui" and only_py_changed and not has_run_ui_tests_label(pr_number, repo):
  103. print("Only Python code was updated, stopping Cypress build process.")
  104. sys.exit(0)
  105. os.system('echo "build=strawberry" >> $GITHUB_OUTPUT')