devenv
managing dev environments since '24
devenv is an extensible execution framework and library for authoring
a simple set of high level commands - bootstrap, fetch, sync, doctor - that
manage a repository's dev environment.
Prerequisites
If you are a Sentry employee, make sure your GitHub account is in a getsentry/engineering team. If it is not, open an IT ticket before you continue.
If you are not a Sentry employee, set the SENTRY_EXTERNAL_CONTRIBUTOR environment variable. devenv bootstrap and devenv fetch both read it.
Install
Download install-devenv.sh and run it:
curl https://raw.githubusercontent.com/getsentry/devenv/main/install-devenv.sh > install-devenv.sh
bash install-devenv.sh
Keep the file name install-devenv.sh. The script only runs its installer when it has that name.
The script installs the global devenv to ~/.local/share/sentry-devenv/bin/devenv.
devenv uses uv to install itself and to manage virtualenvs; it does not use pip.
Install the latest uv first with brew install uv. If the script can't find uv, it installs the latest uv to ~/.local/bin with uv's official installer.
To update the global devenv, run devenv update.
Commands
Run devenv --help for the full list.
devenv bootstrap
Sets up a new machine. It writes the global configuration, configures GitHub SSH access, and installs the global tools.
devenv fetch [repository name]
Clones any GitHub repository in the form [org]/[reponame] over SSH into your coderoot, then runs devenv sync in it. If you omit the org, it defaults to getsentry.
sentry and ops are special names:
devenv fetch sentrysets upgetsentry/sentry, and alsogetsentry/getsentryunlessSENTRY_EXTERNAL_CONTRIBUTORis set.devenv fetch opssets upgetsentry/opsand clonesgetsentry/terraform-modules.
devenv sync
Runs the repo's sync.py from the repo config directory. sync.py defines main(context: dict[str, str]) -> int. The context keys are reporoot, repo, and coderoot. sync.py should:
- install any tools the repo needs
- create the dev environment, or bring it up to date
sync.py runs in devenv's runtime, so it can import the devenv.lib modules. There are no API docs. Start from the examples. If you have a feature request, open an issue.
The library keeps a repo's dev environment inside [reporoot]/.devenv where it can.
For example, gcloud is installed to [reporoot]/.devenv/bin/gcloud, with the gcloud SDK at [reporoot]/.devenv/bin/google-cloud-sdk.
Python virtualenvs are an exception because they predate [reporoot]/.devenv.
devenv doctor
Diagnoses and fixes common issues. Use --check-only to skip fixes, and --tag or --exclude-tag to select checks.
Builtin checks live in devenv.checks. A repo can add its own checks in the checks directory of its repo config directory.
devenv update [version]
Updates the global devenv installation and the global tools. Pass a version to install that version.
If your devenv is old enough that it has no update command, run:
uv pip install --python ~/.local/share/sentry-devenv/venv/bin/python -U sentry-devenv
devenv colima start
Starts or creates devenv's Colima VM with resources sized for your machine. Existing VM settings are kept. The other subcommands are restart, check, and stop.
On affected Apple M4/M5 systems, this and devenv colima restart check whether the VM kernel reports SVE support the CPU does not have. Devenv upgrades the VM kernel when needed, restarts once, and verifies the result. devenv doctor checks this too.
devenv pin_gha [file ...]
Pins each uses: reference in the given GitHub Actions workflow files to a commit SHA.
Technical overview
Everything devenv needs is in ~/.local/share/sentry-devenv.
~/.local/share/sentry-devenv/bin contains:
devenvitselfdirenv, if direnv was not already on your PATH. devenv relies on direnv and a minimal[reporoot]/.envrcto add[reporoot]/.devenv/binto PATH.- on macOS only, the global tools: the
dockerCLI,colima, andlima. On Linux, install docker engine yourself.devenv bootstrapexits if it is missing.
Runtime
devenv is installed with uv in a virtualenv at ~/.local/share/sentry-devenv/venv.
That virtualenv uses the Python at ~/.local/share/sentry-devenv/python.
It has no pip; devenv update uses uv pip to update it.
Global configuration
~/.config/sentry-devenv/config.ini
[devenv]
# the parent directory of all devenv-managed repos
coderoot = ~/code
Repository configuration
devenv reads config.ini, sync.py, and checks from the repo config directory.
The repo config directory is [reporoot]/.devenv if [reporoot]/.devenv/config.ini exists.
Otherwise, it is [reporoot]/devenv if [reporoot]/devenv/config.ini exists.
If neither file exists, it is [reporoot]/.devenv.
The examples below use [reporoot]/devenv.
[reporoot]/devenv/config.ini
[devenv]
# optionally require a minimum version to run sync.py
minimum_version = 1.22.1
The examples show the other sections.
Examples
Skip to:
direnv
Every repo needs a minimal [reporoot]/.envrc:
if [[ -f "${PWD}/.env" ]]; then
dotenv
fi
PATH_add "${HOME}/.local/share/sentry-devenv/bin"
if ! command -v devenv >/dev/null; then
echo "install devenv: https://github.com/getsentry/devenv#install"
return 1
fi
PATH_add "${PWD}/.devenv/bin"
python
devenv does not manage uv installations. Run brew install uv.
To activate the virtualenv with direnv and run uv sync as part of devenv sync:
[reporoot]/.envrc
export VIRTUAL_ENV="${PWD}/.venv"
PATH_add "${PWD}/.venv/bin"
[reporoot]/devenv/sync.py
from devenv.lib import proc
def main(context: dict[str, str]) -> int:
# reporoot/.venv is the default venv location
print(f"syncing .venv ...")
proc.run(("uv", "sync", "--frozen", "--quiet"))
return 0
Use [reporoot]/.python-version to pin a python version for uv:
3.13.16
node
node.install_pnpm installs the pnpm version named in the packageManager field of [reporoot]/package.json.
[reporoot]/.envrc
PATH_add "${PWD}/node_modules/.bin"
[reporoot]/devenv/sync.py
from devenv import constants
from devenv.lib import config, node, proc
def main(context: dict[str, str]) -> int:
reporoot = context["reporoot"]
cfg = config.get_repo(reporoot)
node.install(
cfg["node"]["version"],
cfg["node"][constants.SYSTEM_MACHINE],
cfg["node"][f"{constants.SYSTEM_MACHINE}_sha256"],
reporoot,
)
node.install_pnpm(reporoot)
print("installing node dependencies...")
proc.run(
(
f"{reporoot}/.devenv/bin/pnpm",
"install",
"--frozen-lockfile",
"--reporter=append-only",
)
)
return 0
If you want a different node version, first fill in the matching URLs from https://nodejs.org/dist/ in config.ini. Then ask dev-infra to mirror them to GCS.
[reporoot]/devenv/config.ini
[node]
# upstream (https://nodejs.org/dist/) is not reliable enough so we've mirrored it to GCS
darwin_x86_64 = https://storage.googleapis.com/sentry-dev-infra-assets/node/node-v20.13.1-darwin-x64.tar.xz
darwin_x86_64_sha256 = c83bffeb4eb793da6cb61a44c422b399048a73d7a9c5eb735d9c7f5b0e8659b6
darwin_arm64 = https://storage.googleapis.com/sentry-dev-infra-assets/node/node-v20.13.1-darwin-arm64.tar.xz
darwin_arm64_sha256 = e8a8e78b91485bc95d20f2aa86201485593685c828ee609245ce21c5680d07ce
linux_x86_64 = https://storage.googleapis.com/sentry-dev-infra-assets/node/node-v20.13.1-linux-x64.tar.xz
linux_x86_64_sha256 = efc0f295dd878e510ab12ea36bbadc3db03c687ab30c07e86c7cdba7eed879a9
# used for autoupdate
version = v20.13.1
brew
[reporoot]/devenv/sync.py
from devenv import constants
from devenv.lib import brew, proc
def main(context: dict[str, str]) -> int:
reporoot = context["reporoot"]
brew.install()
proc.run((f"{constants.homebrew_bin}/brew", "bundle"), cwd=reporoot)
return 0
[reporoot]/Brewfile
# whatever you want, but we generally discourage installing
# things via brew as it's very difficult to pin a particular
# version of something
colima
devenv bootstrap and devenv update install Colima v0.10.3 and Lima v2.2.1 on macOS.
New macOS installations
Colima 0.10.3 creates new VMs from its Ubuntu 24.04.4 image, whose kernel is expected to report SVE correctly. M4 Pro validation confirmed this on that host. New VMs use a separate persistent 512 GiB container data disk and Docker's containerd image store. Inotify is off by default.
Existing macOS installations
Updating devenv keeps the existing VM, Docker images, containers, and named volumes. It does not recreate the VM or convert its disk layout. Colima 0.8.1 VMs keep Docker data on their root disk; newer VMs use a separate persistent data disk. Do not delete a legacy VM as routine cleanup: its containers and named volumes can be lost with its root disk.
devenv update does not stop a running VM. Before the next upgraded start, devenv checks a running daemon through the colima Docker context and records its store choice in ~/.colima/default/colima.yaml. For a stopped VM, it uses Colima's persisted store and Lima disk metadata to identify the layout. If the evidence is ambiguous, startup stops with instructions to set docker.features.containerd-snapshotter explicitly. Existing explicit values are preserved, and devenv does not remove Docker data.
Affected M4/M5 Macs may need an in-VM kernel update because existing VMs keep their original kernel. Devenv installs and boots the update when needed. If a previous repair installed the kernel but did not boot it, run devenv colima restart. This does not convert the VM to the new data disk layout.
Lima 2.1 changed the instance disk layout. After starting a VM with Lima 2.x, Lima 1.x cannot start that instance. Downgrading devenv or its binaries does not restore the old layout. See Lima's compatibility discussion.
Check or change the Docker image store
Run docker --context=colima info to see the active storage driver. The classic store reports overlay2. The containerd store reports io.containerd.snapshotter.v1 in the driver status. Use the explicit colima context so Docker Desktop's current context does not affect the result.
If images or containers appear missing after an upgrade, inspect docker --context=colima info, docker --context=colima images, docker --context=colima ps -a, and docker --context=colima volume ls. Check docker.features.containerd-snapshotter in ~/.colima/default/colima.yaml against the store containing your data. For a legacy overlay2 VM, use:
docker:
features:
buildkit: true
containerd-snapshotter: false
Set it to true only after confirming the VM's data is in the containerd store. Start Colima after correcting the value. Switching stores hides images and containers in the other store. Do not delete the VM or its disks to diagnose the problem.
Enable inotify propagation
To propagate host file events into the VM, set mountInotify: true in ~/.colima/default/colima.yaml or start Colima with --mount-inotify. Devenv preserves an existing true setting. Inotify is off for new VMs because Colima watches configured mounts, including devenv's writable home mount. Watching a large home directory can increase host CPU and memory use; see Colima issue 1569.
gcloud
[reporoot]/devenv/sync.py
from devenv import constants
from devenv.lib import config, gcloud
def main(context: dict[str, str]) -> int:
reporoot = context["reporoot"]
cfg = config.get_repo(reporoot)
gcloud.install(
cfg["gcloud"]["version"],
cfg["gcloud"][constants.SYSTEM_MACHINE],
cfg["gcloud"][f"{constants.SYSTEM_MACHINE}_sha256"],
reporoot,
)
return 0
[reporoot]/devenv/config.ini
The SDK uses devenv's internal Python 3.13 because custom Python versions
aren't supported yet.
[gcloud]
darwin_x86_64 = https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-490.0.0-darwin-x86_64.tar.gz
darwin_x86_64_sha256 = fa396909acc763cf831dd5d89e778999debf37ceadccb3c1bdec606e59ba2694
darwin_arm64 = https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-490.0.0-darwin-arm.tar.gz
darwin_arm64_sha256 = a3a098a5f067b561e003c37284a9b164f28f37fd0d6371bb55e326679f48641c
linux_x86_64 = https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-490.0.0-linux-x86_64.tar.gz
linux_x86_64_sha256 = 40ce41958236f76d9cb08f377ccb9fd6502d2df4da14b36d9214bcb620e2b020
# used for autoupdate
version = 490.0.0
terraform
devenv installs tenv and keeps TENV_ROOT at [reporoot]/.devenv/bin/tenv-root. It also writes tenv, terraform, tofu, and terragrunt shims to [reporoot]/.devenv/bin that use that TENV_ROOT. It does not write a tf shim, so a repo's own tf wrapper is not shadowed.
Define [reporoot]/.terraform-version, and optionally [reporoot]/.terragrunt-version. After devenv sync, run terraform and tenv installs the pinned version.
[reporoot]/devenv/sync.py
from devenv import constants
from devenv.lib import config, tenv
def main(context: dict[str, str]) -> int:
reporoot = context["reporoot"]
cfg = config.get_repo(reporoot)
tenv.install(
cfg["tenv"]["version"],
cfg["tenv"][constants.SYSTEM_MACHINE],
cfg["tenv"][f"{constants.SYSTEM_MACHINE}_sha256"],
reporoot,
)
return 0
[reporoot]/devenv/config.ini
[tenv]
darwin_x86_64 = https://github.com/tofuutils/tenv/releases/download/v1.3.0/tenv_v1.3.0_Darwin_x86_64.tar.gz
darwin_x86_64_sha256 = 994100d26f4de6de4eebc7691ca4ea7b424e2fd73e6d5d77c5bf6dfd4af94752
darwin_arm64 = https://github.com/tofuutils/tenv/releases/download/v1.3.0/tenv_v1.3.0_Darwin_arm64.tar.gz
darwin_arm64_sha256 = c31d2b8412147316a0cadb684408bc123e567852d7948091be7e4303fc19397a
# used for autoupdate
version = v1.3.0
Get help
Run devenv doctor first. If that does not fix it, see the devenv troubleshooting guide.
Metadata
Release files for sentry-devenv 1.30.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| sentry_devenv-1.30.1.tar.gz | 77.9 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sentry_devenv-1.30.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 178.8 kB
Release files / sentry_devenv-1.30.1.tar.gz
| Download URL | sentry_devenv-1.30.1.tar.gz |
|---|---|
| Size | 77.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
cb625e4dc81bad5ccfe11cddc84f0fe86d0fd78298b70d71b2d810bb754a124d
|
|
BLAKE2b-256 checksum How to use checksums |
ade1324bb962d1bcb1e18aa00f9fd614c57c573df08072df6b5fd850a81cf298
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.11.2
|
Release files / sentry_devenv-1.30.1-py3-none-any.whl
| Download URL | sentry_devenv-1.30.1-py3-none-any.whl |
|---|---|
| Size | 100.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
99d56f11363f04d89763f6dda11fbd37c5f782e034321eb70b3eb2952c17bcce
|
|
BLAKE2b-256 checksum How to use checksums |
7aa5abb1adb35ceac18323a13c5b21b23219b9785de68e330fb30571d71abc80
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.11.2
|
Security for sentry-devenv 1.30.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.