diff --git a/craft_application/application.py b/craft_application/application.py index 132e4705..e098f68a 100644 --- a/craft_application/application.py +++ b/craft_application/application.py @@ -542,6 +542,7 @@ def _create_dispatcher(self) -> craft_cli.Dispatcher: self.command_groups, summary=str(self.app.summary), extra_global_args=self._global_arguments, + docs_base_url=self.app.versioned_docs_url, ) def _get_app_plugins(self) -> dict[str, PluginType]: diff --git a/craft_application/util/yaml.py b/craft_application/util/yaml.py index 2beac5eb..4a7f18e8 100644 --- a/craft_application/util/yaml.py +++ b/craft_application/util/yaml.py @@ -113,15 +113,15 @@ def safe_yaml_load(stream: TextIO) -> Any: # noqa: ANN401 - The YAML could be a @overload def dump_yaml( - data: Any, stream: TextIO, **kwargs: Any # noqa: ANN401 Any gets passed to pyyaml + data: Any, stream: TextIO, **kwargs: Any # noqa: ANN401 # Any gets passed to pyyaml ) -> None: ... # pragma: no cover @overload def dump_yaml( - data: Any, # noqa: ANN401 Any gets passed to pyyaml + data: Any, # noqa: ANN401 # Any gets passed to pyyaml stream: None = None, - **kwargs: Any, # noqa: ANN401 Any gets passed to pyyaml + **kwargs: Any, # noqa: ANN401 # Any gets passed to pyyaml ) -> str: ... # pragma: no cover diff --git a/docs/reference/changelog.rst b/docs/reference/changelog.rst index 0e3841e8..e037748f 100644 --- a/docs/reference/changelog.rst +++ b/docs/reference/changelog.rst @@ -16,6 +16,8 @@ Application Commands ======== +- Provide a documentation link in help messages. + Services ======== diff --git a/tests/conftest.py b/tests/conftest.py index 6816532c..383a2adb 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -104,7 +104,7 @@ def app_metadata(features, fake_config_model) -> craft_application.AppMetadata: "A fake app for testing craft-application", source_ignore_patterns=["*.snap", "*.charm", "*.starcraft"], features=craft_application.AppFeatures(**features), - docs_url="www.craft-app.com/docs/{version}", + docs_url="www.testcraft.example/docs/{version}", ConfigModel=fake_config_model, ) @@ -116,7 +116,7 @@ def app_metadata_docs(features) -> craft_application.AppMetadata: return craft_application.AppMetadata( "testcraft", "A fake app for testing craft-application", - docs_url="http://craft-app.com", + docs_url="http://testcraft.example", source_ignore_patterns=["*.snap", "*.charm", "*.starcraft"], features=craft_application.AppFeatures(**features), ) diff --git a/tests/integration/test_application.py b/tests/integration/test_application.py index ad1676b1..f5eedfb9 100644 --- a/tests/integration/test_application.py +++ b/tests/integration/test_application.py @@ -81,6 +81,7 @@ def app(create_app): For more information about a command, run 'testcraft help '. For a summary of all commands, run 'testcraft help --all'. +For more information about testcraft, check out: www.testcraft.example/docs/3.14159 """ INVALID_COMMAND = """\ @@ -248,6 +249,10 @@ def test_get_command_help(monkeypatch, emitter, capsys, app, cmd, help_param): stdout, stderr = capsys.readouterr() assert f"testcraft {cmd} [options]" in stderr + assert stderr.endswith( + "For more information, check out: " + f"www.testcraft.example/docs/3.14159/reference/commands/{cmd}\n\n" + ) def test_invalid_command_argument(monkeypatch, capsys, app): diff --git a/tests/unit/test_application.py b/tests/unit/test_application.py index f2409356..75ad9271 100644 --- a/tests/unit/test_application.py +++ b/tests/unit/test_application.py @@ -1031,7 +1031,7 @@ def test_run_error( """\ Failed to run the build script for part 'foo'. Recommended resolution: Check the build output and verify the project can work with the 'python' plugin. - For more information, check out: http://craft-app.com/reference/plugins.html + For more information, check out: http://testcraft.example/reference/plugins.html Full execution log:""" ), ), @@ -2145,9 +2145,9 @@ def test_build_planner_errors(tmp_path, monkeypatch, fake_services): def test_emitter_docs_url(monkeypatch, mocker, app): """Test that the emitter is initialized with the correct url.""" - assert app.app.docs_url == "www.craft-app.com/docs/{version}" + assert app.app.docs_url == "www.testcraft.example/docs/{version}" assert app.app.version == "3.14159" - expected_url = "www.craft-app.com/docs/3.14159" + expected_url = "www.testcraft.example/docs/3.14159" spied_init = mocker.spy(emit, "init") @@ -2223,3 +2223,37 @@ def test_app_config_in_help( expected = "app-name: The name of the app, which is 'testcraft'." _, err = capsys.readouterr() assert expected in err + + +@pytest.mark.parametrize( + "help_args", + [ + pytest.param(["--help"], id="simple help"), + pytest.param(["help", "--all"], id="detailed help"), + ], +) +@pytest.mark.usefixtures("emitter") +def test_doc_url_in_general_help(help_args, monkeypatch, capsys, app): + """General help messages contain a link to the documentation.""" + monkeypatch.setattr(sys, "argv", ["testcraft", *help_args]) + + with pytest.raises(SystemExit): + app.run() + + expected = "For more information about testcraft, check out: www.testcraft.example/docs/3.14159\n\n" + _, err = capsys.readouterr() + assert err.endswith(expected) + + +@pytest.mark.usefixtures("emitter") +def test_doc_url_in_command_help(monkeypatch, capsys, app): + """Command help messages contain a link to the command's doc page.""" + app.add_command_group("Test", [AppConfigCommand]) + monkeypatch.setattr(sys, "argv", ["testcraft", "app-config", "-h"]) + + with pytest.raises(SystemExit): + app.run() + + expected = "For more information, check out: www.testcraft.example/docs/3.14159/reference/commands/app-config\n\n" + _, err = capsys.readouterr() + assert err.endswith(expected)