Add Copier, migrate from Cookiecutter, in a way that supports using the project as is, forking or cloning it (#612)

* 🔧 Add first Copier config

* 🔧 Add custom copier answers file

* 🔨 Add Copier script to update .env after generating/copying

* 🙈 Update .gitignores from Copier updates

* 🔧 Update .env, restructure in order of relevance

* 🔧 Remove Copier config for SMTP port, if necessary, it can be overwritten in .env

* ♻️ Refactor Copier files, make them less visible

* 🔧 Update Copier config

* 🔥 Remove Cookiecutter files
This commit is contained in:
Sebastián Ramírez
2024-02-25 21:20:20 +01:00
committed by GitHub
parent 0cc802eec8
commit 42726193d0
9 changed files with 179 additions and 109 deletions

2
.gitignore vendored
View File

@@ -1,3 +1 @@
.vscode .vscode
.mypy_cache
poetry.lock

View File

@@ -1,44 +0,0 @@
{
"project_name": "Base Project",
"project_slug": "{{ cookiecutter.project_name|lower|replace(' ', '-') }}",
"domain_main": "{{cookiecutter.project_slug}}.com",
"domain_staging": "stag.{{cookiecutter.domain_main}}",
"docker_swarm_stack_name_main": "{{cookiecutter.domain_main|replace('.', '-')}}",
"docker_swarm_stack_name_staging": "{{cookiecutter.domain_staging|replace('.', '-')}}",
"secret_key": "changethis",
"first_superuser": "admin@{{cookiecutter.domain_main}}",
"first_superuser_password": "changethis",
"backend_cors_origins": "[\"http://localhost\", \"http://localhost:4200\", \"http://localhost:3000\", \"http://localhost:8080\", \"https://localhost\", \"https://localhost:4200\", \"https://localhost:3000\", \"https://localhost:8080\", \"http://dev.{{cookiecutter.domain_main}}\", \"https://{{cookiecutter.domain_staging}}\", \"https://{{cookiecutter.domain_main}}\", \"http://local.dockertoolbox.tiangolo.com\", \"http://localhost.tiangolo.com\"]",
"smtp_port": "587",
"smtp_host": "",
"smtp_user": "",
"smtp_password": "",
"smtp_emails_from_email": "info@{{cookiecutter.domain_main}}",
"postgres_password": "changethis",
"pgadmin_default_user": "{{cookiecutter.first_superuser}}",
"pgadmin_default_user_password": "{{cookiecutter.first_superuser_password}}",
"traefik_constraint_tag": "{{cookiecutter.domain_main}}",
"traefik_constraint_tag_staging": "{{cookiecutter.domain_staging}}",
"traefik_public_constraint_tag": "traefik-public",
"flower_auth": "admin:{{cookiecutter.first_superuser_password}}",
"sentry_dsn": "",
"docker_image_prefix": "",
"docker_image_backend": "{{cookiecutter.docker_image_prefix}}backend",
"docker_image_celeryworker": "{{cookiecutter.docker_image_prefix}}celeryworker",
"docker_image_frontend": "{{cookiecutter.docker_image_prefix}}frontend",
"_copy_without_render": [
"frontend/src/**/*.html",
"frontend/src/**/*.vue",
"frontend/node_modules/*",
"backend/app/app/email-templates/**"
]
}

View File

@@ -0,0 +1 @@
{{ _copier_answers|to_json -}}

View File

@@ -0,0 +1,22 @@
from pathlib import Path
import json
# Update the .env file with the answers from the .copier-answers.yml file
# without using Jinja2 templates in the .env file, this way the code works as is
# without needing Copier, but if Copier is used, the .env file will be updated
root_path = Path(__file__).parent.parent
answers_path = Path(__file__).parent / ".copier-answers.yml"
answers = json.loads(answers_path.read_text())
env_path = root_path / ".env"
env_content = env_path.read_text()
lines = []
for line in env_content.splitlines():
for key, value in answers.items():
upper_key = key.upper()
if line.startswith(f"{upper_key}="):
new_line = line.replace(line, f"{upper_key}={value}")
lines.append(new_line)
break
else:
lines.append(line)
env_path.write_text("\n".join(lines))

View File

@@ -2,8 +2,41 @@
DOMAIN=localhost DOMAIN=localhost
# DOMAIN=localhost.tiangolo.com # DOMAIN=localhost.tiangolo.com
STACK_NAME=full-stack-fastapi-postgresql PROJECT_NAME="FastAPI Project"
STACK_NAME=fastapi-project
# Backend
BACKEND_CORS_ORIGINS="[\"http://localhost\", \"http://localhost:4200\", \"http://localhost:3000\", \"http://localhost:8080\", \"https://localhost\", \"https://localhost:4200\", \"https://localhost:3000\", \"https://localhost:8080\", \"http://local.dockertoolbox.tiangolo.com\", \"http://localhost.tiangolo.com\"]"
SECRET_KEY=changethis
FIRST_SUPERUSER=admin@example.com
FIRST_SUPERUSER_PASSWORD=changethis
SMTP_HOST=
SMTP_USER=
SMTP_PASSWORD=
EMAILS_FROM_EMAIL=info@example.com
SMTP_TLS=True
SMTP_PORT=587
USERS_OPEN_REGISTRATION=False
# Postgres
POSTGRES_SERVER=db
POSTGRES_USER=postgres
POSTGRES_DB=app
POSTGRES_PASSWORD=changethis
# PgAdmin
PGADMIN_DEFAULT_EMAIL=admin@example.com
PGADMIN_DEFAULT_PASSWORD=changethis
PGADMIN_LISTEN_PORT=5050
SENTRY_DSN=
# Flower
FLOWER_BASIC_AUTH=
# Traefik
TRAEFIK_PUBLIC_NETWORK=traefik-public TRAEFIK_PUBLIC_NETWORK=traefik-public
TRAEFIK_TAG=traefik TRAEFIK_TAG=traefik
TRAEFIK_PUBLIC_TAG=traefik-public TRAEFIK_PUBLIC_TAG=traefik-public
@@ -13,34 +46,3 @@ DOCKER_IMAGE_BACKEND=backend
DOCKER_IMAGE_CELERYWORKER=celery DOCKER_IMAGE_CELERYWORKER=celery
DOCKER_IMAGE_FRONTEND=frontend DOCKER_IMAGE_FRONTEND=frontend
DOCKER_IMAGE_NEW_FRONTEND=new-frontend DOCKER_IMAGE_NEW_FRONTEND=new-frontend
# Backend
BACKEND_CORS_ORIGINS="[\"http://localhost\", \"http://localhost:4200\", \"http://localhost:3000\", \"http://localhost:8080\", \"https://localhost\", \"https://localhost:4200\", \"https://localhost:3000\", \"https://localhost:8080\", \"http://local.dockertoolbox.tiangolo.com\", \"http://localhost.tiangolo.com\"]"
PROJECT_NAME="FastAPI Project"
SECRET_KEY=changethis
FIRST_SUPERUSER=admin@example.com
FIRST_SUPERUSER_PASSWORD=changethis
SMTP_TLS=True
SMTP_PORT=587
SMTP_HOST=
SMTP_USER=
SMTP_PASSWORD=
EMAILS_FROM_EMAIL=info@example.com
USERS_OPEN_REGISTRATION=False
SENTRY_DSN=
# Flower
FLOWER_BASIC_AUTH=
# Postgres
POSTGRES_SERVER=db
POSTGRES_USER=postgres
POSTGRES_PASSWORD=changethis
POSTGRES_DB=app
# PgAdmin
PGADMIN_LISTEN_PORT=5050
PGADMIN_DEFAULT_EMAIL=admin@example.com
PGADMIN_DEFAULT_PASSWORD=changethis

View File

@@ -4,3 +4,6 @@ app.egg-info
.mypy_cache .mypy_cache
.coverage .coverage
htmlcov htmlcov
poetry.lock
.cache
.venv

View File

@@ -1 +0,0 @@
.cache

View File

@@ -1,30 +0,0 @@
default_context:
project_name: '{{ cookiecutter.project_name }}'
project_slug: '{{ cookiecutter.project_slug }}'
domain_main: '{{ cookiecutter.domain_main }}'
domain_staging: '{{ cookiecutter.domain_staging }}'
docker_swarm_stack_name_main: '{{ cookiecutter.docker_swarm_stack_name_main }}'
docker_swarm_stack_name_staging: '{{ cookiecutter.docker_swarm_stack_name_staging }}'
secret_key: '{{ cookiecutter.secret_key }}'
first_superuser: '{{ cookiecutter.first_superuser }}'
first_superuser_password: '{{ cookiecutter.first_superuser_password }}'
backend_cors_origins: '{{ cookiecutter.backend_cors_origins }}'
smtp_port: '{{ cookiecutter.smtp_port }}'
smtp_host: '{{ cookiecutter.smtp_host }}'
smtp_user: '{{ cookiecutter.smtp_user }}'
smtp_password: '{{ cookiecutter.smtp_password }}'
smtp_emails_from_email: '{{ cookiecutter.smtp_emails_from_email }}'
postgres_password: '{{ cookiecutter.postgres_password }}'
pgadmin_default_user: '{{ cookiecutter.pgadmin_default_user }}'
pgadmin_default_user_password: '{{ cookiecutter.pgadmin_default_user_password }}'
traefik_constraint_tag: '{{ cookiecutter.traefik_constraint_tag }}'
traefik_constraint_tag_staging: '{{ cookiecutter.traefik_constraint_tag_staging }}'
traefik_public_constraint_tag: '{{ cookiecutter.traefik_public_constraint_tag }}'
flower_auth: '{{ cookiecutter.flower_auth }}'
sentry_dsn: '{{ cookiecutter.sentry_dsn }}'
docker_image_prefix: '{{ cookiecutter.docker_image_prefix }}'
docker_image_backend: '{{ cookiecutter.docker_image_backend }}'
docker_image_celeryworker: '{{ cookiecutter.docker_image_celeryworker }}'
docker_image_frontend: '{{ cookiecutter.docker_image_frontend }}'
_copy_without_render: [frontend/src/**/*.html, frontend/src/**/*.vue, frontend/node_modules/*, backend/app/app/email-templates/**]
_template: ./

119
src/copier.yml Normal file
View File

@@ -0,0 +1,119 @@
domain:
type: str
help: |
Which domain name to use for the project, by default,
localhost, but you should change it later (in .env)
default: localhost
project_name:
type: str
help: The name of the project, shown to API users (in .env)
default: FastAPI Project
stack_name:
type: str
help: The name of the stack used for Docker Compose labels (no spaces) (in .env)
default: fastapi-project
secret_key:
type: str
help: |
'The secret key for the project, used for security,
stored in .env, you can generate one with:
python -c "import secrets; print(secrets.token_urlsafe(32))"'
default: changethis
first_superuser:
type: str
help: The email of the first superuser (in .env)
default: admin@example.com
first_superuser_password:
type: str
help: The password of the first superuser (in .env)
default: changethis
smtp_host:
type: str
help: The SMTP server host to send emails, you can set it later in .env
default: ""
smtp_user:
type: str
help: The SMTP server user to send emails, you can set it later in .env
default: ""
smtp_password:
type: str
help: The SMTP server password to send emails, you can set it later in .env
default: ""
emails_from_email:
type: str
help: The email account to send emails from, you can set it later in .env
default: info@example.com
postgres_password:
type: str
help: |
'The password for the PostgreSQL database, stored in .env,
you can generate one with:
python -c "import secrets; print(secrets.token_urlsafe(32))"'
default: changethis
pgadmin_default_email:
type: str
help: The default user email for pgAdmin, you can set it later in .env
default: admin@example.com
pgadmin_default_password:
type: str
help: The default user password for pgAdmin, stored in .env
default: changethis
sentry_dsn:
type: str
help: The DSN for Sentry, if you are using it, you can set it later in .env
default: ""
_exclude:
# Global
- .vscode
- .mypy_cache
- poetry.lock
# Python
- __pycache__
- app.egg-info
- "*.pyc"
- .mypy_cache
- .coverage
- htmlcov
- poetry.lock
- .cache
- .venv
# Frontend
# Logs
- logs
- "*.log"
- npm-debug.log*
- yarn-debug.log*
- yarn-error.log*
- pnpm-debug.log*
- lerna-debug.log*
- node_modules
- dist
- dist-ssr
- "*.local"
# Editor directories and files
- .idea
- .DS_Store
- "*.suo"
- "*.ntvs*"
- "*.njsproj"
- "*.sln"
- "*.sw?"
_answers_file: .copier/.copier-answers.yml
_tasks:
- "python .copier/update_dotenv.py"