lib.sh 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. #!/bin/bash
  2. # Module containing code shared across various shell scripts
  3. # Execute functions from this module via the script do.sh
  4. # shellcheck disable=SC2034 # Unused variables
  5. # shellcheck disable=SC2001 # https://github.com/koalaman/shellcheck/wiki/SC2001
  6. # This block is a safe-guard since in CI calling tput will fail and abort scripts
  7. if [ -z "${CI+x}" ]; then
  8. bold="$(tput bold)"
  9. red="$(tput setaf 1)"
  10. green="$(tput setaf 2)"
  11. yellow="$(tput setaf 3)"
  12. reset="$(tput sgr0)"
  13. fi
  14. venv_name=".venv"
  15. # NOTE: This file is sourced in CI across different repos (e.g. snuba),
  16. # so renaming this file or any functions can break CI!
  17. # Check if a command is available
  18. require() {
  19. command -v "$1" >/dev/null 2>&1
  20. }
  21. configure-sentry-cli() {
  22. if [ -n "${SENTRY_DSN+x}" ] && [ -z "${SENTRY_DEVENV_NO_REPORT+x}" ]; then
  23. if ! require sentry-cli; then
  24. curl -sL https://sentry.io/get-cli/ | bash
  25. fi
  26. eval "$(sentry-cli bash-hook)"
  27. fi
  28. }
  29. query-mac() {
  30. [[ $(uname -s) = 'Darwin' ]]
  31. }
  32. query-big-sur() {
  33. if require sw_vers && sw_vers -productVersion | grep -E "11\." >/dev/null; then
  34. return 0
  35. fi
  36. return 1
  37. }
  38. query-apple-m1() {
  39. query-mac && [[ $(uname -m) = 'arm64' ]]
  40. }
  41. get-pyenv-version() {
  42. if [[ -n "${SENTRY_PYTHON_VERSION:-}" ]]; then
  43. echo "${SENTRY_PYTHON_VERSION}"
  44. return 0
  45. fi
  46. local PYENV_VERSION
  47. PYENV_VERSION=3.6.13
  48. if query-apple-m1; then
  49. PYENV_VERSION=3.8.12
  50. fi
  51. echo "${PYENV_VERSION}"
  52. }
  53. query-valid-python-version() {
  54. if [[ -n "${SENTRY_PYTHON_VERSION:-}" ]]; then
  55. python_version=$(python3 -V 2>&1 | awk '{print $2}')
  56. if [ "$python_version" != "$SENTRY_PYTHON_VERSION" ]; then
  57. cat <<EOF
  58. ${red}${bold}
  59. ERROR: You have explicitly set a non-recommended Python version (${SENTRY_PYTHON_VERSION}),
  60. but it doesn't match the value of python's version: ${python_version}
  61. You should create a new ${SENTRY_PYTHON_VERSION} virtualenv by running "rm -rf ${venv_name} && direnv allow".
  62. ${reset}
  63. EOF
  64. return 1
  65. fi
  66. cat <<EOF
  67. ${yellow}${bold}
  68. You have explicitly set a non-recommended Python version (${SENTRY_PYTHON_VERSION}). You're on your own.
  69. ${reset}
  70. EOF
  71. return 0
  72. fi
  73. python_version=$(python3 -V 2>&1 | awk '{print $2}')
  74. minor=$(echo "${python_version}" | sed 's/[0-9]*\.\([0-9]*\)\.\([0-9]*\)/\1/')
  75. patch=$(echo "${python_version}" | sed 's/[0-9]*\.\([0-9]*\)\.\([0-9]*\)/\2/')
  76. # For Apple M1, we only allow 3.8 and at least patch version 10
  77. if query-apple-m1; then
  78. if [ "$minor" -ne 8 ] || [ "$patch" -lt 10 ]; then
  79. cat <<EOF
  80. ${red}${bold}
  81. ERROR: You're running a virtualenv with Python ${python_version}.
  82. On Apple M1 machines, we only support >= 3.8.10 < 3.9.
  83. Either run "rm -rf ${venv_name} && direnv allow" to
  84. OR set SENTRY_PYTHON_VERSION=${python_version} to an .env file to bypass this check."
  85. EOF
  86. return 1
  87. fi
  88. elif [ "$minor" -ne 6 ] && [ "$minor" -ne 8 ]; then
  89. cat <<EOF
  90. ${red}${bold}
  91. ERROR: You're running a virtualenv with Python ${python_version}.
  92. We only support 3.6 or 3.8.
  93. Either run "rm -rf ${venv_name} && direnv allow" to
  94. OR set SENTRY_PYTHON_VERSION=${python_version} to an .env file to bypass this check."
  95. EOF
  96. return 1
  97. fi
  98. }
  99. sudo-askpass() {
  100. if [ -z "${sudo-askpass-x}" ]; then
  101. sudo --askpass "$@"
  102. else
  103. sudo "$@"
  104. fi
  105. }
  106. upgrade-pip() {
  107. pip install --upgrade "pip==21.1.2" "wheel==0.36.2"
  108. }
  109. install-py-dev() {
  110. upgrade-pip
  111. # It places us within top src dir to be at the same path as setup.py
  112. # This helps when getsentry calls into this script
  113. cd "${HERE}/.." || exit
  114. echo "--> Installing Sentry (for development)"
  115. if query-apple-m1; then
  116. # This installs pyscopg-binary2 since there's no arm64 wheel
  117. # This saves having to install postgresql on the Developer's machine + using flags
  118. # https://github.com/psycopg/psycopg2/issues/1286
  119. pip install https://storage.googleapis.com/python-arm64-wheels/psycopg2_binary-2.8.6-cp38-cp38-macosx_11_0_arm64.whl
  120. fi
  121. # SENTRY_LIGHT_BUILD=1 disables webpacking during setup.py.
  122. # Webpacked assets are only necessary for devserver (which does it lazily anyways)
  123. # and acceptance tests, which webpack automatically if run.
  124. SENTRY_LIGHT_BUILD=1 pip install -e '.[dev]'
  125. }
  126. setup-git-config() {
  127. git config --local branch.autosetuprebase always
  128. git config --local core.ignorecase false
  129. git config --local blame.ignoreRevsFile .git-blame-ignore-revs
  130. }
  131. setup-git() {
  132. setup-git-config
  133. echo "--> Installing git hooks"
  134. mkdir -p .git/hooks && cd .git/hooks && ln -sf ../../config/hooks/* ./ && cd - || exit
  135. # shellcheck disable=SC2016
  136. python3 -c '' || (
  137. echo 'Please run `make setup-pyenv` to install the required Python 3 version.'
  138. exit 1
  139. )
  140. pip install -r requirements-pre-commit.txt
  141. pre-commit install --install-hooks
  142. echo ""
  143. }
  144. node-version-check() {
  145. # Checks to see if node's version matches the one specified in package.json for Volta.
  146. node -pe "process.exit(Number(!(process.version == 'v' + require('./package.json').volta.node )))" ||
  147. (
  148. echo 'Unexpected node version. Recommended to use https://github.com/volta-cli/volta'
  149. exit 1
  150. )
  151. }
  152. install-js-dev() {
  153. node-version-check
  154. echo "--> Installing Yarn packages (for development)"
  155. # Use NODE_ENV=development so that yarn installs both dependencies + devDependencies
  156. NODE_ENV=development yarn install --frozen-lockfile
  157. # A common problem is with node packages not existing in `node_modules` even though `yarn install`
  158. # says everything is up to date. Even though `yarn install` is run already, it doesn't take into
  159. # account the state of the current filesystem (it only checks .yarn-integrity).
  160. # Add an additional check against `node_modules`
  161. yarn check --verify-tree || yarn install --check-files
  162. }
  163. develop() {
  164. setup-git
  165. install-js-dev
  166. install-py-dev
  167. }
  168. init-config() {
  169. sentry init --dev
  170. }
  171. run-dependent-services() {
  172. sentry devservices up
  173. }
  174. create-db() {
  175. # shellcheck disable=SC2155
  176. local CREATEDB=$(command -v createdb 2>/dev/null)
  177. if [[ -z "$CREATEDB" ]]; then
  178. CREATEDB="docker exec sentry_postgres createdb"
  179. fi
  180. echo "--> Creating 'sentry' database"
  181. ${CREATEDB} -h 127.0.0.1 -U postgres -E utf-8 sentry || true
  182. }
  183. apply-migrations() {
  184. echo "--> Applying migrations"
  185. sentry upgrade --noinput
  186. }
  187. create-user() {
  188. if [[ -n "${GITHUB_ACTIONS+x}" ]]; then
  189. sentry createuser --superuser --email foo@tbd.com --no-password
  190. else
  191. sentry createuser --superuser
  192. fi
  193. }
  194. build-platform-assets() {
  195. echo "--> Building platform assets"
  196. echo "from sentry.utils.integrationdocs import sync_docs; sync_docs(quiet=True)" | sentry exec
  197. }
  198. bootstrap() {
  199. develop
  200. init-config
  201. run-dependent-services
  202. create-db
  203. apply-migrations
  204. create-user
  205. build-platform-assets
  206. }
  207. clean() {
  208. echo "--> Cleaning static cache"
  209. rm -rf dist/* src/sentry/static/sentry/dist/*
  210. echo "--> Cleaning integration docs cache"
  211. rm -rf src/sentry/integration-docs
  212. echo "--> Cleaning pyc files"
  213. find . -name "*.pyc" -delete
  214. echo "--> Cleaning python build artifacts"
  215. rm -rf build/ dist/ src/sentry/assets.json
  216. echo ""
  217. }
  218. drop-db() {
  219. # shellcheck disable=SC2155
  220. local DROPDB=$(command -v dropdb 2>/dev/null)
  221. if [[ -z "$DROPDB" ]]; then
  222. DROPDB="docker exec sentry_postgres dropdb"
  223. fi
  224. echo "--> Dropping existing 'sentry' database"
  225. ${DROPDB} -h 127.0.0.1 -U postgres sentry || true
  226. }
  227. reset-db() {
  228. drop-db
  229. create-db
  230. apply-migrations
  231. }
  232. prerequisites() {
  233. brew update -q && brew bundle -q
  234. }
  235. direnv-help() {
  236. cat >&2 <<EOF
  237. If you're a Sentry employee and you're stuck or have questions, ask in #discuss-dev-tooling.
  238. If you're not, please file an issue under https://github.com/getsentry/sentry/issues/new/choose and mention @getsentry/owners-sentry-dev
  239. You can configure the behaviour of direnv by adding the following variables to a .env file:
  240. - SENTRY_DIRENV_DEBUG=1: This will allow printing debug messages
  241. - SENTRY_DEVENV_NO_REPORT=1: Do not report development environment errors to Sentry.io
  242. EOF
  243. }