Repository: meltano/meltano

Issue:
bug: `meltano install` exits success even if migrations fail
I would expect `meltano install` to fail and exit with a non-zero exit code if the migrations fail. Instead, it proceeds to install plugins.

To reproduce:

```
$ meltano --version && python --version
meltano, version 2.2.0
Python 3.9.13
$ meltano init example
$ cd example
# this is just an example of a way to make migrations fail
$ sqlite3 .meltano/meltano.db "UPDATE alembic_version SET version_num = 'garbage';"
$ meltano install                                                                   
2022-07-12T16:35:37.771519Z [info     ] Environment 'dev' is active
2022-07-12T16:35:38.860146Z [error    ] No such revision or branch 'garbage' 
Traceback (most recent call last):
  File ".venv/lib/python3.9/site-packages/meltano/core/migration_service.py", line 89, in upgrade
    self.ensure_migration_needed(script, context, head)
  File ".venv/lib/python3.9/site-packages/meltano/core/migration_service.py", line 55, in ensure_migration_needed
    for rev in script.iterate_revisions(current_head, "base"):
  File ".venv/lib/python3.9/site-packages/alembic/script/revision.py", line 799, in iterate_revisions
    revisions, heads = fn(
  File ".venv/lib/python3.9/site-packages/alembic/script/revision.py", line 1426, in _collect_upgrade_revisions
    for rev in self._parse_upgrade_target(
  File ".venv/lib/python3.9/site-packages/alembic/script/revision.py", line 1218, in _parse_upgrade_target
    return self.get_revisions(target)
  File ".venv/lib/python3.9/site-packages/alembic/script/revision.py", line 552, in get_revisions
    return tuple(
  File ".venv/lib/python3.9/site-packages/alembic/script/revision.py", line 553, in <genexpr>
    self._revision_for_ident(rev_id, branch_label)
  File ".venv/lib/python3.9/site-packages/alembic/script/revision.py", line 624, in _revision_for_ident
    raise ResolutionError(
alembic.script.revision.ResolutionError: No such revision or branch 'garbage'
Cannot upgrade the system database. It might be corrupted or was created before database migrations where introduced (v0.34.0)
Installing 0 plugins...
$ echo $?                                                                           
0



Discussion:
This problem made it hard to realize that I was running into the problem from  #6405 since running `meltano install`  succeeded in our docker build but didn't actually successfully set up the database.
@pdebelak thanks for reporting. I've marked it to be worked on in early August, but it could get pulled up sooner.

Resolving patch:
diff --git a/src/meltano/cli/params.py b/src/meltano/cli/params.py
--- a/src/meltano/cli/params.py
+++ b/src/meltano/cli/params.py
@@ -1,3 +1,5 @@
+"""Click parameter helper decorators."""
+
 from __future__ import annotations
 
 import functools
@@ -6,12 +8,19 @@
 from click.globals import get_current_context as get_current_click_context
 
 from meltano.core.db import project_engine
+from meltano.core.migration_service import MigrationError
 from meltano.core.project_settings_service import ProjectSettingsService
 
 from .utils import CliError
 
 
 def database_uri_option(func):
+    """Database URI Click option decorator.
+
+    args:
+        func: The function to decorate.
+    """
+
     @click.option("--database-uri", help="System database URI.")
     def decorate(*args, database_uri=None, **kwargs):
         if database_uri:
@@ -28,9 +37,20 @@ class pass_project:  # noqa: N801
     __name__ = "project"
 
     def __init__(self, migrate=False):
+        """Instantiate decorator.
+
+        args:
+            migrate: Flag to perform database migration before passing the project.
+        """
         self.migrate = migrate
 
     def __call__(self, func):
+        """Return decorated function.
+
+        args:
+            func: The function to decorate.
+        """
+
         @database_uri_option
         def decorate(*args, **kwargs):
             ctx = get_current_click_context()
@@ -48,9 +68,12 @@ def decorate(*args, **kwargs):
             if self.migrate:
                 from meltano.core.migration_service import MigrationService
 
-                migration_service = MigrationService(engine)
-                migration_service.upgrade(silent=True)
-                migration_service.seed(project)
+                try:
+                    migration_service = MigrationService(engine)
+                    migration_service.upgrade(silent=True)
+                    migration_service.seed(project)
+                except MigrationError as err:
+                    raise CliError(str(err))
 
             func(project, *args, **kwargs)
 
diff --git a/src/meltano/core/migration_service.py b/src/meltano/core/migration_service.py
--- a/src/meltano/core/migration_service.py
+++ b/src/meltano/core/migration_service.py
@@ -105,10 +105,8 @@ def upgrade(  # noqa: WPS213, WPS231 too many expression and too complex
                 click.secho("System database up-to-date.")
         except Exception as err:
             logging.exception(str(err))
-            click.secho(
-                "Cannot upgrade the system database. It might be corrupted or was created before database migrations where introduced (v0.34.0)",
-                fg="yellow",
-                err=True,
+            raise MigrationError(
+                "Cannot upgrade the system database. It might be corrupted or was created before database migrations where introduced (v0.34.0)"
             )
         finally:
             conn.close()


Test patch: