sync.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. from __future__ import annotations
  2. import concurrent.futures
  3. import configparser
  4. import functools
  5. import os
  6. from libdevinfra.jobs import Job, Task, run_jobs
  7. from devenv import constants
  8. from devenv.lib import colima, config, fs, limactl, proc, venv, volta
  9. def main(context: dict[str, str]) -> int:
  10. repo = context["repo"]
  11. reporoot = context["reporoot"]
  12. FRONTEND_ONLY = os.environ.get("SENTRY_DEVENV_FRONTEND_ONLY") is not None
  13. # venv's still needed for frontend because repo-local devenv and pre-commit
  14. # exist inside it
  15. venv_dir, python_version, requirements, editable_paths, bins = venv.get(reporoot, repo)
  16. url, sha256 = config.get_python(reporoot, python_version)
  17. print(f"ensuring {repo} venv at {venv_dir}...")
  18. venv.ensure(venv_dir, python_version, url, sha256)
  19. # TODO: move volta version into per-repo config
  20. try:
  21. volta.install(reporoot)
  22. except TypeError:
  23. # this is needed for devenv <=1.4.0,>1.2.3 to finish syncing and therefore update itself
  24. volta.install()
  25. if constants.DARWIN:
  26. repo_config = configparser.ConfigParser()
  27. repo_config.read(f"{reporoot}/devenv/config.ini")
  28. try:
  29. colima.install(
  30. repo_config["colima"]["version"],
  31. repo_config["colima"][constants.SYSTEM_MACHINE],
  32. repo_config["colima"][f"{constants.SYSTEM_MACHINE}_sha256"],
  33. reporoot,
  34. )
  35. except TypeError:
  36. # this is needed for devenv <=1.4.0,>1.2.3 to finish syncing and therefore update itself
  37. colima.install(
  38. repo_config["colima"]["version"],
  39. repo_config["colima"][constants.SYSTEM_MACHINE],
  40. repo_config["colima"][f"{constants.SYSTEM_MACHINE}_sha256"],
  41. )
  42. # TODO: move limactl version into per-repo config
  43. try:
  44. limactl.install(reporoot)
  45. except TypeError:
  46. # this is needed for devenv <=1.4.0,>1.2.3 to finish syncing and therefore update itself
  47. limactl.install()
  48. jp1 = Task(
  49. name="upgrade pip",
  50. func=functools.partial(
  51. proc.run,
  52. (
  53. f"{venv_dir}/bin/python3",
  54. "-m",
  55. "pip",
  56. "--disable-pip-version-check",
  57. "install",
  58. "--constraint",
  59. "requirements-dev-frozen.txt",
  60. "pip",
  61. ),
  62. stdout=True,
  63. ),
  64. )
  65. jp2 = Task(
  66. name="uninstall some problems",
  67. func=functools.partial(
  68. proc.run,
  69. (
  70. f"{venv_dir}/bin/python3",
  71. "-m",
  72. "pip",
  73. "--disable-pip-version-check",
  74. "uninstall",
  75. "-qqy",
  76. "djangorestframework-stubs",
  77. "django-stubs",
  78. ),
  79. stdout=True,
  80. ),
  81. )
  82. jp3 = Task(
  83. name="install dependencies",
  84. func=functools.partial(
  85. proc.run,
  86. (
  87. f"{venv_dir}/bin/python3",
  88. "-m",
  89. "pip",
  90. "--disable-pip-version-check",
  91. "install",
  92. "--constraint",
  93. "requirements-dev-frozen.txt",
  94. "-r",
  95. "requirements-dev-frozen.txt",
  96. ),
  97. stdout=True,
  98. ),
  99. )
  100. jp4 = Task(
  101. name="install editable",
  102. func=functools.partial(
  103. proc.run,
  104. (f"{venv_dir}/bin/python3", "-m", "tools.fast_editable", "--path", "."),
  105. stdout=True,
  106. ),
  107. )
  108. jp5 = Task(
  109. name="init sentry config",
  110. func=functools.partial(
  111. proc.run,
  112. (f"{venv_dir}/bin/sentry", "init", "--dev", "--no-clobber"),
  113. stdout=True,
  114. ),
  115. )
  116. jpc1 = Task(
  117. name="install pre-commit dependencies",
  118. func=functools.partial(
  119. proc.run,
  120. (f"{venv_dir}/bin/pre-commit", "install", "--install-hooks", "-f"),
  121. stdout=True,
  122. ),
  123. )
  124. jm1 = Task(
  125. name="bring up redis and postgres",
  126. func=functools.partial(
  127. proc.run,
  128. (f"{venv_dir}/bin/sentry", "devservices", "up", "redis", "postgres"),
  129. stdout=True,
  130. ),
  131. )
  132. jm2 = Task(
  133. name="apply migrations",
  134. func=functools.partial(
  135. proc.run,
  136. ("make", "apply-migrations"),
  137. pathprepend=f"{venv_dir}/bin:{reporoot}/.devenv/bin",
  138. env={"VIRTUAL_ENV": venv_dir},
  139. stdout=True,
  140. ),
  141. )
  142. jt1 = Task(
  143. name="install js dependencies",
  144. func=functools.partial(
  145. proc.run,
  146. (
  147. "yarn",
  148. "install",
  149. "--frozen-lockfile",
  150. "--no-progress",
  151. "--non-interactive",
  152. ),
  153. pathprepend=f"{venv_dir}/bin:{reporoot}/.devenv/bin",
  154. env={
  155. "NODE_ENV": "development",
  156. "VOLTA_HOME": f"{reporoot}/.devenv/bin/volta-home",
  157. },
  158. stdout=True,
  159. ),
  160. )
  161. jp = Job(name="python dependencies", tasks=(jp1, jp2, jp3, jp4, jp5))
  162. jm = Job(name="sentry migrations", tasks=(jm1, jm2))
  163. jpc = Job(name="pre-commit dependencies", tasks=(jpc1,))
  164. jt = Job(name="javascript dependencies", tasks=(jt1,))
  165. # after python deps are installed we can install pre-commit deps
  166. jp3.spawn_jobs = (jpc,)
  167. # Frontend engineers don't necessarily always have devservices running and
  168. # can configure to skip them to save on local resources
  169. if FRONTEND_ONLY:
  170. print("Skipping python migrations since SENTRY_DEVENV_FRONTEND_ONLY is set.")
  171. else:
  172. jp5.spawn_jobs = (jm,)
  173. with concurrent.futures.ThreadPoolExecutor() as tpe:
  174. run_jobs((jp, jt), tpe)
  175. fs.ensure_symlink("../../config/hooks/post-merge", f"{reporoot}/.git/hooks/post-merge")