Skip to content

Commit

Permalink
configured docker-compose and github action wait for db
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex1-ai committed Mar 23, 2024
1 parent 7ecafd8 commit 0936633
Show file tree
Hide file tree
Showing 18 changed files with 189 additions and 9 deletions.
6 changes: 4 additions & 2 deletions .github/workflows/checks.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
---
--- # the --- signifies that it is a yaml file
name: Checks

on: [push]
Expand All @@ -13,9 +13,11 @@ jobs:
with:
username: ${{ secrets.DOCKERHUB_USER }}
password: ${{ secrets.DOCKERHUB_TOKEN}}
# checkout is to put the codes into the ubuntu we are using here
- name: Checkout
uses: actions/checkout@v2
# ubuntu-20.04 automatically comes with a preinstalled docker so we don't have to install it again
- name: Test
run: docker-compose run --rm app sh -c "python manage.py test"
run: docker-compose run --rm app sh -c "python manage.py wait_for_db && python manage.py test"
- name: Lint
run: docker-compose run --rm app sh -c "flake8"
11 changes: 9 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ LABEL maintainer="https://github.com/Alex1-ai/"

# THIS TELL PYTHON NOT TO BUFFER THE OUTPUT
# SO THAT IT PREVENT ANY DELAYS SO WE CAN SEE LOG IMMEDIATELY
ENV PYTHONUNBUFFERED=1
ENV PYTHONUNBUFFERED 1

# COPYING ALL OUR REQUIREMENTS AND FILES FROM LOCAL TO DOCKER CONTAINER
COPY ./requirements.txt /tmp/requirements.txt
Expand All @@ -27,20 +27,27 @@ COPY ./app /app
WORKDIR /app
EXPOSE 8000

# HERE WE ARE SAYING DEV TO BE DEFAULT FALSE
# BUT WE WOULD BE OVERIDDING IT ON OUR ON DOCKER-COMPOSE
ARG DEV=false
RUN python -m venv /py && \
/py/bin/pip install --upgrade pip && \
apk add --update --no-cache postgresql-client && \
apk add --update --no-cache --virtual .tmp-build-deps \
build-base postgresql-dev musl-dev && \
/py/bin/pip install -r /tmp/requirements.txt && \
if [ $DEV = "true" ]; \
then /py/bin/pip install -r /tmp/requirements.dev.txt ; \
fi && \
rm -rf /tmp && \
apk del .tmp-build-deps && \
adduser \
--disabled-password \
--no-create-home \
django-user


# UPDATING THE ENVIRONMENT OF THE DOCKER
ENV PATH="/py/bin:$PATH"

# AFTER RUNNING THE USER AS ROOT THIS USER django-user SWITCHES BACK THE USER TO django-user
USER django-user
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,22 @@
# food-recipy-api
This is a food recipy Django api project Integrated with Docker , CI/CD


## To Start the app with Docker-compose
command` docker-compose up`
<!-- code` docker-compose run --rm app sh -c "python manage.py collectstatic"` -->

## To check the code using linting
command` docker-compose run --rm app sh -c "flake8"`

## To run the test
command` docker-compose run --rm app sh -c "python manage.py test"`

## To run our custom command
command` docker-compose run --rm app sh -c "python manage.py wait_for_db"`

## To start an project
command` docker-compose run --rm app sh -c "django-admin startproject app ."`

## To create a core app
command` docker-compose run --rm app sh -c "python manage.py startapp core`
14 changes: 14 additions & 0 deletions app/app/calc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"""
calculator functions
"""


def add(x, y):
""" add x and y and return result """
return x + y


def substract(x, y):
""" subtracting x from y and return result"""
return y - x
12 changes: 9 additions & 3 deletions app/app/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"""

from pathlib import Path

import os
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent

Expand All @@ -37,6 +37,7 @@
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'core'
]

MIDDLEWARE = [
Expand Down Expand Up @@ -75,8 +76,13 @@

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
'ENGINE':'django.db.backends.postgresql',
'HOST':os.environ.get('DB_HOST'),
'NAME':os.environ.get('DB_NAME'),
'USER': os.environ.get('DB_USER'),
'PASSWORD':os.environ.get('DB_PASS')
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': BASE_DIR / 'db.sqlite3',
}
}

Expand Down
20 changes: 20 additions & 0 deletions app/app/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"""
Sample tests
"""


from django.test import SimpleTestCase
from app import calc


class CalcTests(SimpleTestCase):
"""Test the calc module"""
def test_add_numbers(self):
"""Test adding numbers togeter"""
res = calc.add(5, 6)
self.assertEqual(res, 11)

def test_substract_number(self):
""""Test substracting numbers"""
res = calc.substract(10, 15)
self.assertEqual(res, 5)
Empty file added app/core/__init__.py
Empty file.
4 changes: 4 additions & 0 deletions app/core/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# the noqa tells flake8 to ignore that line for linting
from django.contrib import admin # noqa

# Register your models here.
6 changes: 6 additions & 0 deletions app/core/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class CoreConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'core'
Empty file added app/core/management/__init__.py
Empty file.
Empty file.
30 changes: 30 additions & 0 deletions app/core/management/commands/wait_for_db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""
Django command to wait for the database to be available.
"""

# from django.core.management.base import BaseCommand

import time

from psycopg2 import OperationalError as Psycopg2OpError

from django.db.utils import OperationalError
from django.core.management.base import BaseCommand


class Command(BaseCommand):
""" Django command to wait for database ."""

def handle(self, *args, **options):
""" Django command to wait for database """
self.stdout.write("Waiting for database ....")
db_up = False
while db_up is False:
try:
self.check(databases=['default'])
db_up = True
except (Psycopg2OpError, OperationalError):
self.stdout.write('Database unavailable, waiting 1 second....')
time.sleep(1)
self.stdout.write(self.style.SUCCESS('Database avaialble!'))
Empty file added app/core/migrations/__init__.py
Empty file.
3 changes: 3 additions & 0 deletions app/core/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.db import models # noqa

# Create your models here.
Empty file added app/core/tests/__init__.py
Empty file.
34 changes: 34 additions & 0 deletions app/core/tests/test_commands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"""
Test custom Django management commands
"""

from unittest.mock import patch

from psycopg2 import OperationalError as Psycopg2Error

from django.core.management import call_command
from django.db.utils import OperationalError
from django.test import SimpleTestCase


@patch("core.management.commands.wait_for_db.Command.check")
class CommandTests(SimpleTestCase):
"""
Test commands.
"""
def test_wait_for_db_ready(self, patched_check):
""" Test waiting for database if database ready. """
patched_check.return_value = True

call_command('wait_for_db')

patched_check.assert_called_once_with(databases=['default'])

@patch('time.sleep')
def test_wait_for_db_delay(self, patched_sleep, patched_check):
"Test waiting for database when getting OperationalError"
patched_check.side_effect = [Psycopg2Error] * 2 + \
[OperationalError] * 3 + [True]
call_command("wait_for_db")
self.assertEqual(patched_check.call_count, 6)
patched_check.assert_called_with(databases=['default'])
35 changes: 34 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,47 @@
# Docker compose version 3.9 : is saying use the version 3.9 syntax
version: "3.9"


services:
# NAME OF THE SERVICES app and db
app:
build:
context: .
args:
- DEV=true
# THIS MAP PORT 8000 FROM OUR LOCAL MACHINE TO 8000 PORT IN DOCKER
ports:
- "8000:8000"
# VOLUMES ARE WAY OF MAPPING OR LINKING DIRECTORIES FROM OUR LOCAL MACHINE TO DOCKER
# WHY WE ADDING VOLUMES IS OTHER TO SYNC THE CODE ON OUR LOCAL MACHINE TO DOCKER IN REALTIME
# SO WE DON'T HAVE TO BUILD EVERYTIME
volumes:
- ./app:/app
command: >
sh -c "python manage.py runserver 0.0.0.0:8000"
sh -c "python manage.py wait_for_db &&
python manage.py migrate &&
python manage.py runserver 0.0.0.0:8000"
environment:
# we are using db because it is the host name of the database db
- DB_HOST=db
- DB_NAME=devdb
- DB_USER=devuser
- DB_PASS=changeme
# depends_on will wait for the db service to start before moving on
# it would automatically create a network between the db service and app
depends_on:
- db

db:
image: postgres:13-alpine
# stores the database which is located in docker in our local machine
volumes:
- dev-db-data:/var/lib/postgresql/data

environment:
- POSTGRES_DB=devdb
- POSTGRES_USER=devuser
- POSTGRES_PASSWORD=changeme

volumes:
dev-db-data:
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
Django>=3.2.4,<3.3
djangorestframework>=3.12.4,<3.13
djangorestframework>=3.12.4,<3.13
psycopg2>=2.8.6,<2.9

0 comments on commit 0936633

Please sign in to comment.