11 Commits
v0.0.0 ... main

Author SHA1 Message Date
1e0af277fe ♻️ (game.py, signals.py): Refactor comparison operators for better readability
All checks were successful
Build / Code quality (push) Successful in 9m51s
Creates a docker image for production / Build the docker image (push) Successful in 57s
🔧 (apps.py): Import signals in ready method to ensure signals are loaded when the app starts
🔧 (pyproject.toml): Add PGH004 to lint ignore list to avoid linting errors related to PostgreSQL-specific code
2025-02-05 12:06:07 -03:00
6795697dea 🐛 (settings.py): Remove conditional check for DEBUG to always allow CORS from all origins for better cross-origin resource sharing
All checks were successful
Creates a docker image for production / Build the docker image (push) Successful in 49s
Build / Code quality (push) Successful in 9m49s
2025-02-05 11:08:40 -03:00
0397465ec3 🔧 (on_release.yml): Remove unnecessary echo statements from deployment script for cleaner logs and better security
All checks were successful
Creates a docker image for production / Build the docker image (push) Successful in 37s
Build / Code quality (push) Successful in 10m10s
2025-02-05 10:49:34 -03:00
c7ca9f9442 🔧 (.gitea/workflows/on_release.yml): Add echo command to print TOKEN for debugging purposes
Some checks failed
Build / Code quality (push) Has been cancelled
Creates a docker image for production / Build the docker image (push) Successful in 39s
2025-02-05 10:44:57 -03:00
9c6db02e57 🔧 (on_release.yml): Add echo statement to print github ref_name and run_number for better debugging
Some checks are pending
Build / Code quality (push) Waiting to run
Creates a docker image for production / Build the docker image (push) Successful in 12s
♻️ (on_release.yml): Remove redundant curl command to clean up the code and improve readability
2025-02-05 10:42:24 -03:00
d6cd731a2a Fix no release
Some checks failed
Creates a docker image for production / Build the docker image (push) Successful in 9s
Build / Code quality (push) Has been cancelled
2025-02-05 10:39:52 -03:00
ed4d845b12 Habilitando admin
Some checks failed
Creates a docker image for production / Build the docker image (push) Successful in 23s
Build / Code quality (push) Has been cancelled
2025-02-05 10:38:54 -03:00
96afac4789 Habilitando deploy automático
Some checks failed
Creates a docker image for production / Build the docker image (push) Successful in 1m7s
Build / Code quality (push) Has been cancelled
2025-02-05 10:34:00 -03:00
50690f01cf Fix settings
Some checks failed
Build / Code quality (push) Has been cancelled
2025-02-05 10:33:23 -03:00
64d0105d4a Alterando Dockerfile
All checks were successful
Creates a docker image for production / Build the docker image (push) Successful in 43s
Build / Code quality (push) Successful in 9m39s
2025-02-05 10:11:51 -03:00
fc19676a8d Preparando release
Some checks failed
Creates a docker image for production / Build the docker image (push) Failing after 12s
Build / Code quality (push) Has been cancelled
2025-02-05 10:06:48 -03:00
9 changed files with 103 additions and 133 deletions

View File

@@ -3,71 +3,53 @@ name: Creates a docker image for production
on: on:
push: push:
tags: tags:
- 'v*' - "v*"
jobs: jobs:
build: build_docker:
name: Build the docker image name: Build the docker image
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Build started
uses: voxmedia/github-action-slack-notify-build@v1
if: success()
with:
channel: ci-notifications
status: STARTED
color: good
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
- name: Checkout - name: Checkout
uses: actions/checkout@v1 uses: actions/checkout@v4
with: with:
fetch-depth: 1 fetch-depth: 1
- name: Log in to Docker Hub - name: Log in to Nexus Docker Hub
uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9 uses: docker/login-action@v3
with: with:
username: ${{ secrets.DOCKER_HUB_USERNAME }} registry: docker.nexus.makecodes.dev
password: ${{ secrets.DOCKER_HUB_PASSWORD }} username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Extract metadata (tags, labels) for Docker - name: Extract metadata (tags, labels) for Docker
id: meta id: meta
uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38 uses: docker/metadata-action@v5
with: with:
images: redbeard/mines-backend images: docker.nexus.makecodes.dev/mines/backend
- name: Build and push Docker image - name: Build and push
uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc uses: docker/build-push-action@v5
env:
SCOPE: production
with: with:
context: . context: .
push: true push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
- name: Build finished - name: Deploy to production server
if: success() run: |
uses: voxmedia/github-action-slack-notify-build@v1 TOKEN=$(curl --silent --location 'https://auth.makecodes.dev/auth' \
with: --header 'Content-Type: application/json' \
channel: ci-notifications --data '{
status: SUCCESS "email": "'$USERNAME'",
color: good "password": "'$PASSWORD'"
}' | jq -r '.token')
curl --location --silent 'https://deployer.makecodes.dev/deploy' \
--header 'Content-Type: application/json' \
--header "Authorization: Bearer $TOKEN" \
--data '{
"image": "docker.nexus.makecodes.dev/mines/backend",
"service": "mines_backend",
"version": "${{ github.ref_name }}",
"pipeline": "${{ github.run_number }}",
"repository": "mines/backend"
}'
env: env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} USERNAME: ${{ secrets.SERVER_AUTH_USERNAME }}
deploy: PASSWORD: ${{ secrets.SERVER_AUTH_PASSWORD }}
name: Deploy
runs-on: ubuntu-latest
needs:
- build
steps:
- name: Deploy to production
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USERNAME }}
password: ${{ secrets.SSH_PASSWORD }}
port: ${{ secrets.SSH_PORT }}
script: |
cd /media/data/apps/mines-backend
docker pull redbeard/mines-backend:latest
docker-compose up -d app0
docker-compose up -d app1
docker exec -t mines-be0 python manage.py migrate
docker image prune -f

View File

@@ -1,52 +1,72 @@
FROM python:3.8-slim-buster FROM python:3.12.6-bullseye AS base
ARG SCOPE ARG APP_USER \
APP_GROUP \
UID \
GID \
NEXUS_USERNAME \
NEXUS_PASSWORD
# Setup env ENV APP_USER=${APP_USER:-mines} \
ENV SCOPE=${SCOPE} \ APP_GROUP=${APP_GROUP:-mines} \
# python UID=${UID:-1000} \
PYTHONDONTWRITEBYTECODE=1 \ GID=${GID:-1000} \
PYTHONFAULTHANDLER=1 \ PYTHONFAULTHANDLER=1 \
PYTHONUNBUFFERED=1 \ PYTHONUNBUFFERED=1 \
PYTHONHASHSEED=random \ PYTHONHASHSEED=random \
LC_ALL=C.UTF-8 \ PYTHONDONTWRITEBYTECODE=1 \
LANG=C.UTF-8 \ LC_ALL=C.UTF-8 \
# pip LANG=C.UTF-8 \
PIP_NO_CACHE_DIR=off \ PIP_NO_CACHE_DIR=off \
PIP_DISABLE_PIP_VERSION_CHECK=on \ PIP_DISABLE_PIP_VERSION_CHECK=on \
PIP_DEFAULT_TIMEOUT=100 \ PIP_DEFAULT_TIMEOUT=100 \
# poetry: UV_LINK_MODE=copy \
POETRY_VERSION=1.1.13 \ UV_PROJECT_ENVIRONMENT=/.venv \
POETRY_NO_INTERACTION=1 \ VIRTUAL_ENV=/.venv \
POETRY_VIRTUALENVS_CREATE=false \ PATH="/.venv/bin:$PATH"
POETRY_CACHE_DIR='/var/cache/pypoetry' \
POETRY_HOME='/usr/local'
SHELL ["/bin/bash", "-eo", "pipefail", "-c"] COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv
RUN apt-get update && apt-get upgrade -y \ WORKDIR /app
&& apt-get install --no-install-recommends -y \
COPY uv.lock pyproject.toml ./
# Dependências
RUN echo "deb http://apt.postgresql.org/pub/repos/apt bullseye-pgdg main" > /etc/apt/sources.list.d/pgdg.list && \
curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - && \
apt-get update && \
apt-get install -y \
bash \ bash \
curl \ clang \
build-essential \ build-essential \
curl \
default-libmysqlclient-dev \ default-libmysqlclient-dev \
gnupg \
jq \
libc6 \
libffi-dev \
libjpeg-dev \
libmariadb-dev \
libpq-dev \ libpq-dev \
# Installing `poetry` package manager: libpthread-stubs0-dev \
# https://github.com/python-poetry/poetry libxml2-dev \
&& curl -sSL 'https://install.python-poetry.org' | python - \ libxslt-dev \
&& poetry --version \ mariadb-client \
# Cleaning cache: zlib1g-dev && \
&& apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \ apt-get install -y --no-install-recommends gcc && \
&& apt-get clean -y && rm -rf /var/lib/apt/lists/* apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false && \
apt-get clean -y && rm -rf /var/lib/apt/lists/* && \
uv sync --dev && \
uv cache clean && \
. $VIRTUAL_ENV/bin/activate
# Copy only requirements to cache them in docker layer
WORKDIR /code
COPY poetry.lock pyproject.toml /code/
RUN poetry config virtualenvs.create false \ # Copia o restante do código da aplicação
&& poetry install $(test "$SCOPE" == production && echo "--no-dev") --no-interaction --no-ansi COPY . /app
# Creating folders, and files for a project: RUN groupadd -r $APP_GROUP -g $GID && \
COPY . /code useradd -r -g $APP_GROUP -u $UID $APP_USER --shell /bin/bash --home /app
CMD ["/code/commands/run-prod.sh"] USER $APP_USER
CMD ["/app/commands/run-prod.sh"]

View File

@@ -46,7 +46,6 @@ class GameEventResource(APIView):
def post(self, request, game_id): def post(self, request, game_id):
"""Creates a new event""" """Creates a new event"""
try: try:
game = Game.objects.get(pk=game_id) game = Game.objects.get(pk=game_id)
except Game.DoesNotExist: except Game.DoesNotExist:

View File

@@ -12,7 +12,7 @@ OP_ITEM_TITLE = os.environ.get('OP_ITEM_TITLE', 'mines')
op_env = OnePassword(SCOPE, OP_ITEM_TITLE) op_env = OnePassword(SCOPE, OP_ITEM_TITLE)
sentry_sdk.init( sentry_sdk.init(
dsn=op_env.get('settings.SENTRY_DSN'), dsn=op_env.get('SENTRY_DSN'),
integrations=[DjangoIntegration()], integrations=[DjangoIntegration()],
environment=SCOPE, environment=SCOPE,
send_default_pii=False, send_default_pii=False,
@@ -23,12 +23,12 @@ sentry_sdk.init(
BASE_DIR = Path(__file__).resolve().parent.parent BASE_DIR = Path(__file__).resolve().parent.parent
# SECURITY WARNING: keep the secret key used in production secret! # SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = op_env.get('settings.SECRET_KEY') SECRET_KEY = op_env.get('SECRET_KEY')
# SECURITY WARNING: don't run with debug turned on in production! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = op_env.get('settings.DEBUG', '0') in ['1', 'true'] DEBUG = op_env.get('DEBUG', '0') in ['1', 'true']
ALLOWED_HOSTS = op_env.get('settings.ALLOWED_HOSTS', '127.0.0.1,localhost').split(',') ALLOWED_HOSTS = op_env.get('ALLOWED_HOSTS', '127.0.0.1,localhost').split(',')
# Application definition # Application definition
INSTALLED_APPS = [ INSTALLED_APPS = [
@@ -131,8 +131,7 @@ REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': ('rest_framework.renderers.JSONRenderer',), 'DEFAULT_RENDERER_CLASSES': ('rest_framework.renderers.JSONRenderer',),
} }
if DEBUG is True: CORS_ALLOW_ALL_ORIGINS = True
CORS_ALLOW_ALL_ORIGINS = True
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

View File

@@ -1,13 +1,7 @@
from django.conf import settings
from django.contrib import admin from django.contrib import admin
from django.urls import include, path from django.urls import include, path
urlpatterns = [ urlpatterns = [
path('', include('api.urls')), path('', include('api.urls')),
path('admin/', admin.site.urls),
] ]
# We need this only for development purpose
if settings.DEBUG is True:
urlpatterns += [
path('admin/', admin.site.urls),
]

View File

@@ -1,25 +0,0 @@
import onepasswordconnectsdk
from onepasswordconnectsdk.client import Client, new_client_from_environment
def get_op_config():
op_client: Client = new_client_from_environment()
OP_DJANGO_SETTINGS_VARS = [
'database.host',
'database.port',
'database.name',
'database.user',
'database.password',
'settings.ALLOWED_HOSTS',
'settings.DEBUG',
'settings.SCOPE',
'settings.SENTRY_DSN',
'settings.SECRET_KEY',
]
op_config_get = {}
for var in OP_DJANGO_SETTINGS_VARS:
op_config_get[var] = {'opitem': 'mines', 'opfield': var}
return onepasswordconnectsdk.load_dict(op_client, op_config_get)

View File

@@ -7,4 +7,4 @@ class GameConfig(AppConfig):
verbose_name_plural = 'Games' verbose_name_plural = 'Games'
def ready(self): def ready(self):
pass from game import signals # noqa

View File

@@ -8,7 +8,7 @@ from .models import EventTypes, Game, GameEvent, GameStatuses
@receiver(post_save, sender=Game) @receiver(post_save, sender=Game)
def game_start(sender, signal, instance, **kwargs): def game_start(sender, signal, instance, **kwargs):
"""If the game was just created, insert the first event START_GAME""" """If the game was just created, insert the first event START_GAME"""
if not instance.status == GameStatuses.NOT_PLAYED: if instance.status != GameStatuses.NOT_PLAYED:
return return
GameEvent.objects.get_or_create(game=instance, type=EventTypes.START_GAME) GameEvent.objects.get_or_create(game=instance, type=EventTypes.START_GAME)
@@ -16,7 +16,7 @@ def game_start(sender, signal, instance, **kwargs):
@receiver(pre_save, sender=GameEvent) @receiver(pre_save, sender=GameEvent)
def identify_click_event(sender, signal, instance, **kwargs): def identify_click_event(sender, signal, instance, **kwargs):
"""Verify what is on the naive click: mine, point or empty""" """Verify what is on the naive click: mine, point or empty"""
if not instance.type == EventTypes.CLICK_NAIVE: if instance.type != EventTypes.CLICK_NAIVE:
return return
if instance.row is None and instance.col is None: if instance.row is None and instance.col is None:

View File

@@ -74,6 +74,7 @@ lint.ignore = [
"RUF012", "RUF012",
"N806", "N806",
"ARG002", "ARG002",
"PGH004",
"N805", # Missing type annotation for self in method (Pydantic don't like this) "N805", # Missing type annotation for self in method (Pydantic don't like this)
"SIM108", # Use ternary operator {contents} instead of if-else-block "SIM108", # Use ternary operator {contents} instead of if-else-block
"RUF009", # Missing dataclass field. "RUF009", # Missing dataclass field.