sync.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. from __future__ import annotations
  2. import configparser
  3. import os
  4. import subprocess
  5. from devenv import constants
  6. from devenv.lib import colima, config, limactl, proc, venv, volta
  7. # TODO: need to replace this with a nicer process executor in devenv.lib
  8. def run_procs(
  9. repo: str,
  10. reporoot: str,
  11. venv_path: str,
  12. _procs: tuple[tuple[str, tuple[str, ...]], ...],
  13. ) -> bool:
  14. procs: list[tuple[str, tuple[str, ...], subprocess.Popen[bytes]]] = []
  15. for name, cmd in _procs:
  16. print(f"⏳ {name}")
  17. if constants.DEBUG:
  18. proc.xtrace(cmd)
  19. procs.append(
  20. (
  21. name,
  22. cmd,
  23. subprocess.Popen(
  24. cmd,
  25. stdout=subprocess.PIPE,
  26. stderr=subprocess.STDOUT,
  27. env={
  28. **constants.user_environ,
  29. **proc.base_env,
  30. "VIRTUAL_ENV": venv_path,
  31. "VOLTA_HOME": f"{reporoot}/.devenv/bin/volta-home",
  32. "PATH": f"{venv_path}/bin:{reporoot}/.devenv/bin:{proc.base_path}",
  33. },
  34. cwd=reporoot,
  35. ),
  36. )
  37. )
  38. all_good = True
  39. for name, final_cmd, p in procs:
  40. out, _ = p.communicate()
  41. if p.returncode != 0:
  42. all_good = False
  43. out_str = "" if out is None else out.decode()
  44. print(
  45. f"""
  46. ❌ {name}
  47. failed command (code p.returncode):
  48. {proc.quote(final_cmd)}
  49. Output:
  50. {out_str}
  51. """
  52. )
  53. else:
  54. print(f"✅ {name}")
  55. return all_good
  56. def main(context: dict[str, str]) -> int:
  57. repo = context["repo"]
  58. reporoot = context["reporoot"]
  59. # don't want this to be accidentally run from getsentry
  60. assert repo == "sentry", repo
  61. venv_dir, python_version, requirements, editable_paths, bins = venv.get(reporoot, repo)
  62. url, sha256 = config.get_python(reporoot, python_version)
  63. print(f"ensuring {repo} venv at {venv_dir}...")
  64. venv.ensure(venv_dir, python_version, url, sha256)
  65. # TODO: move volta version into per-repo config
  66. try:
  67. volta.install(reporoot)
  68. except TypeError:
  69. # this is needed for devenv <=1.4.0,>1.2.3 to finish syncing and therefore update itself
  70. volta.install()
  71. if constants.DARWIN:
  72. repo_config = configparser.ConfigParser()
  73. repo_config.read(f"{reporoot}/devenv/config.ini")
  74. try:
  75. colima.install(
  76. repo_config["colima"]["version"],
  77. repo_config["colima"][constants.SYSTEM_MACHINE],
  78. repo_config["colima"][f"{constants.SYSTEM_MACHINE}_sha256"],
  79. reporoot,
  80. )
  81. except TypeError:
  82. # this is needed for devenv <=1.4.0,>1.2.3 to finish syncing and therefore update itself
  83. colima.install(
  84. repo_config["colima"]["version"],
  85. repo_config["colima"][constants.SYSTEM_MACHINE],
  86. repo_config["colima"][f"{constants.SYSTEM_MACHINE}_sha256"],
  87. )
  88. # TODO: move limactl version into per-repo config
  89. try:
  90. limactl.install(reporoot)
  91. except TypeError:
  92. # this is needed for devenv <=1.4.0,>1.2.3 to finish syncing and therefore update itself
  93. limactl.install()
  94. if not run_procs(
  95. repo,
  96. reporoot,
  97. venv_dir,
  98. (
  99. (
  100. "javascript dependencies",
  101. (
  102. "bash",
  103. "-euo",
  104. "pipefail",
  105. "-c",
  106. """
  107. NODE_ENV=development ./.devenv/bin/yarn install --frozen-lockfile
  108. yarn check --verify-tree || yarn install --check-files
  109. """,
  110. ),
  111. ),
  112. (
  113. "python dependencies",
  114. (
  115. "bash",
  116. "-euo",
  117. "pipefail",
  118. "-c",
  119. """
  120. # install pinned pip
  121. pip install --constraint requirements-dev-frozen.txt pip
  122. # pip doesn't do well with swapping drop-ins
  123. pip uninstall -qqy djangorestframework-stubs django-stubs
  124. pip install -r requirements-dev-frozen.txt
  125. python3 -m tools.fast_editable --path .
  126. """,
  127. ),
  128. ),
  129. ),
  130. ):
  131. return 1
  132. if not run_procs(
  133. repo,
  134. reporoot,
  135. venv_dir,
  136. (
  137. (
  138. "git and precommit",
  139. # this can't be done in paralell with python dependencies
  140. # as multiple pips cannot act on the same venv
  141. ("make", "setup-git"),
  142. ),
  143. ),
  144. ):
  145. return 1
  146. if not os.path.exists(f"{constants.home}/.sentry/config.yml") or not os.path.exists(
  147. f"{constants.home}/.sentry/sentry.conf.py"
  148. ):
  149. proc.run((f"{venv_dir}/bin/sentry", "init", "--dev", "--no-clobber"))
  150. # TODO: check healthchecks for redis and postgres to short circuit this
  151. proc.run(
  152. (
  153. f"{venv_dir}/bin/sentry",
  154. "devservices",
  155. "up",
  156. "redis",
  157. "postgres",
  158. ),
  159. pathprepend=f"{reporoot}/.devenv/bin",
  160. exit=True,
  161. )
  162. if not run_procs(
  163. repo,
  164. reporoot,
  165. venv_dir,
  166. (
  167. (
  168. "python migrations",
  169. (
  170. "bash",
  171. "-euo",
  172. "pipefail",
  173. "-c",
  174. """
  175. make create-db
  176. sentry upgrade --noinput
  177. """,
  178. ),
  179. ),
  180. ),
  181. ):
  182. return 1
  183. # Starting sentry is slow.
  184. stdout = proc.run(
  185. (
  186. "docker",
  187. "exec",
  188. "sentry_postgres",
  189. "psql",
  190. "sentry",
  191. "postgres",
  192. "-t",
  193. "-c",
  194. "select exists (select from auth_user where email = 'admin@sentry.io')",
  195. ),
  196. stdout=True,
  197. )
  198. if stdout != "t":
  199. proc.run(
  200. (
  201. f"{venv_dir}/bin/sentry",
  202. "createuser",
  203. "--superuser",
  204. "--email",
  205. "admin@sentry.io",
  206. "--password",
  207. "admin",
  208. "--no-input",
  209. )
  210. )
  211. return 0