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
brew
withapt
, 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]