sync.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. from __future__ import annotations
  2. import configparser
  3. import os
  4. import shlex
  5. import subprocess
  6. from devenv import constants
  7. from devenv.lib import colima, config, limactl, proc, venv, volta
  8. # TODO: need to replace this with a nicer process executor in devenv.lib
  9. def run_procs(
  10. repo: str,
  11. reporoot: str,
  12. venv_path: str,
  13. _procs: tuple[tuple[str, tuple[str, ...]], ...],
  14. ) -> bool:
  15. procs: list[tuple[str, tuple[str, ...], subprocess.Popen[bytes]]] = []
  16. for name, cmd in _procs:
  17. print(f"⏳ {name}")
  18. if constants.DEBUG:
  19. proc.xtrace(cmd)
  20. procs.append(
  21. (
  22. name,
  23. cmd,
  24. subprocess.Popen(
  25. cmd,
  26. stdout=subprocess.PIPE,
  27. stderr=subprocess.STDOUT,
  28. env={
  29. **constants.user_environ,
  30. **proc.base_env,
  31. "VIRTUAL_ENV": venv_path,
  32. "VOLTA_HOME": f"{reporoot}/.devenv/bin/volta-home",
  33. "PATH": f"{venv_path}/bin:{reporoot}/.devenv/bin:{proc.base_path}",
  34. },
  35. cwd=reporoot,
  36. ),
  37. )
  38. )
  39. all_good = True
  40. for name, final_cmd, p in procs:
  41. out, _ = p.communicate()
  42. if p.returncode != 0:
  43. all_good = False
  44. print(
  45. f"""
  46. ❌ {name}
  47. failed command (code p.returncode):
  48. {shlex.join(final_cmd)}
  49. Output:
  50. {out.decode()}
  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