-
-
Notifications
You must be signed in to change notification settings - Fork 236
feat(build): Track plugin versions from SENTRY_PIPELINE in build uploads (EME-606) #2994
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
runningcode
wants to merge
8
commits into
master
Choose a base branch
from
no/track-plugin-versions-in-build-uploads
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+172
−20
Open
Changes from 6 commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
d43c2a5
feat(build): Add CLI parameters to track plugin versions (EME-XXX)
runningcode 2ab57cf
refactor(build): Use --metadata parameter for flexible key-value meta…
runningcode 4d232d8
test: Update help output tests to use --metadata parameter (EME-XXX)
runningcode 7809fa6
fix: Use to_owned() instead of to_string() for clippy (EME-XXX)
runningcode 6e57330
fix: Add validation for metadata keys (EME-XXX)
runningcode ded4c51
refactor(build): Use SENTRY_PIPELINE env var for plugin versions (EME…
runningcode 53daba1
style: Apply cargo fmt formatting (EME-XXX)
runningcode c837eb6
docs(changelog): Update build upload plugin tracking description (EME…
runningcode File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -150,6 +150,31 @@ pub fn execute(matches: &ArgMatches) -> Result<()> { | |
| let build_configuration = matches.get_one("build_configuration").map(String::as_str); | ||
| let release_notes = matches.get_one("release_notes").map(String::as_str); | ||
|
|
||
| // Parse plugin info from SENTRY_PIPELINE environment variable | ||
| // Format: "sentry-gradle-plugin/4.12.0" or "sentry-fastlane-plugin/1.2.3" | ||
| let (plugin_name, plugin_version) = config | ||
| .get_pipeline_env() | ||
| .and_then(|pipeline| { | ||
| let parts: Vec<&str> = pipeline.splitn(2, '/').collect(); | ||
| if parts.len() == 2 { | ||
| let name = parts[0]; | ||
| let version = parts[1]; | ||
|
|
||
| // Only extract known Sentry plugins | ||
| if name == "sentry-gradle-plugin" || name == "sentry-fastlane-plugin" { | ||
| debug!("Detected {name} version {version} from SENTRY_PIPELINE"); | ||
| Some((name.to_owned(), version.to_owned())) | ||
| } else { | ||
| debug!("SENTRY_PIPELINE contains unrecognized plugin: {name}"); | ||
| None | ||
| } | ||
| } else { | ||
| debug!("SENTRY_PIPELINE format not recognized: {pipeline}"); | ||
| None | ||
| } | ||
| }) | ||
| .unzip(); | ||
|
|
||
| let api = Api::current(); | ||
| let authenticated_api = api.authenticated()?; | ||
|
|
||
|
|
@@ -171,10 +196,10 @@ pub fn execute(matches: &ArgMatches) -> Result<()> { | |
|
|
||
| let normalized_zip = if path.is_file() { | ||
| debug!("Normalizing file: {}", path.display()); | ||
| handle_file(path, &byteview)? | ||
| handle_file(path, &byteview, plugin_name.as_deref(), plugin_version.as_deref())? | ||
| } else if path.is_dir() { | ||
| debug!("Normalizing directory: {}", path.display()); | ||
This comment was marked as outdated.
Sorry, something went wrong. |
||
| handle_directory(path).with_context(|| { | ||
| handle_directory(path, plugin_name.as_deref(), plugin_version.as_deref()).with_context(|| { | ||
| format!( | ||
| "Failed to generate uploadable bundle for directory {}", | ||
| path.display() | ||
|
|
@@ -434,18 +459,23 @@ fn collect_git_metadata( | |
| } | ||
| } | ||
|
|
||
| fn handle_file(path: &Path, byteview: &ByteView) -> Result<TempFile> { | ||
| fn handle_file( | ||
| path: &Path, | ||
| byteview: &ByteView, | ||
| plugin_name: Option<&str>, | ||
| plugin_version: Option<&str>, | ||
| ) -> Result<TempFile> { | ||
| // Handle IPA files by converting them to XCArchive | ||
| #[cfg(all(target_os = "macos", target_arch = "aarch64"))] | ||
| if is_zip_file(byteview) && is_ipa_file(byteview)? { | ||
| debug!("Converting IPA file to XCArchive structure"); | ||
| let archive_temp_dir = TempDir::create()?; | ||
| return ipa_to_xcarchive(path, byteview, &archive_temp_dir) | ||
| .and_then(|path| handle_directory(&path)) | ||
| .and_then(|path| handle_directory(&path, plugin_name, plugin_version)) | ||
| .with_context(|| format!("Failed to process IPA file {}", path.display())); | ||
| } | ||
|
|
||
| normalize_file(path, byteview).with_context(|| { | ||
| normalize_file(path, byteview, plugin_name, plugin_version).with_context(|| { | ||
| format!( | ||
| "Failed to generate uploadable bundle for file {}", | ||
| path.display() | ||
|
|
@@ -499,7 +529,12 @@ fn validate_is_supported_build(path: &Path, bytes: &[u8]) -> Result<()> { | |
| } | ||
|
|
||
| // For APK and AAB files, we'll copy them directly into the zip | ||
| fn normalize_file(path: &Path, bytes: &[u8]) -> Result<TempFile> { | ||
| fn normalize_file( | ||
| path: &Path, | ||
| bytes: &[u8], | ||
| plugin_name: Option<&str>, | ||
| plugin_version: Option<&str>, | ||
| ) -> Result<TempFile> { | ||
| debug!("Creating normalized zip for file: {}", path.display()); | ||
|
|
||
| let temp_file = TempFile::create()?; | ||
|
|
@@ -523,20 +558,24 @@ fn normalize_file(path: &Path, bytes: &[u8]) -> Result<TempFile> { | |
| zip.start_file(file_name, options)?; | ||
| zip.write_all(bytes)?; | ||
|
|
||
| write_version_metadata(&mut zip)?; | ||
| write_version_metadata(&mut zip, plugin_name, plugin_version)?; | ||
|
|
||
| zip.finish()?; | ||
| debug!("Successfully created normalized zip for file"); | ||
| Ok(temp_file) | ||
| } | ||
|
|
||
| fn handle_directory(path: &Path) -> Result<TempFile> { | ||
| fn handle_directory( | ||
| path: &Path, | ||
| plugin_name: Option<&str>, | ||
| plugin_version: Option<&str>, | ||
| ) -> Result<TempFile> { | ||
| let temp_dir = TempDir::create()?; | ||
| #[cfg(all(target_os = "macos", target_arch = "aarch64"))] | ||
| if is_apple_app(path)? { | ||
| handle_asset_catalogs(path, temp_dir.path()); | ||
| } | ||
| normalize_directory(path, temp_dir.path()) | ||
| normalize_directory(path, temp_dir.path(), plugin_name, plugin_version) | ||
| } | ||
|
|
||
| /// Returns artifact url if upload was successful. | ||
|
|
@@ -674,7 +713,7 @@ mod tests { | |
| fs::create_dir_all(test_dir.join("Products"))?; | ||
| fs::write(test_dir.join("Products").join("app.txt"), "test content")?; | ||
|
|
||
| let result_zip = normalize_directory(&test_dir, temp_dir.path())?; | ||
| let result_zip = normalize_directory(&test_dir, temp_dir.path(), None, None)?; | ||
| let zip_file = fs::File::open(result_zip.path())?; | ||
| let mut archive = ZipArchive::new(zip_file)?; | ||
| let file = archive.by_index(0)?; | ||
|
|
@@ -690,7 +729,7 @@ mod tests { | |
| let xcarchive_path = Path::new("tests/integration/_fixtures/build/archive.xcarchive"); | ||
|
|
||
| // Process the XCArchive directory | ||
| let result = handle_directory(xcarchive_path)?; | ||
| let result = handle_directory(xcarchive_path, None, None)?; | ||
|
|
||
| // Verify the resulting zip contains parsed assets | ||
| let zip_file = fs::File::open(result.path())?; | ||
|
|
@@ -723,7 +762,7 @@ mod tests { | |
| let byteview = ByteView::open(ipa_path)?; | ||
|
|
||
| // Process the IPA file - this should work even without asset catalogs | ||
| let result = handle_file(ipa_path, &byteview)?; | ||
| let result = handle_file(ipa_path, &byteview, None, None)?; | ||
|
|
||
| let zip_file = fs::File::open(result.path())?; | ||
| let mut archive = ZipArchive::new(zip_file)?; | ||
|
|
@@ -760,7 +799,7 @@ mod tests { | |
| let symlink_path = test_dir.join("Products").join("app_link.txt"); | ||
| symlink("app.txt", &symlink_path)?; | ||
|
|
||
| let result_zip = normalize_directory(&test_dir, temp_dir.path())?; | ||
| let result_zip = normalize_directory(&test_dir, temp_dir.path(), None, None)?; | ||
| let zip_file = fs::File::open(result_zip.path())?; | ||
| let mut archive = ZipArchive::new(zip_file)?; | ||
|
|
||
|
|
@@ -877,4 +916,93 @@ mod tests { | |
| "head_ref should be empty with auto_collect=false and no explicit value" | ||
| ); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_metadata_includes_gradle_plugin_version() -> Result<()> { | ||
| let temp_dir = crate::utils::fs::TempDir::create()?; | ||
| let test_dir = temp_dir.path().join("TestApp.xcarchive"); | ||
| fs::create_dir_all(test_dir.join("Products"))?; | ||
| fs::write(test_dir.join("Products").join("app.txt"), "test content")?; | ||
|
|
||
| let result_zip = normalize_directory( | ||
| &test_dir, | ||
| temp_dir.path(), | ||
| Some("sentry-gradle-plugin"), | ||
| Some("4.12.0"), | ||
| )?; | ||
| let zip_file = fs::File::open(result_zip.path())?; | ||
| let mut archive = ZipArchive::new(zip_file)?; | ||
|
|
||
| // Find and read the metadata file | ||
| let metadata_file = archive.by_name(".sentry-cli-metadata.txt")?; | ||
| let metadata_content = std::io::read_to_string(metadata_file)?; | ||
|
|
||
| assert!( | ||
| metadata_content.contains("sentry-cli-version:"), | ||
| "Metadata should contain sentry-cli-version" | ||
| ); | ||
| assert!( | ||
| metadata_content.contains("sentry-gradle-plugin: 4.12.0"), | ||
| "Metadata should contain sentry-gradle-plugin" | ||
| ); | ||
| Ok(()) | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_metadata_includes_fastlane_plugin_version() -> Result<()> { | ||
| let temp_dir = crate::utils::fs::TempDir::create()?; | ||
| let test_dir = temp_dir.path().join("TestApp.xcarchive"); | ||
| fs::create_dir_all(test_dir.join("Products"))?; | ||
| fs::write(test_dir.join("Products").join("app.txt"), "test content")?; | ||
|
|
||
| let result_zip = normalize_directory( | ||
| &test_dir, | ||
| temp_dir.path(), | ||
| Some("sentry-fastlane-plugin"), | ||
| Some("1.2.3"), | ||
| )?; | ||
| let zip_file = fs::File::open(result_zip.path())?; | ||
| let mut archive = ZipArchive::new(zip_file)?; | ||
|
|
||
| // Find and read the metadata file | ||
| let metadata_file = archive.by_name(".sentry-cli-metadata.txt")?; | ||
| let metadata_content = std::io::read_to_string(metadata_file)?; | ||
|
|
||
| assert!( | ||
| metadata_content.contains("sentry-cli-version:"), | ||
| "Metadata should contain sentry-cli-version" | ||
| ); | ||
| assert!( | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. technically it is impossible to have both. i could also add an assertion that both are not set but I didn't think it was worth it. |
||
| metadata_content.contains("sentry-fastlane-plugin: 1.2.3"), | ||
| "Metadata should contain sentry-fastlane-plugin" | ||
| ); | ||
| Ok(()) | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_metadata_without_plugin() -> Result<()> { | ||
| let temp_dir = crate::utils::fs::TempDir::create()?; | ||
| let test_dir = temp_dir.path().join("TestApp.xcarchive"); | ||
| fs::create_dir_all(test_dir.join("Products"))?; | ||
| fs::write(test_dir.join("Products").join("app.txt"), "test content")?; | ||
|
|
||
| // No plugin info provided | ||
| let result_zip = normalize_directory(&test_dir, temp_dir.path(), None, None)?; | ||
| let zip_file = fs::File::open(result_zip.path())?; | ||
| let mut archive = ZipArchive::new(zip_file)?; | ||
|
|
||
| let metadata_file = archive.by_name(".sentry-cli-metadata.txt")?; | ||
| let metadata_content = std::io::read_to_string(metadata_file)?; | ||
|
|
||
| // Should only contain sentry-cli-version | ||
| assert!( | ||
| metadata_content.contains("sentry-cli-version:"), | ||
| "Metadata should contain sentry-cli-version" | ||
| ); | ||
|
|
||
| // Should not have any other lines besides the version | ||
| let line_count = metadata_content.lines().count(); | ||
| assert_eq!(line_count, 1, "Should only have one line when no plugin info"); | ||
| Ok(()) | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will be printed out as debug for javascript when they use the
SENTRY_PIPELINEvariable. I think this message is helpful for debugging but might be confusing if we print it for javascript devs.Alternatively, we can also detect the javascript tool and not print this in that case. WDYT?