devs-cli 3.2.4__tar.gz → 3.3.1__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 (32) hide show
  1. {devs_cli-3.2.4/devs_cli.egg-info → devs_cli-3.3.1}/PKG-INFO +1 -1
  2. {devs_cli-3.2.4 → devs_cli-3.3.1}/devs/cli.py +27 -19
  3. {devs_cli-3.2.4 → devs_cli-3.3.1/devs_cli.egg-info}/PKG-INFO +1 -1
  4. {devs_cli-3.2.4 → devs_cli-3.3.1}/pyproject.toml +1 -1
  5. {devs_cli-3.2.4 → devs_cli-3.3.1}/tests/test_container_manager.py +6 -5
  6. {devs_cli-3.2.4 → devs_cli-3.3.1}/LICENSE +0 -0
  7. {devs_cli-3.2.4 → devs_cli-3.3.1}/README.md +0 -0
  8. {devs_cli-3.2.4 → devs_cli-3.3.1}/devs/__init__.py +0 -0
  9. {devs_cli-3.2.4 → devs_cli-3.3.1}/devs/config.py +0 -0
  10. {devs_cli-3.2.4 → devs_cli-3.3.1}/devs/core/__init__.py +0 -0
  11. {devs_cli-3.2.4 → devs_cli-3.3.1}/devs/core/integration.py +0 -0
  12. {devs_cli-3.2.4 → devs_cli-3.3.1}/devs/exceptions.py +0 -0
  13. {devs_cli-3.2.4 → devs_cli-3.3.1}/devs/utils/__init__.py +0 -0
  14. {devs_cli-3.2.4 → devs_cli-3.3.1}/devs_cli.egg-info/SOURCES.txt +0 -0
  15. {devs_cli-3.2.4 → devs_cli-3.3.1}/devs_cli.egg-info/dependency_links.txt +0 -0
  16. {devs_cli-3.2.4 → devs_cli-3.3.1}/devs_cli.egg-info/entry_points.txt +0 -0
  17. {devs_cli-3.2.4 → devs_cli-3.3.1}/devs_cli.egg-info/requires.txt +0 -0
  18. {devs_cli-3.2.4 → devs_cli-3.3.1}/devs_cli.egg-info/top_level.txt +0 -0
  19. {devs_cli-3.2.4 → devs_cli-3.3.1}/setup.cfg +0 -0
  20. {devs_cli-3.2.4 → devs_cli-3.3.1}/tests/test_cli.py +0 -0
  21. {devs_cli-3.2.4 → devs_cli-3.3.1}/tests/test_cli_clean.py +0 -0
  22. {devs_cli-3.2.4 → devs_cli-3.3.1}/tests/test_cli_misc.py +0 -0
  23. {devs_cli-3.2.4 → devs_cli-3.3.1}/tests/test_cli_start.py +0 -0
  24. {devs_cli-3.2.4 → devs_cli-3.3.1}/tests/test_cli_stop.py +0 -0
  25. {devs_cli-3.2.4 → devs_cli-3.3.1}/tests/test_cli_vscode.py +0 -0
  26. {devs_cli-3.2.4 → devs_cli-3.3.1}/tests/test_e2e.py +0 -0
  27. {devs_cli-3.2.4 → devs_cli-3.3.1}/tests/test_error_parsing.py +0 -0
  28. {devs_cli-3.2.4 → devs_cli-3.3.1}/tests/test_integration.py +0 -0
  29. {devs_cli-3.2.4 → devs_cli-3.3.1}/tests/test_live_mode.py +0 -0
  30. {devs_cli-3.2.4 → devs_cli-3.3.1}/tests/test_project.py +0 -0
  31. {devs_cli-3.2.4 → devs_cli-3.3.1}/tests/test_repo_cache.py +0 -0
  32. {devs_cli-3.2.4 → devs_cli-3.3.1}/tests/test_workspace_manager.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devs-cli
3
- Version: 3.2.4
3
+ Version: 3.3.1
4
4
  Summary: DevContainer Management Tool - Manage multiple named devcontainers for any project
5
5
  Author: Dan Lester
6
6
  License-Expression: MIT
@@ -168,46 +168,52 @@ def cli(ctx, debug: bool, repo: str) -> None:
168
168
  @cli.command()
169
169
  @click.argument('dev_names', nargs=-1, required=True)
170
170
  @click.option('--rebuild', is_flag=True, help='Force rebuild of container images')
171
+ @click.option('--rebuild-if-changed', 'rebuild_if_changed', is_flag=True, help='Rebuild if devcontainer files have changed since last build')
171
172
  @click.option('--live', is_flag=True, help='Mount current directory as workspace instead of copying')
172
173
  @click.option('--env', multiple=True, help='Environment variables to pass to container (format: VAR=value)')
173
174
  @debug_option
174
- def start(dev_names: tuple, rebuild: bool, live: bool, env: tuple, debug: bool) -> None:
175
+ def start(dev_names: tuple, rebuild: bool, rebuild_if_changed: bool, live: bool, env: tuple, debug: bool) -> None:
175
176
  """Start named devcontainers.
176
-
177
+
177
178
  DEV_NAMES: One or more development environment names to start
178
-
179
+
179
180
  Example: devs start sally bob
180
181
  Example: devs start sally --live # Mount current directory directly
182
+ Example: devs start sally --rebuild-if-changed # Rebuild only if devcontainer files changed
181
183
  Example: devs start sally --env QUART_PORT=5001 --env DB_HOST=localhost:3307
182
184
  """
183
185
  check_dependencies()
184
186
  project = get_project()
185
-
187
+
186
188
  console.print(f"🚀 Starting devcontainers for project: {project.info.name}")
187
-
189
+
188
190
  container_manager = ContainerManager(project, config)
189
191
  workspace_manager = WorkspaceManager(project, config)
190
-
192
+
191
193
  for dev_name in dev_names:
192
194
  console.print(f" Starting: {dev_name}")
193
-
195
+
194
196
  # Load environment variables from DEVS.yml and merge with CLI --env flags
195
197
  devs_env = DevsConfigLoader.load_env_vars(dev_name, project.info.name)
196
198
  cli_env = parse_env_vars(env) if env else {}
197
199
  extra_env = merge_env_vars(devs_env, cli_env) if devs_env or cli_env else None
198
-
200
+
199
201
  if extra_env:
200
202
  console.print(f"🔧 Environment variables: {', '.join(f'{k}={v}' for k, v in extra_env.items())}")
201
-
203
+
202
204
  try:
203
205
  # Create/ensure workspace exists (handles live mode internally)
204
206
  workspace_dir = workspace_manager.create_workspace(dev_name, live=live)
205
-
206
- # Ensure container is running
207
+
208
+ # Ensure container is running.
209
+ # --rebuild: always force a full rebuild
210
+ # --rebuild-if-changed: rebuild only when devcontainer file content has changed
211
+ # (default): never auto-rebuild
207
212
  if container_manager.ensure_container_running(
208
- dev_name,
209
- workspace_dir,
213
+ dev_name,
214
+ workspace_dir,
210
215
  force_rebuild=rebuild,
216
+ check_rebuild=rebuild_if_changed,
211
217
  debug=debug,
212
218
  live=live,
213
219
  extra_env=extra_env
@@ -215,7 +221,7 @@ def start(dev_names: tuple, rebuild: bool, live: bool, env: tuple, debug: bool)
215
221
  continue
216
222
  else:
217
223
  console.print(f" ⚠️ Failed to start {dev_name}, continuing with others...")
218
-
224
+
219
225
  except (ContainerError, WorkspaceError) as e:
220
226
  console.print(f" ❌ Error starting {dev_name}: {e}")
221
227
  continue
@@ -268,8 +274,8 @@ def vscode(dev_names: tuple, delay: float, live: bool, env: tuple, debug: bool)
268
274
  # Ensure workspace exists (handles live mode internally)
269
275
  workspace_dir = workspace_manager.create_workspace(dev_name, live=live)
270
276
 
271
- # Ensure container is running before launching VS Code
272
- if container_manager.ensure_container_running(dev_name, workspace_dir, debug=debug, live=live, extra_env=extra_env):
277
+ # Ensure container is running before launching VS Code (no auto-rebuild in CLI)
278
+ if container_manager.ensure_container_running(dev_name, workspace_dir, check_rebuild=False, debug=debug, live=live, extra_env=extra_env):
273
279
  workspace_dirs.append(workspace_dir)
274
280
  valid_dev_names.append(dev_name)
275
281
  else:
@@ -776,11 +782,13 @@ def tunnel(dev_name: str, auth: bool, status: bool, kill_tunnel: bool, live: boo
776
782
  extra_env=extra_env
777
783
  )
778
784
  if is_running:
779
- console.print(f"Tunnel status for {dev_name}:")
785
+ console.print(f"[bold]Tunnel for {dev_name}:[/bold]")
780
786
  console.print(status_msg)
781
787
  else:
782
- console.print(f"No tunnel running in {dev_name}")
783
- console.print(f" {status_msg}")
788
+ console.print(f"[bold]Tunnel for {dev_name}:[/bold]")
789
+ console.print(f"[dim] Not running[/dim]")
790
+ if status_msg:
791
+ console.print(f" {status_msg}")
784
792
 
785
793
  elif kill_tunnel:
786
794
  # Kill the tunnel
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devs-cli
3
- Version: 3.2.4
3
+ Version: 3.3.1
4
4
  Summary: DevContainer Management Tool - Manage multiple named devcontainers for any project
5
5
  Author: Dan Lester
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "devs-cli"
7
- version = "3.2.4"
7
+ version = "3.3.1"
8
8
  description = "DevContainer Management Tool - Manage multiple named devcontainers for any project"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
@@ -246,7 +246,7 @@ class TestContainerManager:
246
246
  assert result is False
247
247
 
248
248
  def test_should_rebuild_image_no_existing(self, mock_project):
249
- """Test should_rebuild_image when no image exists."""
249
+ """Test should_rebuild_image returns False when no existing container."""
250
250
  with patch('devs_common.utils.docker_client.docker') as mock_docker:
251
251
  mock_docker_instance = MagicMock()
252
252
  mock_docker.from_env.return_value = mock_docker_instance
@@ -257,13 +257,14 @@ class TestContainerManager:
257
257
 
258
258
  manager = ContainerManager(mock_project)
259
259
 
260
- # Mock no existing images
261
- manager.docker.find_images_by_pattern = MagicMock(return_value=[])
260
+ # Mock no existing containers
261
+ manager.docker.find_containers_by_labels = MagicMock(return_value=[])
262
262
 
263
- should_rebuild, reason = manager.should_rebuild_image("alice")
263
+ project_labels = {'devs.project': 'test-org-test-repo', 'devs.dev': 'alice'}
264
+ should_rebuild, reason = manager.should_rebuild_image("alice", project_labels)
264
265
 
265
266
  assert should_rebuild is False
266
- assert "No existing image" in reason
267
+ assert "No existing container" in reason
267
268
 
268
269
  def test_find_aborted_containers(self, mock_project):
269
270
  """Test finding aborted containers."""
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