superset-showtime 0.5.0__tar.gz → 0.5.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.

Potentially problematic release.


This version of superset-showtime might be problematic. Click here for more details.

Files changed (33) hide show
  1. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/PKG-INFO +1 -1
  2. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/showtime/__init__.py +1 -1
  3. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/showtime/cli.py +1 -1
  4. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/showtime/core/aws.py +39 -13
  5. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/showtime/core/pull_request.py +18 -4
  6. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/showtime/core/show.py +4 -6
  7. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/.claude/settings.local.json +0 -0
  8. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/.gitignore +0 -0
  9. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/.pre-commit-config.yaml +0 -0
  10. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/CLAUDE.md +0 -0
  11. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/Makefile +0 -0
  12. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/README.md +0 -0
  13. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/dev-setup.sh +0 -0
  14. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/pypi-push.sh +0 -0
  15. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/pyproject.toml +0 -0
  16. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/requirements-dev.txt +0 -0
  17. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/requirements.txt +0 -0
  18. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/showtime/__main__.py +0 -0
  19. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/showtime/core/__init__.py +0 -0
  20. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/showtime/core/emojis.py +0 -0
  21. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/showtime/core/github.py +0 -0
  22. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/showtime/core/github_messages.py +0 -0
  23. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/showtime/core/label_colors.py +0 -0
  24. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/showtime/data/ecs-task-definition.json +0 -0
  25. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/tests/__init__.py +0 -0
  26. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/tests/unit/__init__.py +0 -0
  27. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/tests/unit/test_label_transitions.py +0 -0
  28. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/tests/unit/test_pull_request.py +0 -0
  29. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/tests/unit/test_sha_specific_logic.py +0 -0
  30. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/tests/unit/test_show.py +0 -0
  31. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/uv.lock +0 -0
  32. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/workflows-reference/showtime-cleanup.yml +0 -0
  33. {superset_showtime-0.5.0 → superset_showtime-0.5.1}/workflows-reference/showtime-trigger.yml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: superset-showtime
3
- Version: 0.5.0
3
+ Version: 0.5.1
4
4
  Summary: 🎪 Apache Superset ephemeral environment management with circus tent emoji state tracking
5
5
  Project-URL: Homepage, https://github.com/apache/superset-showtime
6
6
  Project-URL: Documentation, https://superset-showtime.readthedocs.io/
@@ -4,7 +4,7 @@
4
4
  Circus tent emoji state tracking for Apache Superset ephemeral environments.
5
5
  """
6
6
 
7
- __version__ = "0.5.0"
7
+ __version__ = "0.5.1"
8
8
  __author__ = "Maxime Beauchemin"
9
9
  __email__ = "maximebeauchemin@gmail.com"
10
10
 
@@ -722,7 +722,7 @@ def aws_cleanup(
722
722
  parts = pr_match.split("-")
723
723
  if len(parts) >= 2:
724
724
  pr_number = int(parts[0])
725
- success = aws.delete_environment(service.replace("-service", ""), pr_number)
725
+ success = aws.delete_environment(service, pr_number)
726
726
  if success:
727
727
  p(f"✅ Deleted {service}")
728
728
  deleted_count += 1
@@ -175,36 +175,62 @@ class AWSInterface:
175
175
 
176
176
  def delete_environment(self, service_name: str, pr_number: int) -> bool:
177
177
  """
178
- Delete ephemeral environment - replicates cleanup GHA logic
178
+ Delete ephemeral environment with proper verification
179
179
 
180
180
  Steps:
181
- 1. Check if ECS service exists and is active
182
- 2. Delete ECS service with --force
181
+ 1. Check if ECS service exists
182
+ 2. Delete ECS service with force and wait for completion
183
183
  3. Delete ECR image tag
184
+ 4. Verify deletion completed
184
185
  """
185
186
  try:
186
- # Step 1: Check if service exists and is active
187
- if not self._service_exists(service_name):
188
- return True # Already deleted
187
+ ecs_service_name = f"{service_name}-service" if not service_name.endswith("-service") else service_name
188
+ print(f"🗑️ Deleting ECS service: {ecs_service_name}")
189
+
190
+ # Step 1: Check if service exists
191
+ if not self._service_exists(ecs_service_name):
192
+ print(f"✅ Service {ecs_service_name} already deleted")
193
+ return True
194
+
195
+ # Step 2: Delete ECS service (force delete) and wait
196
+ print(f"☁️ Initiating ECS service deletion...")
197
+ delete_response = self.ecs_client.delete_service(
198
+ cluster=self.cluster,
199
+ service=ecs_service_name,
200
+ force=True
201
+ )
202
+ print(f"🔄 Delete initiated: {delete_response.get('service', {}).get('status', 'unknown')}")
189
203
 
190
- # Step 2: Delete ECS service (force delete)
191
- self.ecs_client.delete_service(cluster=self.cluster, service=service_name, force=True)
204
+ # Step 3: Wait for deletion to complete (crucial!)
205
+ print(f"⏳ Waiting for service deletion to complete...")
206
+ deletion_success = self._wait_for_service_deletion(ecs_service_name, timeout_minutes=10)
207
+
208
+ if not deletion_success:
209
+ print(f"⚠️ Service deletion timeout - service may still exist")
210
+ return False
192
211
 
193
- # Step 3: Delete ECR image tag
194
- # Extract SHA from service name: pr-1234-abc123f → abc123f
195
- sha = service_name.split("-")[-1]
196
- image_tag = f"pr-{pr_number}-{sha}"
212
+ # Step 4: Delete ECR image tag
213
+ print(f"🐳 Cleaning up Docker image...")
214
+ # Fix SHA extraction: pr-34831-ac533ec-service → ac533ec
215
+ # Remove "pr-" prefix and "-service" suffix, then get SHA (last part)
216
+ base_name = service_name.replace("pr-", "").replace("-service", "")
217
+ parts = base_name.split("-")
218
+ sha = parts[-1] if len(parts) > 1 else base_name # Last part is SHA
219
+ image_tag = f"pr-{pr_number}-{sha}-ci"
197
220
 
198
221
  try:
199
222
  self.ecr_client.batch_delete_image(
200
223
  repositoryName=self.repository, imageIds=[{"imageTag": image_tag}]
201
224
  )
225
+ print(f"✅ Deleted ECR image: {image_tag}")
202
226
  except self.ecr_client.exceptions.ImageNotFoundException:
203
- pass # Image already deleted
227
+ print(f"ℹ️ ECR image {image_tag} already deleted")
204
228
 
229
+ print(f"✅ Environment {service_name} fully deleted")
205
230
  return True
206
231
 
207
232
  except Exception as e:
233
+ print(f"❌ AWS deletion failed: {e}")
208
234
  raise AWSError(
209
235
  message=str(e), operation="delete_environment", resource=service_name
210
236
  ) from e
@@ -450,17 +450,31 @@ class PullRequest:
450
450
 
451
451
  # 2. Remove trigger labels (atomic operation)
452
452
  trigger_labels = [label for label in self.labels if "showtime-trigger-" in label]
453
- for trigger_label in trigger_labels:
454
- get_github().remove_label(self.pr_number, trigger_label)
453
+ if trigger_labels:
454
+ print(f"🏷️ Removing trigger labels: {trigger_labels}")
455
+ for trigger_label in trigger_labels:
456
+ get_github().remove_label(self.pr_number, trigger_label)
457
+ else:
458
+ print("🏷️ No trigger labels to remove")
455
459
 
456
460
  # 3. Set building state immediately (claim the PR)
457
461
  if action in ["create_environment", "rolling_update", "auto_sync"]:
458
462
  building_show = self._create_new_show(target_sha)
459
463
  building_show.status = "building"
464
+
460
465
  # Update labels to reflect building state
466
+ print(f"🏷️ Removing existing circus labels...")
461
467
  get_github().remove_circus_labels(self.pr_number)
462
- for label in building_show.to_circus_labels():
463
- get_github().add_label(self.pr_number, label)
468
+
469
+ new_labels = building_show.to_circus_labels()
470
+ print(f"🏷️ Creating new labels: {new_labels}")
471
+ for label in new_labels:
472
+ try:
473
+ get_github().add_label(self.pr_number, label)
474
+ print(f" ✅ Added: {label}")
475
+ except Exception as e:
476
+ print(f" ❌ Failed to add {label}: {e}")
477
+ raise
464
478
 
465
479
  return True
466
480
 
@@ -202,16 +202,14 @@ class Show:
202
202
  ])
203
203
  print("🐳 Local environment: Using cache-from only (no export)")
204
204
 
205
- # Add --load only when building for native architecture or explicitly requested
206
- # Intel Mac/Linux can load linux/amd64, Apple Silicon cannot
207
- native_x86 = platform.machine() in ("x86_64", "AMD64")
205
+ # Add --load only when explicitly requested for local testing
208
206
  force_load = os.getenv("DOCKER_LOAD", "false").lower() == "true"
209
207
 
210
- if native_x86 or force_load:
208
+ if force_load:
211
209
  cmd.append("--load")
212
- print("🐳 Will load image to local Docker daemon (native x86_64 platform)")
210
+ print("🐳 Will load image to local Docker daemon (DOCKER_LOAD=true)")
213
211
  else:
214
- print("🐳 Cross-platform build - pushing to registry only (no local load)")
212
+ print("🐳 Push-only build (no local load) - faster for CI/deployment")
215
213
 
216
214
  # Add build context path last
217
215
  cmd.append(".")