backend: Add django base web application (#161)

This commit is contained in:
Bastien Abadie 2019-10-18 12:29:51 +02:00 коммит произвёл GitHub
Родитель 797e36bad6
Коммит fa80fe5bc4
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
16 изменённых файлов: 424 добавлений и 2 удалений

2
.dockerignore Normal file
Просмотреть файл

@ -0,0 +1,2 @@
*/node_modules
*.sqlite*

2
.gitignore поставляемый
Просмотреть файл

@ -1,3 +1,5 @@
.vscode/
*.pyc
*.egg-info
*.sqlite*
backend/hgmo

Просмотреть файл

@ -1,6 +1,6 @@
[settings]
known_first_party = code_review_bot,code_review_tools,code_review_events,conftest
known_third_party = influxdb,libmozdata,libmozevent,logbook,parsepatch,pytest,raven,requests,responses,setuptools,structlog,taskcluster,toml
known_first_party = code_review_backend,code_review_bot,code_review_tools,code_review_events,conftest
known_third_party = dj_database_url,django,influxdb,libmozdata,libmozevent,logbook,parsepatch,pytest,raven,requests,responses,setuptools,structlog,taskcluster,toml
force_single_line = True
default_section=FIRSTPARTY
line_length=159

Просмотреть файл

@ -98,6 +98,26 @@ tasks:
owner: bastien@mozilla.com
source: https://github.com/mozilla/code-review
- taskId: {$eval: as_slugid("backend_check_tests")}
provisionerId: aws-provisioner-v1
workerType: github-worker
created: {$fromNow: ''}
deadline: {$fromNow: '1 hour'}
payload:
maxRunTime: 3600
image: python:3
command:
- sh
- -lxce
- "git clone --quiet ${repository} /src && cd /src && git checkout ${head_rev} -b checks &&
cd /src/backend && pip install -q . && pip install -q -r requirements-dev.txt &&
./manage.py test"
metadata:
name: "Code Review Backend checks: unit tests"
description: Check python code with Django tests
owner: bastien@mozilla.com
source: https://github.com/mozilla/code-review
- taskId: {$eval: as_slugid("frontend_build")}
provisionerId: aws-provisioner-v1
workerType: github-worker
@ -205,6 +225,47 @@ tasks:
owner: bastien@mozilla.com
source: https://github.com/mozilla/code-review
- taskId: {$eval: as_slugid("backend_build")}
created: {$fromNow: ''}
deadline: {$fromNow: '1 hour'}
provisionerId: aws-provisioner-v1
workerType: releng-svc
dependencies:
- {$eval: as_slugid("check_lint")}
- {$eval: as_slugid("backend_check_tests")}
payload:
capabilities:
privileged: true
maxRunTime: 3600
image: "${taskboot_image}"
env:
GIT_REPOSITORY: ${repository}
GIT_REVISION: ${head_rev}
command:
- taskboot
- build
- --image
- mozilla/code-review
- --tag
- "${channel}"
- --tag
- "${head_rev}"
- --write
- /backend.tar
- backend/Dockerfile
artifacts:
public/code-review-backend.tar:
expires: {$fromNow: '2 weeks'}
path: /backend.tar
type: file
scopes:
- docker-worker:capability:privileged
metadata:
name: Code Review Backend docker build
description: Build docker image of code review backend
owner: bastien@mozilla.com
source: https://github.com/mozilla/code-review
- $if: 'channel in ["testing", "production"]'
then:
taskId: {$eval: as_slugid("frontend_deploy")}
@ -326,3 +387,33 @@ tasks:
description: Deploy docker image on Heroku
owner: bastien@mozilla.com
source: https://github.com/mozilla/code-review
- $if: 'channel in ["testing", "production"]'
then:
taskId: {$eval: as_slugid("backend_deploy")}
created: {$fromNow: ''}
deadline: {$fromNow: '1 hour'}
provisionerId: aws-provisioner-v1
workerType: github-worker
dependencies:
- {$eval: as_slugid("backend_build")}
payload:
features:
taskclusterProxy: true
maxRunTime: 3600
image: "${taskboot_image}"
command:
- taskboot
- deploy-heroku
- --heroku-app
- "code-review-backend-${channel}"
- web:public/code-review-backend.tar
env:
TASKCLUSTER_SECRET: "project/relman/code-review/deploy-${channel}"
scopes:
- "secrets:get:project/relman/code-review/deploy-${channel}"
metadata:
name: "Code Review Backend deployment (${channel})"
description: Deploy docker image on Heroku
owner: bastien@mozilla.com
source: https://github.com/mozilla/code-review

15
backend/Dockerfile Normal file
Просмотреть файл

@ -0,0 +1,15 @@
FROM python:3.7-slim
ADD backend /src/backend
WORKDIR /src/backend
# Activate Django settings for in docker image
ENV DJANGO_DOCKER=true
RUN pip install --no-cache-dir .
# Collect all static files
RUN ./manage.py collectstatic --no-input
CMD gunicorn code_review_backend.app.wsgi

14
backend/README.md Normal file
Просмотреть файл

@ -0,0 +1,14 @@
# Code Review Backend
## Developer setup
```
mkvirtualenv -p /usr/bin/python3 code-review-backend
cd backend
pip install -r requirements.txt
./manage.py migrate
./manage.py createsuperuser
./manage.py runserver
```
At this point, you can log into http://127.0.0.1:8000/admin/ with the credentials you mentioned during the `createsuperuser` step.

1
backend/VERSION Normal file
Просмотреть файл

@ -0,0 +1 @@
1.0.4

Просмотреть файл

Просмотреть файл

Просмотреть файл

@ -0,0 +1,179 @@
# -*- coding: utf-8 -*-
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
"""
Django settings for backend project.
Generated by 'django-admin startproject' using Django 2.2.6.
For more information on this file, see
https://docs.djangoproject.com/en/2.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.2/ref/settings/
"""
import logging
import os
import dj_database_url
logger = logging.getLogger(__name__)
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
ROOT_DIR = os.path.dirname(BASE_DIR)
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = "t!+s!@x5p!85x19q83jufr#95_z0fv7$!u5z*c&gi!%hr3^w+r"
# Only use DEBUG mode for local development
# When running on Heroku, we disable that mode (see end of file & DYNO mode)
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"rest_framework",
]
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
ROOT_URLCONF = "code_review_backend.app.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
]
},
}
]
WSGI_APPLICATION = "code_review_backend.app.wsgi.application"
# Database
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": os.path.join(ROOT_DIR, "db.sqlite3"),
}
}
# Password validation
# https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator"
},
{"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator"},
{"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"},
{"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"},
]
# Internationalization
# https://docs.djangoproject.com/en/2.2/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
USE_I18N = True
USE_L10N = True
USE_TZ = True
# API configuration
REST_FRAMEWORK = {
# Use Django's standard `django.contrib.auth` permissions,
# or allow read-only access for unauthenticated users.
"DEFAULT_PERMISSION_CLASSES": [
"rest_framework.permissions.IsAuthenticatedOrReadOnly"
],
# Setup pagination
"PAGE_SIZE": 50,
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.LimitOffsetPagination",
}
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.2/howto/static-files/
STATIC_URL = "/static/"
# Static files are set in a dedicated path in Docker image
if "DJANGO_DOCKER" in os.environ:
STATIC_ROOT = "/static"
# Enable GZip and cache, and build a manifest during collectstatic
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
# Internal logging setup
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"handlers": {"console": {"class": "logging.StreamHandler"}},
"loggers": {
"django": {"handlers": ["console"], "level": "INFO"},
"code_review_backend": {"handlers": ["console"], "level": "INFO"},
},
}
# Heroku settings override to run the web app in production mode
if "DYNO" in os.environ:
logger.info("Setting up Heroku environment")
ALLOWED_HOSTS = ["*"]
DEBUG = os.environ.get("DEBUG", "false").lower() == "true"
# Database setup
if "DATABASE_URL" in os.environ:
logger.info("Using remote database from $DATABASE_URL")
DATABASES["default"] = dj_database_url.parse(
os.environ["DATABASE_URL"], ssl_require=True
)
else:
logger.info("DATABASE_URL not found, will use sqlite. Data may be lost.")
# Insert Whitenoise Middleware after the security one
MIDDLEWARE.insert(1, "whitenoise.middleware.WhiteNoiseMiddleware")
# Use Secret key from env
SECRET_KEY = os.environ.get("SECRET_KEY", SECRET_KEY)

Просмотреть файл

@ -0,0 +1,13 @@
# -*- coding: utf-8 -*-
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from django.contrib import admin
from django.shortcuts import redirect
from django.urls import path
urlpatterns = [
path("", lambda request: redirect("admin/", permanent=False)),
path("admin/", admin.site.urls),
]

Просмотреть файл

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
"""
WSGI config for backend project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "code_review_backend.app.settings")
application = get_wsgi_application()

26
backend/manage.py Executable file
Просмотреть файл

@ -0,0 +1,26 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "code_review_backend.app.settings")
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == "__main__":
main()

Просмотреть файл

@ -0,0 +1 @@
pre-commit==1.18.3

10
backend/requirements.txt Normal file
Просмотреть файл

@ -0,0 +1,10 @@
Django==2.2.6
dj-database-url==0.5.0
djangorestframework==3.10.3
gunicorn==19.9.0
psycopg2-binary==2.8.3
pytz==2019.3
sqlparse==0.3.0
taskcluster==19.0.0
taskcluster-urls==11.0.0
whitenoise==4.1.4

47
backend/setup.py Normal file
Просмотреть файл

@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import setuptools
def read_requirements(file_):
lines = []
with open(file_) as f:
for line in f.readlines():
line = line.strip()
if (
line.startswith("-e ")
or line.startswith("http://")
or line.startswith("https://")
):
extras = ""
if "[" in line:
extras = "[" + line.split("[")[1].split("]")[0] + "]"
line = line.split("#")[1].split("egg=")[1] + extras
elif line == "" or line.startswith("#") or line.startswith("-"):
continue
line = line.split("#")[0].strip()
lines.append(line)
return sorted(list(set(lines)))
with open("VERSION") as f:
VERSION = f.read().strip()
setuptools.setup(
name="code_review_backend",
version=VERSION,
description="Store and compare issues found in Mozilla code review tasks",
author="Mozilla Release Management",
author_email="release-mgmt-analysis@mozilla.com",
url="https://github.com/mozilla/code-review",
tests_require=read_requirements("requirements-dev.txt"),
install_requires=read_requirements("requirements.txt"),
packages=setuptools.find_packages(),
include_package_data=True,
zip_safe=False,
license="MPL2",
)