diff --git a/datasette/cli.py b/datasette/cli.py index 0ed5e287d8..6e8f0d9b58 100644 --- a/datasette/cli.py +++ b/datasette/cli.py @@ -105,16 +105,7 @@ async def inspect_(files, sqlite_extensions): return data -class PublishAliases(click.Group): - aliases = {"now": "nowv1"} - - def get_command(self, ctx, cmd_name): - if cmd_name in self.aliases: - return click.Group.get_command(self, ctx, self.aliases[cmd_name]) - return click.Group.get_command(self, ctx, cmd_name) - - -@cli.group(cls=PublishAliases) +@cli.group() def publish(): "Publish specified SQLite database files to the internet along with a Datasette-powered interface and API" pass diff --git a/datasette/plugins.py b/datasette/plugins.py index 6e1e785efc..6c9677d066 100644 --- a/datasette/plugins.py +++ b/datasette/plugins.py @@ -6,7 +6,6 @@ DEFAULT_PLUGINS = ( "datasette.publish.heroku", - "datasette.publish.now", "datasette.publish.cloudrun", "datasette.facets", "datasette.sql_functions", diff --git a/datasette/publish/now.py b/datasette/publish/now.py deleted file mode 100644 index d7831c809e..0000000000 --- a/datasette/publish/now.py +++ /dev/null @@ -1,133 +0,0 @@ -from datasette import hookimpl -import click -import json -import os -from subprocess import run, PIPE - -from .common import ( - add_common_publish_arguments_and_options, - fail_if_publish_binary_not_installed, -) -from ..utils import temporary_docker_directory - - -@hookimpl -def publish_subcommand(publish): - @publish.command() - @add_common_publish_arguments_and_options - @click.option( - "-n", - "--name", - default="datasette", - help="Application name to use when deploying", - ) - @click.option("--force", is_flag=True, help="Pass --force option to now") - @click.option("--token", help="Auth token to use for deploy") - @click.option("--alias", multiple=True, help="Desired alias e.g. yoursite.now.sh") - @click.option("--spatialite", is_flag=True, help="Enable SpatialLite extension") - @click.option( - "--show-files", - is_flag=True, - help="Output the generated Dockerfile and metadata.json", - ) - def nowv1( - files, - metadata, - extra_options, - branch, - template_dir, - plugins_dir, - static, - install, - plugin_secret, - version_note, - title, - license, - license_url, - source, - source_url, - about, - about_url, - name, - force, - token, - alias, - spatialite, - show_files, - ): - fail_if_publish_binary_not_installed("now", "Zeit Now", "https://zeit.co/now") - if extra_options: - extra_options += " " - else: - extra_options = "" - extra_options += "--config force_https_urls:on" - - extra_metadata = { - "title": title, - "license": license, - "license_url": license_url, - "source": source, - "source_url": source_url, - "about": about, - "about_url": about_url, - } - - environment_variables = {} - if plugin_secret: - extra_metadata["plugins"] = {} - for plugin_name, plugin_setting, setting_value in plugin_secret: - environment_variable = ( - "{}_{}".format(plugin_name, plugin_setting) - .upper() - .replace("-", "_") - ) - environment_variables[environment_variable] = setting_value - extra_metadata["plugins"].setdefault(plugin_name, {})[ - plugin_setting - ] = {"$env": environment_variable} - - with temporary_docker_directory( - files, - name, - metadata, - extra_options, - branch, - template_dir, - plugins_dir, - static, - install, - spatialite, - version_note, - extra_metadata, - environment_variables, - ): - now_json = {"version": 1} - open("now.json", "w").write(json.dumps(now_json, indent=4)) - args = [] - if force: - args.append("--force") - if token: - args.append("--token={}".format(token)) - if args: - done = run(["now"] + args, stdout=PIPE) - else: - done = run("now", stdout=PIPE) - deployment_url = done.stdout - if show_files: - if os.path.exists("metadata.json"): - print("=== metadata.json ===\n") - print(open("metadata.json").read()) - print("\n==== Dockerfile ====\n") - print(open("Dockerfile").read()) - print("\n====================\n") - if alias: - # I couldn't get --target=production working, so I call - # 'now alias' with arguments directly instead - but that - # means I need to figure out what URL it was deployed to. - for single_alias in alias: # --alias can be specified multiple times - args = ["now", "alias", deployment_url, single_alias] - if token: - args.append("--token={}".format(token)) - run(args) - else: - print(deployment_url.decode("latin1")) diff --git a/docs/plugins.rst b/docs/plugins.rst index 36b3113119..222af7de7c 100644 --- a/docs/plugins.rst +++ b/docs/plugins.rst @@ -99,19 +99,25 @@ If you run ``datasette plugins --all`` it will include default plugins that ship $ datasette plugins --all [ { - "name": "datasette_json_html", + "name": "datasette.sql_functions", "static": false, "templates": false, - "version": "0.4.0" + "version": null }, { - "name": "datasette.publish.heroku", + "name": "datasette.publish.cloudrun", + "static": false, + "templates": false, + "version": null + }, + { + "name": "datasette.facets", "static": false, "templates": false, "version": null }, { - "name": "datasette.publish.now", + "name": "datasette.publish.heroku", "static": false, "templates": false, "version": null diff --git a/tests/test_publish_now.py b/tests/test_publish_now.py deleted file mode 100644 index 532fc50e2f..0000000000 --- a/tests/test_publish_now.py +++ /dev/null @@ -1,163 +0,0 @@ -from click.testing import CliRunner -from datasette import cli -from unittest import mock -import json -import subprocess - - -@mock.patch("shutil.which") -def test_publish_now_requires_now(mock_which): - mock_which.return_value = False - runner = CliRunner() - with runner.isolated_filesystem(): - open("test.db", "w").write("data") - result = runner.invoke(cli.cli, ["publish", "nowv1", "test.db"]) - assert result.exit_code == 1 - assert "Publishing to Zeit Now requires now" in result.output - - -@mock.patch("shutil.which") -def test_publish_now_invalid_database(mock_which): - mock_which.return_value = True - runner = CliRunner() - result = runner.invoke(cli.cli, ["publish", "nowv1", "woop.db"]) - assert result.exit_code == 2 - assert "Path 'woop.db' does not exist" in result.output - - -@mock.patch("shutil.which") -def test_publish_now_using_now_alias(mock_which): - mock_which.return_value = True - result = CliRunner().invoke(cli.cli, ["publish", "now", "woop.db"]) - assert result.exit_code == 2 - - -@mock.patch("shutil.which") -@mock.patch("datasette.publish.now.run") -def test_publish_now(mock_run, mock_which): - mock_which.return_value = True - runner = CliRunner() - with runner.isolated_filesystem(): - open("test.db", "w").write("data") - result = runner.invoke(cli.cli, ["publish", "nowv1", "test.db"]) - assert 0 == result.exit_code - mock_run.assert_called_once_with("now", stdout=subprocess.PIPE) - - -@mock.patch("shutil.which") -@mock.patch("datasette.publish.now.run") -def test_publish_now_force_token(mock_run, mock_which): - mock_which.return_value = True - runner = CliRunner() - with runner.isolated_filesystem(): - open("test.db", "w").write("data") - result = runner.invoke( - cli.cli, ["publish", "nowv1", "test.db", "--force", "--token=X"] - ) - assert 0 == result.exit_code - mock_run.assert_called_once_with( - ["now", "--force", "--token=X"], stdout=subprocess.PIPE - ) - - -@mock.patch("shutil.which") -@mock.patch("datasette.publish.now.run") -def test_publish_now_multiple_aliases(mock_run, mock_which): - mock_which.return_value = True - mock_run.return_value = mock.Mock(0) - mock_run.return_value.stdout = b"https://demo.example.com/" - runner = CliRunner() - with runner.isolated_filesystem(): - open("test.db", "w").write("data") - runner.invoke( - cli.cli, - [ - "publish", - "now", - "test.db", - "--token", - "XXX", - "--alias", - "alias1", - "--alias", - "alias2", - ], - ) - mock_run.assert_has_calls( - [ - mock.call(["now", "--token=XXX"], stdout=subprocess.PIPE), - mock.call( - [ - "now", - "alias", - b"https://demo.example.com/", - "alias1", - "--token=XXX", - ] - ), - mock.call( - [ - "now", - "alias", - b"https://demo.example.com/", - "alias2", - "--token=XXX", - ] - ), - ] - ) - - -@mock.patch("shutil.which") -@mock.patch("datasette.publish.now.run") -def test_publish_now_plugin_secrets(mock_run, mock_which): - mock_which.return_value = True - mock_run.return_value = mock.Mock(0) - mock_run.return_value.stdout = b"https://demo.example.com/" - - runner = CliRunner() - with runner.isolated_filesystem(): - open("test.db", "w").write("data") - result = runner.invoke( - cli.cli, - [ - "publish", - "now", - "test.db", - "--token", - "XXX", - "--plugin-secret", - "datasette-auth-github", - "client_id", - "x-client-id", - "--show-files", - ], - ) - dockerfile = ( - result.output.split("==== Dockerfile ====\n")[1] - .split("\n====================\n")[0] - .strip() - ) - expected = """FROM python:3.8 -COPY . /app -WORKDIR /app - -ENV DATASETTE_AUTH_GITHUB_CLIENT_ID 'x-client-id' -RUN pip install -U datasette -RUN datasette inspect test.db --inspect-file inspect-data.json -ENV PORT 8001 -EXPOSE 8001 -CMD datasette serve --host 0.0.0.0 -i test.db --cors --inspect-file inspect-data.json --metadata metadata.json --config force_https_urls:on --port $PORT""".strip() - assert expected == dockerfile - metadata = ( - result.output.split("=== metadata.json ===\n")[1] - .split("\n==== Dockerfile ====\n")[0] - .strip() - ) - assert { - "plugins": { - "datasette-auth-github": { - "client_id": {"$env": "DATASETTE_AUTH_GITHUB_CLIENT_ID"} - } - } - } == json.loads(metadata)