diff --git a/.github/workflows/api-staging.yml b/.github/workflows/api-staging.yml new file mode 100644 index 00000000..008e9b14 --- /dev/null +++ b/.github/workflows/api-staging.yml @@ -0,0 +1,84 @@ +name: Staging + +on: + push: + branches: + - staging-deployment-experiment + +jobs: + stage: + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@master + + - name: build_image + id: build_image + uses: elgohr/Publish-Docker-Github-Action@master + with: + name: codebuddies/backend/cb-backend + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + registry: docker.pkg.github.com + dockerfile: Dockerfile + workdir: project + tag_names: true + + - name: start deployment + uses: bobheadxi/deployments@master + id: deployment + with: + step: start + token: ${{ secrets.GITHUB_TOKEN }} + env: staging + transient: true + desc: Setting up staging deployment for ${{ steps.build_image.outputs.tag }} + + - name: copy files + uses: appleboy/scp-action@master + with: + host: ${{ secrets.DO_STAGING_HOST }} + key: ${{ secrets.DO_SSH_KEY }} + passphrase: ${{ secrets.DO_SSH_PASSPHRASE }} + port: ${{ secrets.DO_STAGING_SSH_PORT }} + username: ${{ secrets.DO_SSH_USER }} + source: "project/docker-compose-staging.yaml" + target: "./" + + - name: run deployment + uses: appleboy/ssh-action@master + env: + DO_STAGING_DB_URL: ${{ secrets.DO_STAGING_DB_URL }} + CB_IMAGE_TAG: ${{ steps.build_image.outputs.tag }} + GITHUB_ACTOR: $GITHUB_ACTOR + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + DJANGO_SECRET_KEY: ${{ secrets.STAGING_DJANGO_SECRET_KEY }} + DJANGO_ALLOWED_HOSTS: "${{ secrets.STAGING_ALLOWED_HOSTS }}" + with: + host: ${{ secrets.DO_STAGING_HOST }} + key: ${{ secrets.DO_SSH_KEY }} + passphrase: ${{ secrets.DO_SSH_PASSPHRASE }} + port: ${{ secrets.DO_STAGING_SSH_PORT }} + username: ${{ secrets.DO_SSH_USER }} + script_stop: true + debug: true + envs: DO_STAGING_DB_URL,CB_IMAGE_TAG,GITHUB_ACTOR,GITHUB_TOKEN,DJANGO_SECRET_KEY,DJANGO_ALLOWED_HOSTS + script: | + export DB_URL=$DO_STAGING_DB_URL + export CB_IMAGE_TAG=$CB_IMAGE_TAG + export DJANGO_SECRET_KEY=$DJANGO_SECRET_KEY + export DJANGO_ALLOWED_HOSTS=$DJANGO_ALLOWED_HOSTS + docker login docker.pkg.github.com -u $GITHUB_ACTOR -p $GITHUB_TOKEN + docker-compose --project-name=-stage -f project/docker-compose-staging.yaml rm -f + docker-compose --project-name=-stage -f project/docker-compose-staging.yaml pull + docker-compose --project-name=-stage -f project/docker-compose-staging.yaml up -d + - name: finish deployment + uses: bobheadxi/deployments@master + if: always() + with: + step: finish + token: ${{ secrets.GITHUB_TOKEN }} + status: ${{ job.status }} + env: ${{ steps.deployment.outputs.env }} + env_url: https://${{ secrets.DO_STAGING_HOST }} + deployment_id: ${{ steps.deployment.outputs.deployment_id }} diff --git a/bump.md b/bump.md new file mode 100644 index 00000000..d00491fd --- /dev/null +++ b/bump.md @@ -0,0 +1 @@ +1 diff --git a/community_health_file.md b/community_health_file.md index 5b1cf60c..14cf8cab 100644 --- a/community_health_file.md +++ b/community_health_file.md @@ -1,42 +1,51 @@ [//]: <> (github.com/codebuddies/backend/) -## **Overview of Codebuddies** + +## Overview of Codebuddies ### What is CodeBuddies? -[CodeBuddies](https://codebuddies.org/) is a remote-first community of independent code learners who enjoy sharing knowledge and helping each other learn faster via discussions and pairing. It is free and open-sourced, and supported by open source contributors and financial backers on our [Open Collective](https://opencollective.com/codebuddies). -### CodeBuddies website Version 3 (CBV3) +[CodeBuddies](https://codebuddies.org/) is a remote-first community of independent code learners who enjoy sharing knowledge and helping each other learn faster via discussions and pairing. It is free and open-sourced, and supported by open source contributors and financial backers on our [Open Collective](https://opencollective.com/codebuddies). + +### CodeBuddies Website Version 3 (CBV3) -We are currently building out a new platform (CBV3) to replace the [old version](http://github.com/codebuddies/codebuddies) which is currently shown at [codebuddies.org]((https://codebuddies.org/)). +We are currently building out a new platform (CBV3) to replace the [old version](http://github.com/codebuddies/codebuddies) which is currently shown at [codebuddies.org](<(https://codebuddies.org/)>). The new version of the website will include features that will help users: -* share and recommend resources/tutorial links -* find open source projects to work on -* form study groups -* collect learning paths and share them -* pair programming -- find 1-hour pair programming partners for any topics in a much more easier way + +- share and recommend resources/tutorial links +- find open source projects to work on +- form study groups +- collect learning paths and share them +- pair programming -- find 1-hour pair programming partners for any topics in a much more easier way ## **Role of Backend** + The backend is a Django app that provides API endpoints (built using Django REST Framework) that the frontend (a React app) consumes. We have a technical decision log [here](https://github.com/codebuddies/backend/wiki/Decision-log). ## **Links to Clients / Frontend** + The frontend of CBV3 is built with React and is located at [here](http://github.com/codebuddies/frontend). ## **Technologies Used** -__Components of the CBV3 Backend__ -* [Django REST Framework](https://www.django-rest-framework.org/) -* [Cookiecutter](https://cookiecutter.readthedocs.io/en/1.7.0/) -__Application Deployment__ -* [Docker Compose](http://docs.docker.com/compose) to stand up local development environments -* [Github Actions](http://help.github.com/en/actions) to deploy staging and production. +**Components of the CBV3 Backend** + +- [Django REST Framework](https://www.django-rest-framework.org/) +- [Cookiecutter](https://cookiecutter.readthedocs.io/en/1.7.0/) + +**Application Deployment** -__Database__ -* [PostgreSQL](http://postgresql.org) -* [DigialOcean Droplets](http://digitalocean.com/products/droplets) to store the database on cloud +- [Docker Compose](http://docs.docker.com/compose) to stand up local development environments +- [Github Actions](http://help.github.com/en/actions) to deploy staging and production. -__Core dependencies of CBV3__ +**Database** + +- [PostgreSQL](http://postgresql.org) +- [DigialOcean Droplets](http://digitalocean.com/products/droplets) to store the database on cloud + +**Core dependencies of CBV3** | Dependencies | Version | | ------------ | :-----: | | [djangorestframework](https://github.com/encode/django-rest-framework) | 3.10.2 | @@ -44,18 +53,22 @@ __Core dependencies of CBV3__ | [drf-jwt](https://githbu.com/Styria-Digital/django-rest-framework-jwt) | 1.13.4 | ## **Can I run the website application on my computer?** + Of course you can. Follow the [instructions](contributing.md) to set up the Django API backend. Set up using Docker is highly recommended. ## **Have Questions about CBV3?** + Check out [support.md](support.md) if you're stuck or have questions. ## **Ways to Get Involved** + Anyone is welcome to contribute and make the website better! You can: -* Join our slack community [here](https://codebuddies.org/slack) -* Share your feedback on [Github CBV3 backend issues](https://github.com/codebuddies/backend/issues) -* Help review [CBV3 backend pull requests](https://github.com/codebuddies/backend/pulls) by recreating the feature +- Join our slack community [here](https://codebuddies.org/slack) +- Share your feedback on [Github CBV3 backend issues](https://github.com/codebuddies/backend/issues) +- Help review [CBV3 backend pull requests](https://github.com/codebuddies/backend/pulls) by recreating the feature + +## CODE OF CONDUCT.md -## **CODE OF CONDUCT.md** -_Please_ read CodeBuddies' [Code of Conduct](code_of_conduct.md) to understand the responsibility and scope as a contributor at CodeBuddies. +Please read CodeBuddies' [Code of Conduct](code_of_conduct.md) to understand the responsibility and scope as a contributor at CodeBuddies. diff --git a/project/.do/app.yaml b/project/.do/app.yaml new file mode 100644 index 00000000..03229294 --- /dev/null +++ b/project/.do/app.yaml @@ -0,0 +1,23 @@ +name: cb +services: + - name: backend + git: + repo_clone_url: "https://github.com/codebuddies/backend.git" + branch: staging-deployment-experiment + run_command: gunicorn --worker-tmp-dir /opt/codebuddies/uwsgi.ini + source_dir: project + environment_slug: python + envs: + - key: DISABLE_COLLECTSTATIC + value: "1" + scope: BUILD_TIME + - key: DJANGO_ALLOWED_HOSTS + value: "${APP_DOMAIN}" + scope: RUN_TIME + - key: DATABASE_URL + value: "${db.DATABASE_URL}" + scope: RUN_TIME +databases: + - name: db + engine: PG + version: "12" diff --git a/project/config/settings/production.py b/project/config/settings/production.py index bd80f474..c99481e2 100644 --- a/project/config/settings/production.py +++ b/project/config/settings/production.py @@ -1,12 +1,5 @@ import logging -import sentry_sdk - -from sentry_sdk.integrations.django import DjangoIntegration -from sentry_sdk.integrations.logging import LoggingIntegration -from sentry_sdk.integrations.celery import CeleryIntegration - - from .base import * # noqa from .base import env @@ -15,7 +8,7 @@ # https://docs.djangoproject.com/en/dev/ref/settings/#secret-key SECRET_KEY = env("DJANGO_SECRET_KEY") # https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts -ALLOWED_HOSTS = env.list("DJANGO_ALLOWED_HOSTS", default=["django.codebuddies.org"]) +ALLOWED_HOSTS = env.list("DJANGO_ALLOWED_HOSTS") # DATABASES # ------------------------------------------------------------------------------ @@ -23,21 +16,6 @@ DATABASES["default"]["ATOMIC_REQUESTS"] = True # noqa F405 DATABASES["default"]["CONN_MAX_AGE"] = env.int("CONN_MAX_AGE", default=60) # noqa F405 -# CACHES -# ------------------------------------------------------------------------------ -CACHES = { - "default": { - "BACKEND": "django_redis.cache.RedisCache", - "LOCATION": env("REDIS_URL"), - "OPTIONS": { - "CLIENT_CLASS": "django_redis.client.DefaultClient", - # Mimicing memcache behavior. - # http://niwinz.github.io/django-redis/latest/#_memcached_exceptions_behavior - "IGNORE_EXCEPTIONS": True, - }, - } -} - # SECURITY # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#secure-proxy-ssl-header @@ -63,53 +41,6 @@ "DJANGO_SECURE_CONTENT_TYPE_NOSNIFF", default=True ) -# STORAGES -# ------------------------------------------------------------------------------ -# https://django-storages.readthedocs.io/en/latest/#installation -INSTALLED_APPS += ["storages"] # noqa F405 -# https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings -AWS_ACCESS_KEY_ID = env("DJANGO_AWS_ACCESS_KEY_ID") -# https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings -AWS_SECRET_ACCESS_KEY = env("DJANGO_AWS_SECRET_ACCESS_KEY") -# https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings -AWS_STORAGE_BUCKET_NAME = env("DJANGO_AWS_STORAGE_BUCKET_NAME") -# https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings -AWS_QUERYSTRING_AUTH = False -# DO NOT change these unless you know what you're doing. -_AWS_EXPIRY = 60 * 60 * 24 * 7 -# https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings -AWS_S3_OBJECT_PARAMETERS = { - "CacheControl": f"max-age={_AWS_EXPIRY}, s-maxage={_AWS_EXPIRY}, must-revalidate" -} -# https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings -AWS_DEFAULT_ACL = None -# https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#settings -AWS_S3_REGION_NAME = env("DJANGO_AWS_S3_REGION_NAME", default=None) -# STATIC -# ------------------------ -STATICFILES_STORAGE = "config.settings.production.StaticRootS3Boto3Storage" -STATIC_URL = f"https://{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com/static/" -# MEDIA -# ------------------------------------------------------------------------------ -# region http://stackoverflow.com/questions/10390244/ -# Full-fledge class: https://stackoverflow.com/a/18046120/104731 -from storages.backends.s3boto3 import S3Boto3Storage # noqa E402 - - -class StaticRootS3Boto3Storage(S3Boto3Storage): - location = "static" - default_acl = "public-read" - - -class MediaRootS3Boto3Storage(S3Boto3Storage): - location = "media" - file_overwrite = False - - -# endregion -DEFAULT_FILE_STORAGE = "config.settings.production.MediaRootS3Boto3Storage" -MEDIA_URL = f"https://{AWS_STORAGE_BUCKET_NAME}.s3.amazonaws.com/media/" - # TEMPLATES # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#templates @@ -141,24 +72,6 @@ class MediaRootS3Boto3Storage(S3Boto3Storage): # Django Admin URL regex. ADMIN_URL = env("DJANGO_ADMIN_URL") -# Anymail (Mailgun) -# ------------------------------------------------------------------------------ -# https://anymail.readthedocs.io/en/stable/installation/#installing-anymail -INSTALLED_APPS += ["anymail"] # noqa F405 -EMAIL_BACKEND = "anymail.backends.mailgun.EmailBackend" -# https://anymail.readthedocs.io/en/stable/installation/#anymail-settings-reference -ANYMAIL = { - "MAILGUN_API_KEY": env("MAILGUN_API_KEY"), - "MAILGUN_SENDER_DOMAIN": env("MAILGUN_DOMAIN"), - "MAILGUN_API_URL": env("MAILGUN_API_URL", default="https://api.mailgun.net/v3"), -} - -# Collectfast -# ------------------------------------------------------------------------------ -# https://github.com/antonagestam/collectfast#installation -INSTALLED_APPS = ["collectfast"] + INSTALLED_APPS # noqa F405 -AWS_PRELOAD_METADATA = True - # LOGGING # ------------------------------------------------------------------------------ # https://docs.djangoproject.com/en/dev/ref/settings/#logging @@ -189,7 +102,6 @@ class MediaRootS3Boto3Storage(S3Boto3Storage): "propagate": False, }, # Errors logged by the SDK itself - "sentry_sdk": {"level": "ERROR", "handlers": ["console"], "propagate": False}, "django.security.DisallowedHost": { "level": "ERROR", "handlers": ["console"], @@ -198,19 +110,5 @@ class MediaRootS3Boto3Storage(S3Boto3Storage): }, } -# Sentry -# ------------------------------------------------------------------------------ -SENTRY_DSN = env("SENTRY_DSN") -SENTRY_LOG_LEVEL = env.int("DJANGO_SENTRY_LOG_LEVEL", logging.INFO) - -sentry_logging = LoggingIntegration( - level=SENTRY_LOG_LEVEL, # Capture info and above as breadcrumbs - event_level=logging.ERROR, # Send errors as events -) -sentry_sdk.init( - dsn=SENTRY_DSN, - integrations=[sentry_logging, DjangoIntegration(), CeleryIntegration()], -) - # Your stuff... # ------------------------------------------------------------------------------ diff --git a/project/docker-compose-staging.yaml b/project/docker-compose-staging.yaml new file mode 100644 index 00000000..c0f0d60a --- /dev/null +++ b/project/docker-compose-staging.yaml @@ -0,0 +1,17 @@ +version: "3" + +services: + app_staging: + image: "docker.pkg.github.com/codebuddies/backend/cb-backend:$CB_IMAGE_TAG" + container_name: staging-app + restart: on-failure + command: > + sh -c "python /opt/codebuddies/manage.py migrate && + uwsgi --ini /opt/codebuddies/uwsgi.ini" + environment: + - DATABASE_URL=${DB_URL} + - EMAIL_HOST=localhost + - DJANGO_SETTINGS_MODULE=config.settings.production + - DJANGO_SECRET_KEY=${DJANGO_SECRET_KEY} + - DJANGO_ADMIN_URL=admin/ + - DJANGO_ALLOWED_HOSTS=${DJANGO_ALLOWED_HOSTS} diff --git a/project/requirements/base.txt b/project/requirements/base.txt index 9f2c0d57..e9892f09 100644 --- a/project/requirements/base.txt +++ b/project/requirements/base.txt @@ -5,7 +5,7 @@ python-slugify==4.0.0 # https://github.com/un33k/python-slugify pytz==2019.2 # https://github.com/stub42/pytz redis==3.3.8 # https://github.com/antirez/redis regex==2020.4.4 #https://bitbucket.org/mrabarnett/mrab-regex/src/hg/ - +gunicorn==20.0.4 # Celery # _____________________________________________________________________________ diff --git a/project/runtime.txt b/project/runtime.txt index 59a6441f..795ee725 100644 --- a/project/runtime.txt +++ b/project/runtime.txt @@ -1 +1 @@ -python-3.7 \ No newline at end of file +python-3.7.9