From 2d9c6fcb4736bd1eea57069494351af4608af720 Mon Sep 17 00:00:00 2001 From: Sergio Schvezov Date: Sat, 22 Jun 2024 10:52:59 -0300 Subject: [PATCH] fix: switch from progress to message for init (#604) - Snapcraft uses message, progress hides the docs url as it is "uni-line" - Use a similar message to what is done in Snapcraft - Improve the test for initializing flask-framework - Use the correct documentation slug --------- Co-authored-by: Tiago Nobrega --- rockcraft/commands/init.py | 29 ++++++--- tests/spread/rockcraft/init/task.yaml | 4 +- tests/unit/test_cli.py | 93 ++++++++++++++++++++++++--- 3 files changed, 107 insertions(+), 19 deletions(-) diff --git a/rockcraft/commands/init.py b/rockcraft/commands/init.py index 3451e738e..b4f7ddab8 100644 --- a/rockcraft/commands/init.py +++ b/rockcraft/commands/init.py @@ -156,7 +156,7 @@ class InitCommand(AppCommand): # - libpq5 """ ), - doc_slug="/reference/extensions/#the-flask-framework-extension", + doc_slug="/reference/extensions/flask-framework", ), "django-framework": _InitProfile( rockcraft_yaml=textwrap.dedent( @@ -241,16 +241,27 @@ def run(self, parsed_args: "argparse.Namespace") -> None: name = "my-rock-name" emit.debug(f"Set project name to '{name}'") - context = {"name": name, "snake_name": name.replace("-", "_").lower()} - + # Get the init profile init_profile = self._PROFILES[parsed_args.profile] - rockcraft_yaml_path = init(init_profile.rockcraft_yaml.format(**context)) - message = f"Created {rockcraft_yaml_path}." + # Setup the reference documentation link if available + profile_reference_docs: str | None = None if self._app.docs_url and init_profile.doc_slug: - profile_reference = self._app.docs_url + init_profile.doc_slug + profile_reference_docs = self._app.docs_url + init_profile.doc_slug + + # Format the template, all templates should be tested to avoid risk of + # expecting documentation when there isn't any set + context = { + "name": name, + "snake_name": name.replace("-", "_").lower(), + "profile_reference_docs": profile_reference_docs, + } + rockcraft_yaml_path = init(init_profile.rockcraft_yaml.format(**context)) + + message = f"Created {str(rockcraft_yaml_path)!r}." + if profile_reference_docs: message += ( - f"\nRead more about the {parsed_args.profile!r} at: {profile_reference}" + f"\nGo to {profile_reference_docs} to read more about the " + f"{parsed_args.profile!r} profile." ) - - emit.progress(message) + emit.message(message) diff --git a/tests/spread/rockcraft/init/task.yaml b/tests/spread/rockcraft/init/task.yaml index 760539ab5..3dc039bfd 100644 --- a/tests/spread/rockcraft/init/task.yaml +++ b/tests/spread/rockcraft/init/task.yaml @@ -1,10 +1,10 @@ summary: rockcraft init test execute: | - run_rockcraft init --name=my-rock-name 2> output.txt + run_rockcraft init --name=my-rock-name > output.txt # Output of init must be exactly this line, and nothing else. - echo "Created rockcraft.yaml." > expected.txt + echo "Created 'rockcraft.yaml'." > expected.txt diff output.txt expected.txt test -f rockcraft.yaml diff --git a/tests/unit/test_cli.py b/tests/unit/test_cli.py index 6fd068c39..a7bd16a14 100644 --- a/tests/unit/test_cli.py +++ b/tests/unit/test_cli.py @@ -16,6 +16,7 @@ import pathlib import sys from pathlib import Path +import textwrap from unittest.mock import DEFAULT, call import pytest @@ -117,12 +118,15 @@ def test_run_init_fallback_name(mocker): assert rock_project.name == "my-rock-name" -@pytest.mark.usefixtures("new_dir") -def test_run_init_flask(mocker, tmp_path, monkeypatch): - (tmp_path / "requirements.txt").write_text("flask") - (tmp_path / "app.py").write_text("app = object()") - mock_ended_ok = mocker.patch.object(emit, "ended_ok") - mocker.patch.object(sys, "argv", ["rockcraft", "init", "--profile=flask-framework"]) +def test_run_init_flask(mocker, emitter, monkeypatch, new_dir, tmp_path): + (new_dir / "requirements.txt").write_text("Flask", encoding="utf-8") + (new_dir / "app.py").write_text("app = object()", encoding="utf-8") + + mocker.patch.object( + sys, + "argv", + ["rockcraft", "init", "--profile=flask-framework", "--name", "test-name"], + ) cli.run() @@ -131,7 +135,80 @@ def test_run_init_flask(mocker, tmp_path, monkeypatch): assert len(rock_project_yaml["summary"]) < 80 assert len(rock_project_yaml["description"].split()) < 100 - assert mock_ended_ok.mock_calls == [call()] - + assert rockcraft_yaml_path.read_text() == textwrap.dedent( + """\ + name: test-name + # see https://documentation.ubuntu.com/rockcraft/en/stable/explanation/bases/ + # for more information about bases and using 'bare' bases for chiselled rocks + base: ubuntu@22.04 # the base environment for this Flask application + version: '0.1' # just for humans. Semantic versioning is recommended + summary: A summary of your Flask application # 79 char long summary + description: | + This is test-name's description. You have a paragraph or two to tell the + most important story about it. Keep it under 100 words though, + we live in tweetspace and your description wants to look good in the + container registries out there. + platforms: # the platforms this rock should be built on and run on + amd64: + + # to ensure the flask-framework extension works properly, your Flask application + # should have an `app.py` file with an `app` object as the WSGI entrypoint. + # a `requirements.txt` file with at least the flask package should also exist. + # see https://documentation.ubuntu.com/rockcraft/en/stable/reference/extensions/flask-framework + # for more information. + extensions: + - flask-framework + + # uncomment the sections you need and adjust according to your requirements. + # parts: # you need to uncomment this line to add or update any part. + + # flask-framework/install-app: + # prime: + # # by default, only the files in app/, templates/, static/, migrate, + # # migrate.sh and app.py are copied into the image. You can modify the list + # # below to override the default list and include or exclude specific + # # files/directories in your project. + # # note: prefix each entry with "flask/app/" followed by the local path. + # - flask/app/.env + # - flask/app/app.py + # - flask/app/webapp + # - flask/app/templates + # - flask/app/static + # # you may need packages to build a python package. Add them here if necessary. + # build-packages: + # # for example, if you need pkg-config and libxmlsec1-dev to build one + # # of your packages: + # - pkg-config + # - libxmlsec1-dev + + # you can add package slices or Debian packages to the image. + # package slices are subsets of Debian packages, which result + # in smaller and more secure images. + # see https://documentation.ubuntu.com/rockcraft/en/latest/explanation/chisel/ + + # add this part if you want to add packages slices to your image. + # you can find a list of packages slices at https://github.com/canonical/chisel-releases + # flask-framework/runtime-slices: + # plugin: nil + # stage-packages: + # # list the required package slices for your flask application below. + # # for example, for the slice libs of libpq5: + # - libpq5_libs + + # if you want to add a Debian package to your image, add the next part + # flask-framework/runtime-debs: + # plugin: nil + # stage-packages: + # # list required Debian packages for your flask application below. + # - libpq5 + """ + ) + emitter.assert_message( + textwrap.dedent( + """\ + Created 'rockcraft.yaml'. + Go to https://documentation.ubuntu.com/rockcraft/en/stable/reference/extensions/flask-framework to read more about the 'flask-framework' profile.""" + ) + ) monkeypatch.setenv("ROCKCRAFT_ENABLE_EXPERIMENTAL_EXTENSIONS", "0") project.Project.unmarshal(extensions.apply_extensions(tmp_path, rock_project_yaml))