Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a devcontainer configuration with Docker #4198

Merged
merged 24 commits into from
Jul 3, 2023
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,11 @@ Answer the prompts with your own desired [options](http://cookiecutter-django.re
Choose from 1, 2 [1]: 1
timezone [UTC]: America/Los_Angeles
windows [n]: n
use_pycharm [n]: y
Select an editor to use. The choices are:
1 - None
2 - PyCharm
3 - VS Code
Choose from 1, 2, 3 [1]: 1
use_docker [n]: n
Select postgresql_version:
1 - 14
Expand Down
2 changes: 1 addition & 1 deletion cookiecutter.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"username_type": ["username", "email"],
"timezone": "UTC",
"windows": "n",
"use_pycharm": "n",
"editor": ["None", "PyCharm", "VS Code"],
"use_docker": "n",
"postgresql_version": ["14", "13", "12", "11", "10"],
"cloud_provider": ["AWS", "GCP", "Azure", "None"],
Expand Down
12 changes: 9 additions & 3 deletions docs/project-generation-options.rst
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,15 @@ timezone:
windows:
Indicates whether the project should be configured for development on Windows.

use_pycharm:
Indicates whether the project should be configured for development with PyCharm_.
editor:
Select an editor to use. The choices are:

1. None
2. PyCharm_
3. `VS Code`_

use_docker:
Indicates whether the project should be configured to use Docker_ and `Docker Compose`_.
Indicates whether the project should be configured to use Docker_, `Docker Compose`_ and `devcontainer`_.

postgresql_version:
Select a PostgreSQL_ version to use. The choices are:
Expand Down Expand Up @@ -148,9 +152,11 @@ debug:
.. _Apache Software License 2.0: http://www.apache.org/licenses/LICENSE-2.0

.. _PyCharm: https://www.jetbrains.com/pycharm/
.. _VS Code: https://github.com/microsoft/vscode

.. _Docker: https://github.com/docker/docker
.. _Docker Compose: https://docs.docker.com/compose/
.. _devcontainer: https://containers.dev/

.. _PostgreSQL: https://www.postgresql.org/docs/

Expand Down
20 changes: 16 additions & 4 deletions hooks/post_gen_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,24 @@ def remove_pycharm_files():
shutil.rmtree(docs_dir_path)


def create_devcontainer_bash_history_file():
history_dir_path = ".history"
if not os.path.exists(history_dir_path):
os.mkdir(history_dir_path)

history_file_path = ".history/bash_history"
with open(history_file_path, "a"):
pass
browniebroke marked this conversation as resolved.
Show resolved Hide resolved


def remove_docker_files():
shutil.rmtree(".devcontainer")
shutil.rmtree("compose")

file_names = ["local.yml", "production.yml", ".dockerignore"]
for file_name in file_names:
os.remove(file_name)
if "{{ cookiecutter.use_pycharm }}".lower() == "y":
if "{{ cookiecutter.editor }}".lower() == "PyCharm":
file_names = ["docker_compose_up_django.xml", "docker_compose_up_docs.xml"]
for file_name in file_names:
os.remove(os.path.join(".idea", "runConfigurations", file_name))
Expand Down Expand Up @@ -427,11 +438,12 @@ def main():
if "{{ cookiecutter.username_type }}" == "username":
remove_custom_user_manager_files()

if "{{ cookiecutter.use_pycharm }}".lower() == "n":
if "{{ cookiecutter.editor }}".lower() != "PyCharm":
remove_pycharm_files()

if "{{ cookiecutter.use_docker }}".lower() == "y":
remove_utility_files()
create_devcontainer_bash_history_file()
else:
remove_docker_files()

Expand All @@ -445,8 +457,8 @@ def main():
if "{{ cookiecutter.keep_local_envs_in_vcs }}".lower() == "y":
print(
INFO + ".env(s) are only utilized when Docker Compose and/or "
"Heroku support is enabled so keeping them does not "
"make sense given your current setup." + TERMINATOR
"Heroku support is enabled so keeping them does not make sense "
"given your current setup." + TERMINATOR
)
remove_envs_and_associated_files()
else:
Expand Down
16 changes: 9 additions & 7 deletions tests/test_cookiecutter_generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,9 @@ def context():
{"open_source_license": "Not open source"},
{"windows": "y"},
{"windows": "n"},
{"use_pycharm": "y"},
{"use_pycharm": "n"},
{"editor": "None"},
{"editor": "PyCharm"},
{"editor": "VS Code"},
{"use_docker": "y"},
{"use_docker": "n"},
{"postgresql_version": "14"},
Expand Down Expand Up @@ -373,14 +374,15 @@ def test_error_if_incompatible(cookies, context, invalid_context):


@pytest.mark.parametrize(
["use_pycharm", "pycharm_docs_exist"],
["editor", "pycharm_docs_exist"],
[
("n", False),
("y", True),
("None", False),
("PyCharm", True),
("VS Code", False),
],
)
def test_pycharm_docs_removed(cookies, context, use_pycharm, pycharm_docs_exist):
context.update({"use_pycharm": use_pycharm})
def test_pycharm_docs_removed(cookies, context, editor, pycharm_docs_exist):
context.update({"editor": editor})
result = cookies.bake(extra_context=context)

with open(f"{result.project_path}/docs/index.rst") as f:
Expand Down
20 changes: 20 additions & 0 deletions {{cookiecutter.project_slug}}/.devcontainer/bashrc.override.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

#
# .bashrc.override.sh
#

# persistent bash history
HISTFILE=~/.bash_history
PROMPT_COMMAND="history -a; $PROMPT_COMMAND"

# set some django env vars
source /entrypoint

# restore default shell options
set +o errexit
set +o pipefail
set +o nounset

# start ssh-agent
# https://code.visualstudio.com/docs/remote/troubleshooting
eval "$(ssh-agent -s)"
86 changes: 86 additions & 0 deletions {{cookiecutter.project_slug}}/.devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// For format details, see https://containers.dev/implementors/json_reference/
{
"name": "{{cookiecutter.project_slug}}_dev",
"dockerComposeFile": [
"../local.yml"
],
"init": true,
"mounts": [
{
"source": "./.history/bash_history",
"target": "/home/dev-user/.bash_history",
"type": "bind"
},
{
"source": "~/.ssh",
"target": "/tmp",
"type": "bind"
},
{
"source": "~/.ssh",
"target": "/home/dev-user/.ssh",
"type": "bind"
}
],
// Tells devcontainer.json supporting services / tools whether they should run
// /bin/sh -c "while sleep 1000; do :; done" when starting the container instead of the container’s default command
"overrideCommand": true,
"service": "django",
// "remoteEnv": {"PATH": "/home/dev-user/.local/bin:${containerEnv:PATH}"},
"remoteUser": "dev-user",
"workspaceFolder": "/app",
// Set *default* container specific settings.json values on container create.
"customizations": {
{% if cookiecutter.editor == "VS Code" %}
"vscode": {
"settings": {
"editor.formatOnSave": true,
"[python]": {
"analysis.autoImportCompletions": true,
"analysis.typeCheckingMode": "basic",
"defaultInterpreterPath": "/usr/local/bin/python",
"editor.codeActionsOnSave": {
"source.organizeImports": true
},
//"editor.defaultFormatter": "ms-python.black-formatter",
browniebroke marked this conversation as resolved.
Show resolved Hide resolved
// "formatting.autopep8Path": "/usr/local/py-utils/bin/autopep8",
browniebroke marked this conversation as resolved.
Show resolved Hide resolved
"formatting.blackPath": "/usr/local/bin/black",
"formatting.provider": "black",
// "formatting.yapfPath": "/usr/local/py-utils/bin/yapf",
browniebroke marked this conversation as resolved.
Show resolved Hide resolved
"languageServer": "Pylance",
// "linting.banditPath": "/usr/local/py-utils/bin/bandit",
"linting.enabled": true,
"linting.flake8Enabled": true,
"linting.flake8Path": "/usr/local/bin/flake8",
"linting.mypyEnabled": true,
"linting.mypyPath": "/usr/local/bin/mypy",
"linting.pycodestylePath": "/usr/local/bin/pycodestyle",
// "linting.pydocstylePath": "/usr/local/py-utils/bin/pydocstyle",
"linting.pylintEnabled": true,
"linting.pylintPath": "/usr/local/bin/pylint"
}
},
// https://code.visualstudio.com/docs/remote/devcontainerjson-reference#_vs-code-specific-properties
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"davidanson.vscode-markdownlint",
"mrmlnc.vscode-duplicate",
"visualstudioexptteam.vscodeintellicode",
"visualstudioexptteam.intellicode-api-usage-examples",
// python
"ms-python.python",
"ms-python.vscode-pylance",
"ms-python.isort",
// django
"batisteo.vscode-django"
]
}
{% endif %}
},
// Uncomment the next line if you want start specific services in your Docker Compose config.
// "runServices": [],
// Uncomment the next line if you want to keep your containers running after VS Code shuts down.
// "shutdownAction": "none",
// Uncomment the next line to run commands after the container is created.
"postCreateCommand": "cat .devcontainer/bashrc.override.sh >> ~/.bashrc"
}
2 changes: 1 addition & 1 deletion {{cookiecutter.project_slug}}/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ typings/
.history/


{% if cookiecutter.use_pycharm == 'y' -%}
{% if cookiecutter.editor == 'PyCharm' -%}
# Provided default Pycharm Run/Debug Configurations should be tracked by git
# In case of local modifications made by Pycharm, use update-index command
# for each changed file, like this:
Expand Down
1 change: 1 addition & 0 deletions {{cookiecutter.project_slug}}/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.html
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain why we need this one? It seems a bit unrelated (I don't see prettier configured).

I'm asking because In the pre-commit config, we exclude Django templates from prettier in another way:

exclude: '{{cookiecutter.project_slug}}/templates/'

Maybe we should make the 2 exclusins more consistent?

14 changes: 13 additions & 1 deletion {{cookiecutter.project_slug}}/compose/local/django/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,18 @@ ENV BUILD_ENV ${BUILD_ENVIRONMENT}

WORKDIR ${APP_HOME}

{% if cookiecutter.use_docker == "y" %}
# devcontainer dependencies and utils
RUN apt-get update && apt-get install --no-install-recommends -y \
sudo git bash-completion nano ssh

# Create devcontainer user and add it to sudoers
RUN groupadd --gid 1000 dev-user \
&& useradd --uid 1000 --gid dev-user --shell /bin/bash --create-home dev-user \
&& echo dev-user ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/dev-user \
&& chmod 0440 /etc/sudoers.d/dev-user
{% endif %}

# Install required system dependencies
RUN apt-get update && apt-get install --no-install-recommends -y \
# psycopg2 dependencies
Expand All @@ -49,7 +61,7 @@ COPY --from=python-build-stage /usr/src/app/wheels /wheels/

# use wheels to install python dependencies
RUN pip install --no-cache-dir --no-index --find-links=/wheels/ /wheels/* \
&& rm -rf /wheels/
&& rm -rf /wheels/

COPY ./compose/production/django/entrypoint /entrypoint
RUN sed -i 's/\r$//g' /entrypoint
Expand Down
2 changes: 1 addition & 1 deletion {{cookiecutter.project_slug}}/docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Welcome to {{ cookiecutter.project_name }}'s documentation!
:maxdepth: 2
:caption: Contents:

howto{% if cookiecutter.use_pycharm == 'y' %}
howto{% if cookiecutter.editor == 'PyCharm' %}
pycharm/configuration{% endif %}
users

Expand Down