✨ 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:

committed by
GitHub

parent
0cc802eec8
commit
42726193d0
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,3 +1 @@
|
|||||||
.vscode
|
.vscode
|
||||||
.mypy_cache
|
|
||||||
poetry.lock
|
|
||||||
|
@@ -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/**"
|
|
||||||
]
|
|
||||||
}
|
|
1
src/.copier/.copier-answers.yml.jinja
Normal file
1
src/.copier/.copier-answers.yml.jinja
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{{ _copier_answers|to_json -}}
|
22
src/.copier/update_dotenv.py
Normal file
22
src/.copier/update_dotenv.py
Normal 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))
|
66
src/.env
66
src/.env
@@ -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
|
|
||||||
|
3
src/backend/.gitignore
vendored
3
src/backend/.gitignore
vendored
@@ -4,3 +4,6 @@ app.egg-info
|
|||||||
.mypy_cache
|
.mypy_cache
|
||||||
.coverage
|
.coverage
|
||||||
htmlcov
|
htmlcov
|
||||||
|
poetry.lock
|
||||||
|
.cache
|
||||||
|
.venv
|
||||||
|
1
src/backend/app/tests/.gitignore
vendored
1
src/backend/app/tests/.gitignore
vendored
@@ -1 +0,0 @@
|
|||||||
.cache
|
|
@@ -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
119
src/copier.yml
Normal 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"
|
Reference in New Issue
Block a user