Skip to content

Commit

Permalink
feat: launch django & tests with keyboard interrupt
Browse files Browse the repository at this point in the history
So can run tests or django locally & kill it + database on
keyboard interrupt via 'Ctrl+C'
  • Loading branch information
rdmolony committed Aug 4, 2023
1 parent 9232e67 commit 429c94c
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 39 deletions.
26 changes: 23 additions & 3 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,33 @@ jobs:
run: nix profile install github:cachix/devenv/v0.5
shell: sh
- run: devenv ci
- run: devenv shell run-tests
- name: Show Postgres startup logs
- name: Install dependencies
run: |
OUTPUT=$(devenv shell echo "Dependencies installed!")
# If poetry environment is broken then recache all Python dependencies ...
if [[ "$OUTPUT" == *"POETRY_STATUS=broken"* ]]; then
echo "POETRY_STATUS=broken" >> $GITHUB_ENV
else
echo "POETRY_STATUS=clean" >> $GITHUB_ENV
fi
echo $OUTPUT >> /tmp/dependencies.log
- name: Run tests
run: devenv shell test-all
- name: Show logs from dependency installation
if: always()
run: cat /tmp/dependencies.log
- name: Show logs from test database setup
if: always()
run: cat /tmp/devenv.log
- name: Show environment variables
if: always()
run: |
echo "POETRY_STATUS=${{ env.POETRY_STATUS }}"
- name: Cache python dependencies
uses: actions/cache/save@v3
if: always() && steps.cache.outputs.cache-hit != 'true'
if: always() && steps.cache.outputs.cache-hit != 'true' || ${{ env.POETRY_STATUS }} == 'broken'
with:
path: ~/.cache/pypoetry
key: ${{ runner.os }}-poetry-${{ hashFiles('poetry.lock') }}
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,5 @@ Specifically, `devenv` uses `nix` to install system level packages like `postgr

`devenv` enables defining scripts in `devenv.nix` that are automatically added to the shell path ...

- Run tests via `run-tests`
- Launch a development server via `devenv up`
- Launch a development server via `launch-django`
- Run tests via `test-all`
107 changes: 73 additions & 34 deletions devenv.nix
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
let
db_user = "postgres";
db_host = "localhost";
db_port = "5432";
db_port = 5432;
db_name = "db";
python_version = "3.10";
django_port = "8000";
in
{
packages = [ pkgs.git pkgs.postgresql_14 ];
Expand All @@ -17,71 +18,109 @@ in

env = {
PYTHON_VERSION = python_version;
DATABASE_URL = "postgresql://${db_user}@${db_host}:${db_port}/${db_name}";
DATABASE_URL = "postgresql://${db_user}@${db_host}:${builtins.toString db_port}/${db_name}";
DEBUG = true;
STATIC_ROOT = "/tmp/static";
};

enterShell = ''
# Activate poetry environment on shell entry
# https://pythonspeed.com/articles/activate-virtualenv-dockerfile/
VIRTUAL_ENV=`poetry env info --path` && export VIRTUAL_ENV
export PATH="$VIRTUAL_ENV/bin:$PATH";
# If poetry environment is broken we can check this env var in CI & recache
export POETRY_STATUS=$(check-poetry-status)
echo "POETRY_STATUS=$POETRY_STATUS"
'';

services.postgres = {
enable = true;
initialScript = "CREATE USER ${db_user} SUPERUSER;";
initialDatabases = [ { name = db_name; } ];
listen_addresses = db_host;
};

processes = {
runserver.exec = ''
devenv shell python manage.py runserver
'';
port = db_port;
};

scripts = {
start-processes-in-background.exec = ''
echo
psql --version
# Start Postgres if not running ...
if ! nc -z ${db_host} ${db_port};
dj.exec = ''
python manage.py $@
'';
check-poetry-status.exec = ''
STATUS=$(poetry check)
if [[ "$STATUS" == 'All set!' ]]; then
echo "clean"
else
echo "broken"
fi
'';
start-services-in-background.exec = ''
if ! nc -z ${db_host} ${builtins.toString db_port};
then
echo "Starting Database in the background on ${db_host}:${db_port} ..."
printf "Starting database in background ...\n"
nohup devenv up > /tmp/devenv.log 2>&1 &
fi
'';
kill-services.exec = ''
printf "Killing background services ...\n"
fuser -k ${builtins.toString db_port}/tcp
fuser -k ${django_port}/tcp
'';
wait-for-db.exec = ''
echo
echo "Waiting for database to start .."
echo "(if wait exceeds 100%, check /tmp/devenv.log for errors!)"
printf "Waiting for database to start ...\n"
printf "(if wait exceeds 100 percent then check /tmp/devenv.log for errors)\n"
# wait up to 20s for the database to launch ...
n_loops=20;
timer=0;
n_steps=99;
while true;
do
if nc -z ${db_host} ${db_port}; then
if nc -z ${db_host} ${builtins.toString db_port}; then
printf "\nDatabase is running!\n\n"
exit 0
elif [ $timer -gt $n_steps ]; then
elif [ $timer -gt $n_loops ]; then
printf "\nDatabase failed to launch!\n\n"
exit 1
else
sleep 0.1
sleep 1
let timer++
printf "%-*s" $((timer+1)) '[' | tr ' ' '#'
printf "%*s%3d%%\r" $((100-timer)) "]" "$timer"
percent=$((timer*100/n_loops))
bar+="#"
printf "\r[%-100s] %d%%" "$bar" "$percent"
fi
done
'';
run-tests.exec = ''
start-processes-in-background
wait-for-db || exit 1
python manage.py collectstatic --noinput
python manage.py test
launch-django.exec = ''
interrupt_handler() {
kill-services
exit 1
}
trap 'interrupt_handler' SIGINT
launch_django() {
printf "Launching Django ...\n\n"
start-services-in-background
wait-for-db || exit 1 # if wait-for-db fails, exit!
dj runserver ${django_port}
}
launch_django
'';
test-all.exec = ''
interrupt_handler() {
kill-services
exit 1
}
trap 'interrupt_handler' SIGINT
run_tests() {
printf "Running tests...\n\n"
start-services-in-background
wait-for-db || exit 1 # if wait-for-db fails, exit!
dj collectstatic --noinput
dj test $@
kill-services
exit 0
}
run_tests
'';
};
}

0 comments on commit 429c94c

Please sign in to comment.