Skip to content

Commit 0f64d21

Browse files
authored
Merge pull request #43 from vertti/more-tests
test coverage improvements
2 parents 5df9b0f + 01b7442 commit 0f64d21

22 files changed

+1330
-236
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ jobs:
4343
run: uv run pytest
4444

4545
- name: Upload coverage to Coveralls
46+
if: matrix.python-version == '3.13'
4647
uses: coverallsapp/github-action@v2
4748
with:
4849
github-token: ${{ secrets.GITHUB_TOKEN }}

CLAUDE.md

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,9 +270,30 @@ def test_update_service_status():
270270

271271
## Code Style Guidelines
272272

273-
### Comments
273+
### Comments and Docstrings
274274

275-
Remove obvious comments that repeat what the code already says. Only add comments for complex business logic or non-obvious decisions. Test names should be self-documenting, no docstrings needed.
275+
**CRITICAL: Remove ALL obvious docstrings that just repeat the function signature.**
276+
277+
Functions with clear names don't need docstrings. Only add docstrings for complex business logic or non-obvious behavior.
278+
279+
**Bad (obvious docstring):**
280+
281+
```python
282+
def build_log_group_arn(region: str, account_id: str, log_group: str) -> str:
283+
"""Build CloudWatch log group ARN from components."""
284+
return f"arn:aws:logs:{region}:{account_id}:log-group:{log_group}"
285+
```
286+
287+
**Good (no docstring needed):**
288+
289+
```python
290+
def build_log_group_arn(region: str, account_id: str, log_group: str) -> str:
291+
return f"arn:aws:logs:{region}:{account_id}:log-group:{log_group}"
292+
```
293+
294+
Test names should be self-documenting, no docstrings needed.
295+
296+
Remove obvious comments that repeat what the code already says. Only add comments for complex business logic or non-obvious decisions.
276297

277298
**Bad:**
278299

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "lazy-ecs"
3-
version = "0.7.2"
3+
version = "0.7.3"
44
description = "A CLI tool for working with AWS services"
55
readme = "README.md"
66
authors = [

src/lazy_ecs/__init__.py

Lines changed: 2 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,7 @@
1212
from mypy_boto3_sts.client import STSClient
1313

1414
from .aws_service import ECSService
15-
from .core.navigation import handle_navigation, parse_selection
16-
from .core.types import TaskDetails
17-
from .core.utils import show_spinner
15+
from .core.app import navigate_clusters
1816
from .ui import ECSNavigator
1917

2018
console = Console()
@@ -37,7 +35,7 @@ def main() -> None:
3735
ecs_service = ECSService(ecs_client, sts_client, logs_client, cloudwatch_client)
3836
navigator = ECSNavigator(ecs_service)
3937

40-
_navigate_clusters(navigator, ecs_service)
38+
navigate_clusters(navigator, ecs_service)
4139

4240
except Exception as e:
4341
console.print(f"\n❌ Error: {e}", style="red")
@@ -88,130 +86,5 @@ def _create_cloudwatch_client(profile_name: str | None) -> "CloudWatchClient":
8886
return session.client("cloudwatch", config=config)
8987

9088

91-
def _navigate_clusters(navigator: ECSNavigator, ecs_service: ECSService) -> None:
92-
"""Handle cluster-level navigation with back support."""
93-
while True:
94-
selected_cluster = navigator.select_cluster()
95-
96-
if not selected_cluster:
97-
console.print("\n❌ No cluster selected. Goodbye!", style="yellow")
98-
break
99-
100-
console.print(f"\n✅ Selected cluster: {selected_cluster}", style="green")
101-
102-
if _navigate_services(navigator, ecs_service, selected_cluster):
103-
continue # Back to cluster selection
104-
break # Exit was chosen
105-
106-
107-
def _navigate_services(navigator: ECSNavigator, ecs_service: ECSService, cluster_name: str) -> bool:
108-
"""Handle service-level navigation. Returns True if back was chosen, False if exit."""
109-
service_selection = navigator.select_service(cluster_name)
110-
111-
# Handle navigation responses (back/exit)
112-
should_continue, should_exit = handle_navigation(service_selection)
113-
if not should_continue:
114-
return not should_exit # True for back, False for exit
115-
116-
selection_type, selected_service, _ = parse_selection(service_selection)
117-
if selection_type != "service":
118-
return True
119-
120-
console.print(f"\n✅ Selected service: {selected_service}", style="green")
121-
122-
while True:
123-
selection = navigator.select_service_action(cluster_name, selected_service)
124-
125-
# Handle navigation responses
126-
should_continue, should_exit = handle_navigation(selection)
127-
if not should_continue:
128-
return not should_exit # True for back, False for exit
129-
130-
selection_type, action_name, task_arn = parse_selection(selection)
131-
if selection_type == "task" and action_name == "show_details":
132-
with show_spinner():
133-
task_details = ecs_service.get_task_details(cluster_name, selected_service, task_arn)
134-
if task_details:
135-
navigator.display_task_details(task_details)
136-
# Navigate to task features, handle back navigation
137-
if _handle_task_features(navigator, cluster_name, task_arn, task_details, selected_service):
138-
continue # Back to service selection
139-
return False # Exit was chosen
140-
console.print(f"\n⚠️ Could not fetch task details for {task_arn}", style="yellow")
141-
142-
elif selection_type == "action" and action_name == "force_deployment":
143-
navigator.handle_force_deployment(cluster_name, selected_service)
144-
# Continue the loop to show the menu again
145-
146-
elif selection_type == "action" and action_name == "show_events":
147-
navigator.show_service_events(cluster_name, selected_service)
148-
# Continue the loop to show the menu again
149-
150-
elif selection_type == "action" and action_name == "show_metrics":
151-
navigator.show_service_metrics(cluster_name, selected_service)
152-
# Continue the loop to show the menu again
153-
154-
elif selection_type == "action" and action_name == "open_console":
155-
navigator.open_service_in_console(cluster_name, selected_service)
156-
# Continue the loop to show the menu again
157-
158-
159-
_CONTAINER_ACTIONS = {
160-
"tail_logs": lambda nav, cluster, task_arn, container: nav.show_container_logs_live_tail(
161-
cluster,
162-
task_arn,
163-
container,
164-
),
165-
"show_env": lambda nav, cluster, task_arn, container: nav.show_container_environment_variables(
166-
cluster,
167-
task_arn,
168-
container,
169-
),
170-
"show_secrets": lambda nav, cluster, task_arn, container: nav.show_container_secrets(cluster, task_arn, container),
171-
"show_ports": lambda nav, cluster, task_arn, container: nav.show_container_port_mappings(
172-
cluster,
173-
task_arn,
174-
container,
175-
),
176-
"show_volumes": lambda nav, cluster, task_arn, container: nav.show_container_volume_mounts(
177-
cluster,
178-
task_arn,
179-
container,
180-
),
181-
}
182-
183-
_TASK_ACTIONS = {
184-
"show_history": lambda nav, cluster, service, _task_arn, _task_details: nav.show_task_history(cluster, service),
185-
"show_details": lambda nav, _cluster, _service, _task_arn, task_details: nav.display_task_details(task_details),
186-
"compare_definitions": lambda nav, _cluster, _service, _task_arn, task_details: nav.show_task_definition_comparison(
187-
task_details,
188-
),
189-
"open_console": lambda nav, cluster, _service, task_arn, _task_details: nav.open_task_in_console(cluster, task_arn),
190-
}
191-
192-
193-
def _handle_task_features(
194-
navigator: ECSNavigator,
195-
cluster_name: str,
196-
task_arn: str,
197-
task_details: TaskDetails | None,
198-
service_name: str,
199-
) -> bool:
200-
"""Handle task feature selection and execution. Returns True if back was chosen, False if exit."""
201-
while True:
202-
selection = navigator.select_task_feature(task_details)
203-
204-
should_continue, should_exit = handle_navigation(selection)
205-
if not should_continue:
206-
return not should_exit
207-
208-
selection_type, action_name, container_name = parse_selection(selection)
209-
210-
if selection_type == "container_action" and action_name in _CONTAINER_ACTIONS:
211-
_CONTAINER_ACTIONS[action_name](navigator, cluster_name, task_arn, container_name)
212-
elif selection_type == "task_action" and action_name in _TASK_ACTIONS:
213-
_TASK_ACTIONS[action_name](navigator, cluster_name, service_name, task_arn, task_details)
214-
215-
21689
if __name__ == "__main__":
21790
main()

0 commit comments

Comments
 (0)