diff --git a/pebble_tool/commands/publish.py b/pebble_tool/commands/publish.py index 4703362..06ae988 100644 --- a/pebble_tool/commands/publish.py +++ b/pebble_tool/commands/publish.py @@ -447,6 +447,16 @@ def _prompt_local_screenshot_files(cls): def _collect_screenshot_assets(self, args, pbw_metadata, allow_skip=False): if args.non_interactive: + local_files = getattr(args, "screenshots", None) or [] + if local_files: + for p in local_files: + if not os.path.exists(p): + raise ToolError("Screenshot file not found: {}".format(p)) + gif_paths = [p for p in local_files if p.lower().endswith(".gif")] + screenshot_paths = [p for p in local_files if not p.lower().endswith(".gif")] + if not allow_skip: + self._validate_screenshot_assets(gif_paths, screenshot_paths) + return gif_paths, screenshot_paths gif_paths, screenshot_paths = self._capture_with_emulator(args) if not allow_skip: self._validate_screenshot_assets(gif_paths, screenshot_paths) @@ -980,4 +990,7 @@ def add_parser(cls, parser): help="Path to iconSmall file used when creating a new app.") parser.add_argument("--icon-large", default=None, help="Path to iconLarge file used when creating a new app.") + parser.add_argument("--screenshots", nargs="+", default=None, metavar="FILE", + help="Local screenshot/GIF files to upload in --non-interactive mode. " + "Filenames must start with the platform name, e.g. emery_screenshot.png.") return parser diff --git a/tests/test_publish_command.py b/tests/test_publish_command.py index 6b66eeb..0919858 100644 --- a/tests/test_publish_command.py +++ b/tests/test_publish_command.py @@ -99,6 +99,91 @@ def test_collect_new_app_details_non_interactive_watchface(monkeypatch): assert details["category"] is None +def test_collect_screenshot_assets_non_interactive_uses_local_files(monkeypatch, tmp_path): + png = tmp_path / "emery_screenshot.png" + gif = tmp_path / "emery_preview.gif" + png.write_bytes(b"") + gif.write_bytes(b"") + + args = Namespace( + non_interactive=True, + screenshots=[str(png), str(gif)], + capture_gif_all_platforms=False, + capture_all_platforms=False, + v=0, + sdk=None, + ) + cmd = PublishCommand() + screenshot_paths, gif_paths = [], [] + result_gifs, result_screenshots = cmd._collect_screenshot_assets(args, {}, allow_skip=False) + assert result_screenshots == [str(png)] + assert result_gifs == [str(gif)] + + +def test_collect_screenshot_assets_non_interactive_local_files_separates_gifs(tmp_path): + files = [ + tmp_path / "emery_screenshot.png", + tmp_path / "basalt_screenshot.png", + tmp_path / "emery_preview.gif", + ] + for f in files: + f.write_bytes(b"") + + args = Namespace( + non_interactive=True, + screenshots=[str(f) for f in files], + capture_gif_all_platforms=False, + capture_all_platforms=False, + v=0, + sdk=None, + ) + cmd = PublishCommand() + result_gifs, result_screenshots = cmd._collect_screenshot_assets(args, {}, allow_skip=False) + assert len(result_screenshots) == 2 + assert len(result_gifs) == 1 + assert all(p.endswith(".gif") for p in result_gifs) + + +def test_collect_screenshot_assets_non_interactive_missing_file_raises(tmp_path): + existing = tmp_path / "emery_screenshot.png" + existing.write_bytes(b"") + + args = Namespace( + non_interactive=True, + screenshots=[str(existing), "/nonexistent/missing.png"], + capture_gif_all_platforms=False, + capture_all_platforms=False, + v=0, + sdk=None, + ) + cmd = PublishCommand() + with pytest.raises(ToolError, match="Screenshot file not found"): + cmd._collect_screenshot_assets(args, {}, allow_skip=False) + + +def test_collect_screenshot_assets_non_interactive_no_local_files_falls_back_to_emulator(monkeypatch): + captured = {} + + def fake_capture(self, args): + captured["called"] = True + return ["emery_preview.gif"], ["emery_screenshot.png"] + + monkeypatch.setattr(PublishCommand, "_capture_with_emulator", fake_capture) + + args = Namespace( + non_interactive=True, + screenshots=None, + capture_gif_all_platforms=False, + capture_all_platforms=False, + v=0, + sdk=None, + ) + cmd = PublishCommand() + result_gifs, result_screenshots = cmd._collect_screenshot_assets(args, {}, allow_skip=False) + assert captured.get("called") is True + assert result_screenshots == ["emery_screenshot.png"] + + def test_collect_new_app_details_non_interactive_requires_description(): args = Namespace( non_interactive=True,