youtrack-cli 0.3.3__tar.gz → 0.3.4__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.
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/PKG-INFO +1 -1
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/docs/commands/admin.rst +9 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/pyproject.toml +1 -1
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/tests/test_admin.py +32 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/uv.lock +1 -1
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/admin.py +61 -18
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/.claude/settings.local.json +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/.github/dependabot.yml +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/.github/workflows/ci.yml +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/.github/workflows/release.yml +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/.gitignore +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/.pre-commit-config.yaml +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/.readthedocs.yaml +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/CLAUDE.md +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/PUBLISHING.md +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/README.md +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/docs/Makefile +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/docs/api/index.rst +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/docs/changelog.rst +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/docs/command-aliases.rst +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/docs/commands/articles.rst +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/docs/commands/auth.rst +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/docs/commands/boards.rst +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/docs/commands/config.rst +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/docs/commands/index.rst +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/docs/commands/issues.rst +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/docs/commands/projects.rst +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/docs/commands/reports.rst +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/docs/commands/time.rst +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/docs/commands/users.rst +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/docs/conf.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/docs/configuration.rst +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/docs/development.rst +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/docs/index.rst +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/docs/installation.rst +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/docs/learning-path.rst +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/docs/logging.rst +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/docs/performance.md +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/docs/progress-indicators.md +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/docs/quickstart.rst +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/docs/requirements.txt +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/docs/security.rst +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/docs/troubleshooting.rst +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/docs/workflows.rst +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/docs/youtrack-concepts.rst +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/justfile +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/package-lock.json +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/package.json +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/tests/__init__.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/tests/conftest.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/tests/test_articles.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/tests/test_auth.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/tests/test_boards.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/tests/test_config.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/tests/test_issues.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/tests/test_logging.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/tests/test_main.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/tests/test_projects.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/tests/test_reports.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/tests/test_security.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/tests/test_time.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/tests/test_users.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/tox.ini +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/__init__.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/articles.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/auth.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/boards.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/cache.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/cli_utils/__init__.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/cli_utils/aliases.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/client.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/commands/__init__.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/commands/articles.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/commands/boards.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/commands/common.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/commands/issues.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/commands/projects.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/commands/time_tracking.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/commands/users.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/common.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/config.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/exceptions.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/issues.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/logging.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/main.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/performance.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/progress.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/projects.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/py.typed +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/reports.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/security.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/time.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/users.py +0 -0
- {youtrack_cli-0.3.3 → youtrack_cli-0.3.4}/youtrack_cli/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: youtrack-cli
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
4
4
|
Summary: YouTrack CLI - Command line interface for JetBrains YouTrack issue tracking system
|
|
5
5
|
Project-URL: Homepage, https://github.com/ryan-murphy/yt-cli
|
|
6
6
|
Project-URL: Documentation, https://yt-cli.readthedocs.io/
|
|
@@ -552,6 +552,15 @@ Common Issues and Solutions
|
|
|
552
552
|
**Health Check Issues**
|
|
553
553
|
Review system logs and resource availability.
|
|
554
554
|
|
|
555
|
+
**Health Check 404 Errors**
|
|
556
|
+
If the health check command returns a 404 error, this may indicate:
|
|
557
|
+
|
|
558
|
+
* Your YouTrack version doesn't support the system settings endpoint
|
|
559
|
+
* The API endpoint has changed in your YouTrack version
|
|
560
|
+
* Your YouTrack instance has a different API configuration
|
|
561
|
+
|
|
562
|
+
The command will automatically try fallback endpoints and provide specific guidance based on the error type.
|
|
563
|
+
|
|
555
564
|
System Diagnostics
|
|
556
565
|
~~~~~~~~~~~~~~~~~
|
|
557
566
|
|
|
@@ -175,6 +175,38 @@ class TestAdminManager:
|
|
|
175
175
|
assert result["status"] == "success"
|
|
176
176
|
assert result["data"] == mock_health
|
|
177
177
|
|
|
178
|
+
@pytest.mark.asyncio
|
|
179
|
+
async def test_get_system_health_404_error(self, admin_manager, auth_manager):
|
|
180
|
+
"""Test system health check with 404 error on all endpoints."""
|
|
181
|
+
with patch("httpx.AsyncClient") as mock_client:
|
|
182
|
+
mock_response = Mock()
|
|
183
|
+
mock_response.status_code = 404
|
|
184
|
+
mock_request = Mock()
|
|
185
|
+
http_error = httpx.HTTPStatusError("Not Found", request=mock_request, response=mock_response)
|
|
186
|
+
mock_client.return_value.__aenter__.return_value.get.side_effect = http_error
|
|
187
|
+
|
|
188
|
+
result = await admin_manager.get_system_health()
|
|
189
|
+
|
|
190
|
+
assert result["status"] == "error"
|
|
191
|
+
assert "System health endpoint not found (404)" in result["message"]
|
|
192
|
+
assert "YouTrack version doesn't support this endpoint" in result["message"]
|
|
193
|
+
|
|
194
|
+
@pytest.mark.asyncio
|
|
195
|
+
async def test_get_system_health_403_error(self, admin_manager, auth_manager):
|
|
196
|
+
"""Test system health check with 403 permission error."""
|
|
197
|
+
with patch("httpx.AsyncClient") as mock_client:
|
|
198
|
+
mock_response = Mock()
|
|
199
|
+
mock_response.status_code = 403
|
|
200
|
+
mock_request = Mock()
|
|
201
|
+
http_error = httpx.HTTPStatusError("Forbidden", request=mock_request, response=mock_response)
|
|
202
|
+
mock_client.return_value.__aenter__.return_value.get.side_effect = http_error
|
|
203
|
+
|
|
204
|
+
result = await admin_manager.get_system_health()
|
|
205
|
+
|
|
206
|
+
assert result["status"] == "error"
|
|
207
|
+
assert "Insufficient permissions for health check" in result["message"]
|
|
208
|
+
assert "Low-level Admin Read" in result["message"]
|
|
209
|
+
|
|
178
210
|
@pytest.mark.asyncio
|
|
179
211
|
async def test_clear_caches_success(self, admin_manager, auth_manager):
|
|
180
212
|
"""Test successful cache clearing."""
|
|
@@ -153,6 +153,7 @@ class AdminManager:
|
|
|
153
153
|
response = await client.get(
|
|
154
154
|
f"{credentials.base_url.rstrip('/')}/api/admin/globalSettings/license",
|
|
155
155
|
headers=headers,
|
|
156
|
+
params={"fields": "id,username,license,error"},
|
|
156
157
|
timeout=10.0,
|
|
157
158
|
)
|
|
158
159
|
response.raise_for_status()
|
|
@@ -167,6 +168,14 @@ class AdminManager:
|
|
|
167
168
|
"status": "error",
|
|
168
169
|
"message": "Insufficient permissions to view license.",
|
|
169
170
|
}
|
|
171
|
+
elif e.response.status_code == 404:
|
|
172
|
+
return {
|
|
173
|
+
"status": "error",
|
|
174
|
+
"message": (
|
|
175
|
+
"License endpoint not found. This may indicate an "
|
|
176
|
+
"incompatible YouTrack version or configuration."
|
|
177
|
+
),
|
|
178
|
+
}
|
|
170
179
|
return {"status": "error", "message": f"HTTP error: {e}"}
|
|
171
180
|
except Exception as e:
|
|
172
181
|
return {"status": "error", "message": f"Unexpected error: {e}"}
|
|
@@ -231,28 +240,62 @@ class AdminManager:
|
|
|
231
240
|
"Accept": "application/json",
|
|
232
241
|
}
|
|
233
242
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
timeout=10.0,
|
|
240
|
-
)
|
|
241
|
-
response.raise_for_status()
|
|
242
|
-
|
|
243
|
-
health_info = response.json()
|
|
244
|
-
return {"status": "success", "data": health_info}
|
|
243
|
+
# List of endpoints to try, in order of preference
|
|
244
|
+
endpoints = [
|
|
245
|
+
"/api/admin/globalSettings/systemSettings",
|
|
246
|
+
"/api/admin/globalSettings/systemSettings?fields=baseUrl,isApplicationReadOnly,maxUploadFileSize,maxExportItems",
|
|
247
|
+
]
|
|
245
248
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
+
async with httpx.AsyncClient() as client:
|
|
250
|
+
for endpoint in endpoints:
|
|
251
|
+
try:
|
|
252
|
+
response = await client.get(
|
|
253
|
+
f"{credentials.base_url.rstrip('/')}{endpoint}",
|
|
254
|
+
headers=headers,
|
|
255
|
+
timeout=10.0,
|
|
256
|
+
)
|
|
257
|
+
response.raise_for_status()
|
|
258
|
+
|
|
259
|
+
health_info = response.json()
|
|
260
|
+
return {"status": "success", "data": health_info}
|
|
261
|
+
|
|
262
|
+
except httpx.HTTPStatusError as e:
|
|
263
|
+
if e.response.status_code == 404:
|
|
264
|
+
continue # Try next endpoint
|
|
265
|
+
elif e.response.status_code == 403:
|
|
249
266
|
return {
|
|
250
267
|
"status": "error",
|
|
251
|
-
"message": "Insufficient permissions for health check."
|
|
268
|
+
"message": "Insufficient permissions for health check. "
|
|
269
|
+
"Requires 'Low-level Admin Read' permission.",
|
|
252
270
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
271
|
+
elif e.response.status_code == 401:
|
|
272
|
+
return {
|
|
273
|
+
"status": "error",
|
|
274
|
+
"message": "Authentication failed. Your token may have expired. Run 'yt auth login' again.",
|
|
275
|
+
}
|
|
276
|
+
else:
|
|
277
|
+
response_text = e.response.text if hasattr(e.response, "text") else str(e)
|
|
278
|
+
return {
|
|
279
|
+
"status": "error",
|
|
280
|
+
"message": f"HTTP {e.response.status_code}: {response_text}",
|
|
281
|
+
}
|
|
282
|
+
except httpx.RequestError as e:
|
|
283
|
+
return {
|
|
284
|
+
"status": "error",
|
|
285
|
+
"message": f"Network error: {e}. Check your YouTrack URL and network connection.",
|
|
286
|
+
}
|
|
287
|
+
except Exception as e:
|
|
288
|
+
return {"status": "error", "message": f"Unexpected error: {e}"}
|
|
289
|
+
|
|
290
|
+
# If all endpoints failed with 404
|
|
291
|
+
return {
|
|
292
|
+
"status": "error",
|
|
293
|
+
"message": "System health endpoint not found (404). This may indicate:\n"
|
|
294
|
+
"1. Your YouTrack version doesn't support this endpoint\n"
|
|
295
|
+
"2. The endpoint URL may have changed\n"
|
|
296
|
+
"3. Your YouTrack instance has a different API configuration\n"
|
|
297
|
+
"Please verify your YouTrack version and API access.",
|
|
298
|
+
}
|
|
256
299
|
|
|
257
300
|
async def clear_caches(self) -> dict[str, Any]:
|
|
258
301
|
"""Clear system caches.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|