Development environment setup script#
Background#
Over the years I found that the best teams scale their development environment setup through a shell script.
Interestingly, the script is always at the same path: tools/setup.sh.
As you can imagine, we’re targeting operating systems that support bash.
In fact, these days I see that companies converge on MacOS for all employees for security and uniformity.
We won’t need no Virtual Machines or Docker. Just bare-metal laptop and shell script (mostly).
Boilerplate#
#!/usr/bin/env bash
set -e -o pipefail
PYTHON_VERSION="3.12"
PYTHON="python${PYTHON_VERSION}"
VENV_DIR=~/.virtualenvs/P
brew install "python@${PYTHON_VERSION}"
# Ensure virtualenv is created and active
if [ -z "$VIRTUAL_ENV" ]; then
mkdir -p ~/.virtualenvs/
if [ ! -f "${VENV_DIR}/bin/activate" ]; then
$PYTHON -m venv ${VENV_DIR}
fi
. ${VENV_DIR}/bin/activate
fi
$PYTHON -m pip install -r requirements/prereq.txt
$PYTHON -m piptools sync requirements/dev.txt
pre-commit install
pre-commit autoupdate
Few highlights:
We put Python version into a constant, because it’s bound to change.
If it was Ubuntu, we’d replace
brewwithapt, though. So, no big deal, maybe companies will migrate to Linux some day.Having Python virtual environment outside of repo is good for grep and such.
Having it under
~/.virtualenvs/specifically is compatible with my beloved virtualenvwrapper. I don’t want to enforce virtualenvwrapper on all team members, though. The way I use it with is to runmkvirtualenv -a $PWD -p (which python3.12) P && tools/setup.sh.Virtualenv’s name is a single letter, preferrably the first letter of the project’s name. This way, I can navigate to the project by running
workon P.The nested logic allows running the script with and without virtualenv A) created and B) activated.
Requirements installation is split into two phases:
Install the blessed pip version and pip-tools.
Run pip-sync to ensure the environment is healthy no repeated runs.
Force installation of pre-commit hooks, so ground rules can be enforced reliably.
Pre-commit hooks#
.pre-commit-config.yaml:
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: check-json
- id: check-toml
- id: check-yaml
- id: end-of-file-fixer
- repo: local
hooks:
- id: isort
name: isort
entry: isort
language: system
require_serial: true
types_or: [cython, pyi, python]
args: ['--filter-files']
- id: black
name: black
entry: black
language: system
require_serial: true
types_or: [python, pyi]
- id: flake8
name: flake8
entry: flake8
language: system
require_serial: true
types_or: [python, pyi]