podojo-cli 1.2.0__tar.gz → 1.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/CHANGELOG.md +10 -0
  2. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/PKG-INFO +1 -1
  3. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/pyproject.toml +1 -1
  4. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/src/podojo_cli/client.py +24 -0
  5. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/src/podojo_cli/commands/usertests.py +37 -8
  6. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/uv.lock +1 -1
  7. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/.github/workflows/publish.yml +0 -0
  8. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/.gitignore +0 -0
  9. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/CLAUDE.md +0 -0
  10. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/LICENSE +0 -0
  11. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/README.md +0 -0
  12. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/src/podojo_cli/__init__.py +0 -0
  13. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/src/podojo_cli/commands/__init__.py +0 -0
  14. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/src/podojo_cli/commands/auth.py +0 -0
  15. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/src/podojo_cli/commands/interviews.py +0 -0
  16. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/src/podojo_cli/commands/projects.py +0 -0
  17. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/src/podojo_cli/commands/showreel.py +0 -0
  18. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/src/podojo_cli/commands/synth.py +0 -0
  19. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/src/podojo_cli/commands/transcripts.py +0 -0
  20. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/src/podojo_cli/commands/videos.py +0 -0
  21. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/src/podojo_cli/config.py +0 -0
  22. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/src/podojo_cli/main.py +0 -0
  23. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/src/podojo_cli/synth/__init__.py +0 -0
  24. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/src/podojo_cli/synth/driver.py +0 -0
  25. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/src/podojo_cli/synth/session.py +0 -0
  26. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/src/podojo_cli/version_check.py +0 -0
  27. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/src/podojo_cli/video/__init__.py +0 -0
  28. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/src/podojo_cli/video/showreel.py +0 -0
  29. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/tests/conftest.py +0 -0
  30. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/tests/test_auth.py +0 -0
  31. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/tests/test_interviews.py +0 -0
  32. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/tests/test_projects.py +0 -0
  33. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/tests/test_showreel.py +0 -0
  34. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/tests/test_transcripts.py +0 -0
  35. {podojo_cli-1.2.0 → podojo_cli-1.4.0}/tests/test_usertests.py +0 -0
@@ -5,6 +5,16 @@ All notable changes to the Podojo CLI will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org).
7
7
 
8
+ ## [1.4.0] - 2026-05-31
9
+
10
+ ### Added
11
+ - Support `image_file:` in usertest step config — a local image path that is uploaded to Podojo-hosted storage on `create`/`update` and replaced with the hosted URL. Relative paths resolve against the YAML file's location. Externally-hosted `image:` URLs continue to work.
12
+
13
+ ## [1.3.0] - 2026-05-25
14
+
15
+ ### Removed
16
+ - Drop `privacy_text` field from usertest config. It was never used in practice, and the participant frontend no longer renders it.
17
+
8
18
  ## [1.2.0] - 2026-05-25
9
19
 
10
20
  ### Removed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: podojo-cli
3
- Version: 1.2.0
3
+ Version: 1.4.0
4
4
  Summary: CLI for the Podojo user research platform
5
5
  Project-URL: Homepage, https://github.com/podojo/cli-podojo
6
6
  Project-URL: Source, https://github.com/podojo/cli-podojo
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "podojo-cli"
3
- version = "1.2.0"
3
+ version = "1.4.0"
4
4
  description = "CLI for the Podojo user research platform"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -132,6 +132,30 @@ class PodojoClient:
132
132
  r.raise_for_status()
133
133
  return r.json()
134
134
 
135
+ IMAGE_CONTENT_TYPES = {
136
+ ".png": "image/png",
137
+ ".jpg": "image/jpeg",
138
+ ".jpeg": "image/jpeg",
139
+ ".webp": "image/webp",
140
+ ".gif": "image/gif",
141
+ }
142
+
143
+ def upload_usertest_image(self, file_path: Path) -> dict:
144
+ content_type = self.IMAGE_CONTENT_TYPES.get(file_path.suffix.lower())
145
+ if content_type is None:
146
+ raise ValueError(
147
+ f"Unsupported image type '{file_path.suffix}'. Allowed: PNG, JPEG, WebP, GIF."
148
+ )
149
+ with file_path.open("rb") as f:
150
+ r = httpx.post(
151
+ f"{self.base_url}/usertests/images",
152
+ files={"file": (file_path.name, f, content_type)},
153
+ headers=self._headers(),
154
+ timeout=httpx.Timeout(None),
155
+ )
156
+ r.raise_for_status()
157
+ return r.json()
158
+
135
159
  def create_usertest(self, data: dict) -> dict:
136
160
  r = httpx.post(
137
161
  f"{self.base_url}/usertests",
@@ -36,7 +36,7 @@ EXAMPLE_YAML = """\
36
36
  # Podojo Unmoderated User Test Configuration
37
37
  #
38
38
  # Required fields: usertest_id, title, logo, prototype_url, steps
39
- # Optional fields: welcome_text, privacy_text, promo_code, promo_code_info,
39
+ # Optional fields: welcome_text, promo_code, promo_code_info,
40
40
  # project_name, live, collect_contact
41
41
 
42
42
  usertest_id: checkout-usability-v1
@@ -53,11 +53,6 @@ welcome_text: |
53
53
 
54
54
  This session takes about 10 minutes.
55
55
 
56
- # Optional: privacy notice
57
- privacy_text: |
58
- Your responses are anonymous and will only be used to improve
59
- our product. You can stop at any time.
60
-
61
56
  # Optional: reward for participants
62
57
  promo_code: THANKS10
63
58
  promo_code_info: "Use this code for 10% off your next purchase"
@@ -75,7 +70,10 @@ project_name: checkout-redesign-q1
75
70
  # Each step requires: type ("screen" or "prototype") and title
76
71
  # Screen steps should have a variant: "question" (open-ended), "task" (action-based),
77
72
  # or "instruction" (briefing screen shown before a prototype step — uses a "Continue" button)
78
- # Optional per step: text (markdown), image (URL)
73
+ # Optional per step: text (markdown), and either:
74
+ # image: a URL to an externally-hosted image, or
75
+ # image_file: a path to a local image (uploaded to Podojo storage on create/update;
76
+ # relative paths resolve against this YAML file's location)
79
77
  steps:
80
78
  - type: screen
81
79
  variant: question
@@ -83,7 +81,7 @@ steps:
83
81
  text: |
84
82
  Look at this homepage screenshot.
85
83
  What stands out to you first?
86
- image: https://example.com/screenshots/homepage.png
84
+ image_file: ./screenshots/homepage.png
87
85
 
88
86
  - type: screen
89
87
  variant: instruction
@@ -165,6 +163,35 @@ def _load_yaml(path: Path) -> dict:
165
163
  return data
166
164
 
167
165
 
166
+ def _resolve_image_files(data: dict, base_dir: Path, client: PodojoClient) -> None:
167
+ """Upload any step `image_file` (local path) and replace it with the hosted URL."""
168
+ steps = data.get("steps")
169
+ if not isinstance(steps, list):
170
+ return
171
+ for i, step in enumerate(steps, 1):
172
+ if not isinstance(step, dict) or "image_file" not in step:
173
+ continue
174
+ raw_path = step.pop("image_file")
175
+ if not raw_path:
176
+ continue
177
+ image_path = Path(raw_path)
178
+ if not image_path.is_absolute():
179
+ image_path = (base_dir / image_path).resolve()
180
+ if not image_path.exists():
181
+ console.print(f"[red]Error:[/red] Step {i}: image file not found: {image_path}")
182
+ raise typer.Exit(1)
183
+ try:
184
+ result = client.upload_usertest_image(image_path)
185
+ except ValueError as ve:
186
+ console.print(f"[red]Error:[/red] Step {i}: {ve}")
187
+ raise typer.Exit(1)
188
+ except httpx.HTTPStatusError as he:
189
+ console.print(f"[red]Error:[/red] Step {i}: image upload failed: {_format_api_error(he)}")
190
+ raise typer.Exit(1)
191
+ step["image"] = result["url"]
192
+ console.print(f"[dim]Uploaded image for step {i}: {result['url']}[/dim]")
193
+
194
+
168
195
  def _format_api_error(e: httpx.HTTPStatusError) -> str:
169
196
  """Format API error into actionable message."""
170
197
  try:
@@ -262,6 +289,7 @@ def create_usertest(
262
289
  data["project_name"] = data["usertest_id"]
263
290
 
264
291
  client = PodojoClient()
292
+ _resolve_image_files(data, from_file.parent, client)
265
293
  try:
266
294
  result = client.create_usertest(data)
267
295
  except httpx.HTTPStatusError as e:
@@ -293,6 +321,7 @@ def update_usertest(
293
321
  data = _load_yaml(from_file)
294
322
 
295
323
  client = PodojoClient()
324
+ _resolve_image_files(data, from_file.parent, client)
296
325
  try:
297
326
  result = client.update_usertest(usertest_id, data)
298
327
  except httpx.HTTPStatusError as e:
@@ -369,7 +369,7 @@ wheels = [
369
369
 
370
370
  [[package]]
371
371
  name = "podojo-cli"
372
- version = "1.2.0"
372
+ version = "1.4.0"
373
373
  source = { editable = "." }
374
374
  dependencies = [
375
375
  { name = "httpx" },
File without changes
File without changes
File without changes
File without changes
File without changes