Repository: nautobot/nautobot

Issue:
nautobot-dev (final-dev) docker image doesn't start
<!--
    NOTE: IF YOUR ISSUE DOES NOT FOLLOW THIS TEMPLATE, IT WILL BE CLOSED.

    This form is only for reporting reproducible bugs. If you need assistance
    with Nautobot installation, or if you have a general question, please start a
    discussion instead: https://github.com/nautobot/nautobot/discussions

    Please describe the environment in which you are running Nautobot. Be sure
    that you are running an unmodified instance of the latest stable release
    before submitting a bug report, and that any plugins have been disabled.
-->
### Environment
* Nautobot version (Docker tag too if applicable): 1.4.2 -> latest
* Python version: 3.7 -> 3.10
* Database platform, version: n/a
* Middleware(s): n/a

<!--
    Describe in detail the exact steps that someone else can take to reproduce
    this bug using the current stable release of Nautobot. Begin with the
    creation of any necessary database objects and call out every operation
    being performed explicitly. If reporting a bug in the REST API, be sure to
    reconstruct the raw HTTP request(s) being made: Don't rely on a client
    library such as pynautobot.
-->
### Steps to Reproduce
1. docker run --rm -it ghcr.io/nautobot/nautobot-dev:1.4.7-py3.10

<!-- What did you expect to happen? -->
### Expected Behavior
Nautobot Dev should start up

<!-- What happened instead? -->
### Observed Behavior
```
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/nautobot/extras/plugins/utils.py", line 64, in load_plugin
    plugin = importlib.import_module(plugin_name)
  File "/usr/local/lib/python3.10/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1004, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'example_plugin'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/nautobot/core/runner/runner.py", line 116, in settings_callback
    initializer(
  File "/usr/local/lib/python3.10/site-packages/nautobot/core/cli.py", line 176, in _configure_settings
    load_plugins(settings)
  File "/usr/local/lib/python3.10/site-packages/nautobot/extras/plugins/utils.py", line 54, in load_plugins
    load_plugin(plugin_name, settings)
  File "/usr/local/lib/python3.10/site-packages/nautobot/extras/plugins/utils.py", line 67, in load_plugin
    raise PluginNotFound(
nautobot.extras.plugins.exceptions.PluginNotFound: Unable to import plugin example_plugin: Module not found. Check that the plugin module has been installed within the correct Python environment.
```


Discussion:
Thanks for the report! Hypothesis:

- `example_plugin` is copied in under `/source/examples/example_plugin` and installed in the `dependencies-dev-python` target in editable mode
- both `dev` and `final-dev` targets use `development/nautobot_config.py` as their Nautobot config file, which includes the example plugin
- `dev` (what we use for Nautobot core development) works just fine this way.
- `final-dev` (what we publish as `nautobot-dev`) removes everything under the `/source` directory, breaking the editable installation of the example plugin.

Possible solutions:

- for `final-dev`, build the example plugin as a wheel and install it as non-editable so that the removal of `/source` doesn't impact it?
- for `final-dev`, use a different `nautobot_config.py` that doesn't include the example plugin?

Resolving patch:
diff --git a/tasks.py b/tasks.py
--- a/tasks.py
+++ b/tasks.py
@@ -192,9 +192,10 @@ def run_command(context, command, **kwargs):
         "cache": "Whether to use Docker's cache when building the image. (Default: enabled)",
         "poetry_parallel": "Enable/disable poetry to install packages in parallel. (Default: True)",
         "pull": "Whether to pull Docker images when building the image. (Default: disabled)",
+        "skip_docs_build": "Skip (re)build of documentation after building the image.",
     }
 )
-def build(context, force_rm=False, cache=True, poetry_parallel=True, pull=False):
+def build(context, force_rm=False, cache=True, poetry_parallel=True, pull=False, skip_docs_build=False):
     """Build Nautobot docker image."""
     command = f"build --build-arg PYTHON_VER={context.nautobot.python_ver}"
 
@@ -211,8 +212,9 @@ def build(context, force_rm=False, cache=True, poetry_parallel=True, pull=False)
 
     docker_compose(context, command, env={"DOCKER_BUILDKIT": "1", "COMPOSE_DOCKER_CLI_BUILD": "1"})
 
-    # Build the docs so they are available.
-    build_nautobot_docs(context)
+    if not skip_docs_build:
+        # Build the docs so they are available. Skip if you're using a `final-dev` or `final` image instead of `dev`.
+        build_nautobot_docs(context)
 
 
 @task(
@@ -265,6 +267,8 @@ def buildx(
     print(f"Building Nautobot {target} target with Python {context.nautobot.python_ver} for {platforms}...")
     if tag is None:
         if target == "dev":
+            pass
+        if target == "final-dev":
             tag = f"networktocode/nautobot-dev-py{context.nautobot.python_ver}:local"
         elif target == "final":
             tag = f"networktocode/nautobot-py{context.nautobot.python_ver}:local"


Test patch: