@@ -291,3 +291,104 @@ def test_process_message_project_not_skipped(self, mock_process, mock_sentry_cli
291291 calls = fake_statsd .calls
292292 assert ("increment" , {"metric" : "artifact.processing.started" , "value" : 1 , "tags" : None }) in calls
293293 assert ("increment" , {"metric" : "artifact.processing.completed" , "value" : 1 , "tags" : None }) in calls
294+
295+
296+ class TestToolingVersionExtraction :
297+ """Test extraction of tooling version information from artifacts."""
298+
299+ def setup_method (self ):
300+ """Set up test fixtures."""
301+ mock_sentry_client = Mock (spec = SentryClient )
302+ mock_statsd = Mock ()
303+ self .processor = ArtifactProcessor (mock_sentry_client , mock_statsd )
304+
305+ def test_extract_tooling_versions_with_sentry_cli_version (self , tmp_path ):
306+ """Test extracting sentry-cli version from artifact zip."""
307+ import zipfile
308+
309+ from launchpad .artifacts .artifact import Artifact
310+
311+ # Create a test zip file with .sentry-cli-metadata.txt
312+ zip_path = tmp_path / "test_artifact.zip"
313+ with zipfile .ZipFile (zip_path , "w" ) as zf :
314+ zf .writestr (".sentry-cli-metadata.txt" , "sentry-cli-version: 2.39.1\n " )
315+
316+ # Create an artifact pointing to the zip
317+ artifact = Artifact (path = zip_path )
318+
319+ # Extract versions
320+ versions = self .processor ._extract_tooling_versions (artifact )
321+
322+ # Verify sentry-cli version was extracted
323+ assert versions ["sentry_cli_version" ] == "2.39.1"
324+ assert versions ["fastlane_version" ] is None
325+ assert versions ["gradle_plugin_version" ] is None
326+
327+ def test_extract_tooling_versions_no_metadata_file (self , tmp_path ):
328+ """Test extracting versions when no metadata file exists."""
329+ import zipfile
330+
331+ from launchpad .artifacts .artifact import Artifact
332+
333+ # Create a test zip file without metadata
334+ zip_path = tmp_path / "test_artifact.zip"
335+ with zipfile .ZipFile (zip_path , "w" ) as zf :
336+ zf .writestr ("some_file.txt" , "content" )
337+
338+ artifact = Artifact (path = zip_path )
339+ versions = self .processor ._extract_tooling_versions (artifact )
340+
341+ # All versions should be None
342+ assert versions ["sentry_cli_version" ] is None
343+ assert versions ["fastlane_version" ] is None
344+ assert versions ["gradle_plugin_version" ] is None
345+
346+ def test_extract_tooling_versions_multiline_metadata (self , tmp_path ):
347+ """Test extracting version from metadata file with multiple lines."""
348+ import zipfile
349+
350+ from launchpad .artifacts .artifact import Artifact
351+
352+ zip_path = tmp_path / "test_artifact.zip"
353+ with zipfile .ZipFile (zip_path , "w" ) as zf :
354+ metadata_content = """# Sentry CLI Metadata
355+ sentry-cli-version: 2.40.0
356+ upload-date: 2025-11-10
357+ """
358+ zf .writestr (".sentry-cli-metadata.txt" , metadata_content )
359+
360+ artifact = Artifact (path = zip_path )
361+ versions = self .processor ._extract_tooling_versions (artifact )
362+
363+ assert versions ["sentry_cli_version" ] == "2.40.0"
364+
365+ def test_extract_tooling_versions_with_spaces (self , tmp_path ):
366+ """Test extracting version with extra whitespace."""
367+ import zipfile
368+
369+ from launchpad .artifacts .artifact import Artifact
370+
371+ zip_path = tmp_path / "test_artifact.zip"
372+ with zipfile .ZipFile (zip_path , "w" ) as zf :
373+ zf .writestr (".sentry-cli-metadata.txt" , "sentry-cli-version: 2.39.1 \n " )
374+
375+ artifact = Artifact (path = zip_path )
376+ versions = self .processor ._extract_tooling_versions (artifact )
377+
378+ assert versions ["sentry_cli_version" ] == "2.39.1"
379+
380+ def test_extract_tooling_versions_invalid_zip (self , tmp_path ):
381+ """Test graceful handling of invalid/corrupted zip file."""
382+ from launchpad .artifacts .artifact import Artifact
383+
384+ # Create a non-zip file
385+ invalid_zip = tmp_path / "invalid.zip"
386+ invalid_zip .write_text ("not a zip file" )
387+
388+ artifact = Artifact (path = invalid_zip )
389+ versions = self .processor ._extract_tooling_versions (artifact )
390+
391+ # Should return all None values without crashing
392+ assert versions ["sentry_cli_version" ] is None
393+ assert versions ["fastlane_version" ] is None
394+ assert versions ["gradle_plugin_version" ] is None
0 commit comments