sentry-cli 3.3.4__tar.gz → 3.4.0__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.
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/Cargo.lock +9 -30
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/Cargo.toml +3 -3
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/PKG-INFO +1 -1
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/sentry_cli.egg-info/PKG-INFO +1 -1
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/api/data_types/snapshots.rs +47 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/api/mod.rs +2 -1
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/build/snapshots.rs +121 -88
- sentry_cli-3.4.0/src/commands/debug_files/bundle_jvm.rs +250 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/file_search.rs +12 -5
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/logging.rs +4 -8
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/progress.rs +2 -9
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/source_bundle.rs +58 -32
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/sourcemaps.rs +6 -1
- sentry_cli-3.3.4/src/commands/debug_files/bundle_jvm.rs +0 -102
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/LICENSE +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/MANIFEST.in +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/README.md +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/apple-catalog-parsing/AGENTS.md +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/apple-catalog-parsing/CLAUDE.md +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/apple-catalog-parsing/Cargo.toml +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/apple-catalog-parsing/build.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/apple-catalog-parsing/native/swift/AssetCatalogParser/Package.swift +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/apple-catalog-parsing/native/swift/AssetCatalogParser/Sources/AssetCatalogParser/AssetCatalogReader.swift +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/apple-catalog-parsing/native/swift/AssetCatalogParser/Sources/ObjcSupport/include/safeValueForKey.h +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/apple-catalog-parsing/native/swift/AssetCatalogParser/Sources/ObjcSupport/safeValueForKey.m +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/apple-catalog-parsing/native/swift/AssetCatalogParser/Tests/AssetCatalogParserTests/AssetCatalogParserTests.swift +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/apple-catalog-parsing/native/swift/AssetCatalogParser/Tests/AssetCatalogParserTests/Resources/test.xcarchive/Info.plist +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/apple-catalog-parsing/native/swift/AssetCatalogParser/Tests/AssetCatalogParserTests/Resources/test.xcarchive/Products/Applications/DemoApp.app/Assets.car +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/apple-catalog-parsing/src/asset_catalog.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/apple-catalog-parsing/src/lib.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/build.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/pyproject.toml +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/sentry_cli.egg-info/SOURCES.txt +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/sentry_cli.egg-info/dependency_links.txt +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/sentry_cli.egg-info/top_level.txt +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/setup.cfg +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/setup.py +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/AGENTS.md +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/CLAUDE.md +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/api/connection_manager.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/api/data_types/chunking/artifact.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/api/data_types/chunking/build.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/api/data_types/chunking/compression.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/api/data_types/chunking/dif.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/api/data_types/chunking/file_state.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/api/data_types/chunking/hash_algorithm.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/api/data_types/chunking/mod.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/api/data_types/chunking/upload/mod.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/api/data_types/chunking/upload/options.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/api/data_types/code_mappings.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/api/data_types/deploy.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/api/data_types/mod.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/api/encoding.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/api/envelopes_api.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/api/errors/api_error.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/api/errors/mod.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/api/errors/sentry_error.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/api/pagination.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/api/serialization.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/bashsupport.sh +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/bash_hook.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/build/download.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/build/mod.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/build/upload.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/code_mappings/mod.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/code_mappings/upload.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/dart_symbol_map/mod.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/dart_symbol_map/upload.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/debug_files/bundle_sources.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/debug_files/check.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/debug_files/find.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/debug_files/mod.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/debug_files/print_sources.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/debug_files/upload.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/deploys/list.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/deploys/mod.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/deploys/new.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/derive_parser.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/events/list.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/events/mod.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/info.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/issues/list.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/issues/mod.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/issues/mute.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/issues/resolve.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/issues/unresolve.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/login.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/logs/list.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/logs/mod.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/mod.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/monitors/list.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/monitors/mod.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/monitors/run.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/organizations/list.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/organizations/mod.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/proguard/mod.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/proguard/upload.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/proguard/uuid.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/projects/list.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/projects/mod.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/react_native/gradle.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/react_native/mod.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/react_native/xcode.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/releases/archive.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/releases/delete.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/releases/finalize.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/releases/info.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/releases/list.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/releases/mod.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/releases/new.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/releases/propose_version.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/releases/restore.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/releases/set_commits.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/repos/list.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/repos/mod.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/send_envelope.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/send_event.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/send_metric/common_args.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/send_metric/increment.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/send_metric/mod.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/send_metric/set.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/sourcemaps/inject.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/sourcemaps/mod.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/sourcemaps/resolve.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/sourcemaps/upload.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/uninstall.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/update.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/upload_dif.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/upload_dsym.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/commands/upload_proguard.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/config.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/constants.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/main.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/android.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/args.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/auth_token/auth_token_impl.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/auth_token/error.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/auth_token/mod.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/auth_token/org_auth_token.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/auth_token/redacting.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/auth_token/test.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/auth_token/user_auth_token.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/build/apple.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/build/mod.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/build/normalize.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/build/validation.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/build_vcs.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/chunks/mod.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/chunks/options.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/chunks/types.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/chunks/upload.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/ci.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/cordova.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/dif.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/dif_upload/error.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/dif_upload/mod.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/event.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/file_upload.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/formatting.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/fs.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/http.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/mod.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/non_empty.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/proguard/mapping.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/proguard/mod.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/proguard/upload.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/releases.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/retry.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/snapshots/sentry_cli__utils__vcs__tests__generate_patch_default_twenty.snap +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/snapshots/sentry_cli__utils__vcs__tests__generate_patch_ignore_missing.snap +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/snapshots/sentry_cli__utils__vcs__tests__generate_patch_set_base.snap +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/snapshots/sentry_cli__utils__vcs__tests__generate_patch_set_previous_commit.snap +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/snapshots/sentry_cli__utils__vcs__tests__get_commits_from_git.snap +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/sourcemaps/inject.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/system.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/ui.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/update.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/value_parsers.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/vcs.rs +0 -0
- {sentry_cli-3.3.4 → sentry_cli-3.4.0}/src/utils/xcode.rs +0 -0
|
@@ -206,28 +206,6 @@ dependencies = [
|
|
|
206
206
|
"tokio",
|
|
207
207
|
]
|
|
208
208
|
|
|
209
|
-
[[package]]
|
|
210
|
-
name = "async-stream"
|
|
211
|
-
version = "0.3.6"
|
|
212
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
213
|
-
checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476"
|
|
214
|
-
dependencies = [
|
|
215
|
-
"async-stream-impl",
|
|
216
|
-
"futures-core",
|
|
217
|
-
"pin-project-lite",
|
|
218
|
-
]
|
|
219
|
-
|
|
220
|
-
[[package]]
|
|
221
|
-
name = "async-stream-impl"
|
|
222
|
-
version = "0.3.6"
|
|
223
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
224
|
-
checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d"
|
|
225
|
-
dependencies = [
|
|
226
|
-
"proc-macro2",
|
|
227
|
-
"quote",
|
|
228
|
-
"syn",
|
|
229
|
-
]
|
|
230
|
-
|
|
231
209
|
[[package]]
|
|
232
210
|
name = "atomic-waker"
|
|
233
211
|
version = "1.1.2"
|
|
@@ -2322,12 +2300,11 @@ dependencies = [
|
|
|
2322
2300
|
|
|
2323
2301
|
[[package]]
|
|
2324
2302
|
name = "objectstore-client"
|
|
2325
|
-
version = "0.1.
|
|
2303
|
+
version = "0.1.6"
|
|
2326
2304
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2327
|
-
checksum = "
|
|
2305
|
+
checksum = "f99caa869461b61decd1985c029d7e1462d1bde8e2448040db27d567165fcc1e"
|
|
2328
2306
|
dependencies = [
|
|
2329
2307
|
"async-compression",
|
|
2330
|
-
"async-stream",
|
|
2331
2308
|
"bytes",
|
|
2332
2309
|
"futures-util",
|
|
2333
2310
|
"infer",
|
|
@@ -2346,9 +2323,9 @@ dependencies = [
|
|
|
2346
2323
|
|
|
2347
2324
|
[[package]]
|
|
2348
2325
|
name = "objectstore-types"
|
|
2349
|
-
version = "0.1.
|
|
2326
|
+
version = "0.1.6"
|
|
2350
2327
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2351
|
-
checksum = "
|
|
2328
|
+
checksum = "c375bccef8773d1739eabb7e2b1bbd7e9a9071c8f9557e3b50dce7220e8c8736"
|
|
2352
2329
|
dependencies = [
|
|
2353
2330
|
"http",
|
|
2354
2331
|
"humantime",
|
|
@@ -3230,9 +3207,9 @@ dependencies = [
|
|
|
3230
3207
|
|
|
3231
3208
|
[[package]]
|
|
3232
3209
|
name = "rustls-webpki"
|
|
3233
|
-
version = "0.103.
|
|
3210
|
+
version = "0.103.10"
|
|
3234
3211
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
3235
|
-
checksum = "
|
|
3212
|
+
checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef"
|
|
3236
3213
|
dependencies = [
|
|
3237
3214
|
"ring",
|
|
3238
3215
|
"rustls-pki-types",
|
|
@@ -3345,6 +3322,7 @@ version = "0.8.0"
|
|
|
3345
3322
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
3346
3323
|
checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e"
|
|
3347
3324
|
dependencies = [
|
|
3325
|
+
"serde",
|
|
3348
3326
|
"zeroize",
|
|
3349
3327
|
]
|
|
3350
3328
|
|
|
@@ -3414,7 +3392,7 @@ dependencies = [
|
|
|
3414
3392
|
|
|
3415
3393
|
[[package]]
|
|
3416
3394
|
name = "sentry-cli"
|
|
3417
|
-
version = "3.
|
|
3395
|
+
version = "3.4.0"
|
|
3418
3396
|
dependencies = [
|
|
3419
3397
|
"anyhow",
|
|
3420
3398
|
"anylog",
|
|
@@ -4142,6 +4120,7 @@ dependencies = [
|
|
|
4142
4120
|
"bytes",
|
|
4143
4121
|
"futures-core",
|
|
4144
4122
|
"futures-sink",
|
|
4123
|
+
"futures-util",
|
|
4145
4124
|
"pin-project-lite",
|
|
4146
4125
|
"tokio",
|
|
4147
4126
|
]
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
build = "build.rs"
|
|
3
3
|
name = "sentry-cli"
|
|
4
|
-
version = "3.
|
|
4
|
+
version = "3.4.0"
|
|
5
5
|
edition = "2021"
|
|
6
6
|
rust-version = "1.91"
|
|
7
7
|
|
|
@@ -44,7 +44,7 @@ java-properties = "2.0.0"
|
|
|
44
44
|
lazy_static = "1.4.0"
|
|
45
45
|
libc = "0.2.139"
|
|
46
46
|
log = { version = "0.4.17", features = ["std"] }
|
|
47
|
-
objectstore-client = { version = "0.1.
|
|
47
|
+
objectstore-client = { version = "0.1.6" , default-features = false, features = ["native-tls"] }
|
|
48
48
|
open = "3.2.0"
|
|
49
49
|
parking_lot = "0.12.1"
|
|
50
50
|
percent-encoding = "2.2.0"
|
|
@@ -79,7 +79,7 @@ zip = "2.4.2"
|
|
|
79
79
|
data-encoding = "2.3.3"
|
|
80
80
|
magic_string = "0.3.4"
|
|
81
81
|
chrono-tz = "0.8.4"
|
|
82
|
-
secrecy = "0.8.0"
|
|
82
|
+
secrecy = { version = "0.8.0", features = ["serde"] }
|
|
83
83
|
lru = "0.16.3"
|
|
84
84
|
backon = { version = "1.5.2", features = ["std", "std-blocking-sleep"] }
|
|
85
85
|
|
|
@@ -25,6 +25,14 @@ pub struct CreateSnapshotResponse {
|
|
|
25
25
|
pub struct SnapshotsManifest<'a> {
|
|
26
26
|
pub app_id: String,
|
|
27
27
|
pub images: HashMap<String, ImageMetadata>,
|
|
28
|
+
/// If set, Sentry will only report images as changed if their difference %
|
|
29
|
+
/// is greater than this value (e.g. 0.01 = only report changes >= 1%).
|
|
30
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
31
|
+
pub diff_threshold: Option<f64>,
|
|
32
|
+
/// When true, this upload contains only a subset of images.
|
|
33
|
+
/// Removals and renames will not be detected on PRs.
|
|
34
|
+
#[serde(skip_serializing_if = "std::ops::Not::not")]
|
|
35
|
+
pub selective: bool,
|
|
28
36
|
#[serde(flatten)]
|
|
29
37
|
pub vcs_info: VcsInfo<'a>,
|
|
30
38
|
}
|
|
@@ -55,6 +63,45 @@ mod tests {
|
|
|
55
63
|
|
|
56
64
|
use serde_json::json;
|
|
57
65
|
|
|
66
|
+
fn empty_vcs_info() -> VcsInfo<'static> {
|
|
67
|
+
VcsInfo {
|
|
68
|
+
head_sha: None,
|
|
69
|
+
base_sha: None,
|
|
70
|
+
vcs_provider: "".into(),
|
|
71
|
+
head_repo_name: "".into(),
|
|
72
|
+
base_repo_name: "".into(),
|
|
73
|
+
head_ref: "".into(),
|
|
74
|
+
base_ref: "".into(),
|
|
75
|
+
pr_number: None,
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
#[test]
|
|
80
|
+
fn manifest_omits_selective_when_false() {
|
|
81
|
+
let manifest = SnapshotsManifest {
|
|
82
|
+
app_id: "app".into(),
|
|
83
|
+
images: HashMap::new(),
|
|
84
|
+
diff_threshold: None,
|
|
85
|
+
selective: false,
|
|
86
|
+
vcs_info: empty_vcs_info(),
|
|
87
|
+
};
|
|
88
|
+
let json = serde_json::to_value(&manifest).unwrap();
|
|
89
|
+
assert!(!json.as_object().unwrap().contains_key("selective"));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
#[test]
|
|
93
|
+
fn manifest_includes_selective_when_true() {
|
|
94
|
+
let manifest = SnapshotsManifest {
|
|
95
|
+
app_id: "app".into(),
|
|
96
|
+
images: HashMap::new(),
|
|
97
|
+
diff_threshold: None,
|
|
98
|
+
selective: true,
|
|
99
|
+
vcs_info: empty_vcs_info(),
|
|
100
|
+
};
|
|
101
|
+
let json = serde_json::to_value(&manifest).unwrap();
|
|
102
|
+
assert_eq!(json["selective"], json!(true));
|
|
103
|
+
}
|
|
104
|
+
|
|
58
105
|
#[test]
|
|
59
106
|
fn cli_managed_fields_override_sidecar_fields() {
|
|
60
107
|
let extra = serde_json::from_value(json!({
|
|
@@ -33,7 +33,7 @@ use lazy_static::lazy_static;
|
|
|
33
33
|
use log::{debug, info, warn};
|
|
34
34
|
use parking_lot::Mutex;
|
|
35
35
|
use regex::{Captures, Regex};
|
|
36
|
-
use secrecy::ExposeSecret as _;
|
|
36
|
+
use secrecy::{ExposeSecret as _, SecretString};
|
|
37
37
|
use serde::de::DeserializeOwned;
|
|
38
38
|
use serde::{Deserialize, Serialize};
|
|
39
39
|
use sha1_smol::Digest;
|
|
@@ -2065,5 +2065,6 @@ pub struct SnapshotsUploadOptions {
|
|
|
2065
2065
|
pub struct ObjectstoreUploadOptions {
|
|
2066
2066
|
pub url: String,
|
|
2067
2067
|
pub scopes: Vec<(String, String)>,
|
|
2068
|
+
pub auth_token: Option<SecretString>,
|
|
2068
2069
|
pub expiration_policy: String,
|
|
2069
2070
|
}
|
|
@@ -9,8 +9,9 @@ use anyhow::{Context as _, Result};
|
|
|
9
9
|
use clap::{Arg, ArgMatches, Command};
|
|
10
10
|
use console::style;
|
|
11
11
|
use itertools::Itertools as _;
|
|
12
|
-
use log::{debug,
|
|
12
|
+
use log::{debug, warn};
|
|
13
13
|
use objectstore_client::{ClientBuilder, ExpirationPolicy, Usecase};
|
|
14
|
+
use rayon::prelude::*;
|
|
14
15
|
use secrecy::ExposeSecret as _;
|
|
15
16
|
use serde_json::Value;
|
|
16
17
|
use sha2::{Digest as _, Sha256};
|
|
@@ -50,6 +51,32 @@ pub fn make_command(command: Command) -> Command {
|
|
|
50
51
|
.help("The application identifier.")
|
|
51
52
|
.required(true),
|
|
52
53
|
)
|
|
54
|
+
.arg(
|
|
55
|
+
Arg::new("diff_threshold")
|
|
56
|
+
.long("diff-threshold")
|
|
57
|
+
.value_name("THRESHOLD")
|
|
58
|
+
.value_parser(|s: &str| {
|
|
59
|
+
let v: f64 = s.parse().map_err(|e| format!("invalid float: {e}"))?;
|
|
60
|
+
if !(0.0..=1.0).contains(&v) {
|
|
61
|
+
return Err("value must be between 0.0 and 1.0".to_owned());
|
|
62
|
+
}
|
|
63
|
+
Ok(v)
|
|
64
|
+
})
|
|
65
|
+
.help(
|
|
66
|
+
"If set, Sentry will only report images as changed if their \
|
|
67
|
+
difference % is greater than this value. \
|
|
68
|
+
Example: 0.01 = only report image changes >= 1%.",
|
|
69
|
+
),
|
|
70
|
+
)
|
|
71
|
+
.arg(
|
|
72
|
+
Arg::new("selective")
|
|
73
|
+
.long("selective")
|
|
74
|
+
.action(clap::ArgAction::SetTrue)
|
|
75
|
+
.help(
|
|
76
|
+
"Indicates this upload contains only a subset of images. \
|
|
77
|
+
Removals and renames cannot be detected on PRs.",
|
|
78
|
+
),
|
|
79
|
+
)
|
|
53
80
|
.git_metadata_args()
|
|
54
81
|
}
|
|
55
82
|
|
|
@@ -122,9 +149,15 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
|
|
|
122
149
|
let manifest_entries = upload_images(images, &org, &project)?;
|
|
123
150
|
|
|
124
151
|
// Build manifest from discovered images
|
|
152
|
+
let diff_threshold = matches.get_one::<f64>("diff_threshold").copied();
|
|
153
|
+
|
|
154
|
+
let selective = matches.get_flag("selective");
|
|
155
|
+
|
|
125
156
|
let manifest = SnapshotsManifest {
|
|
126
157
|
app_id: app_id.clone(),
|
|
127
158
|
images: manifest_entries,
|
|
159
|
+
diff_threshold,
|
|
160
|
+
selective,
|
|
128
161
|
vcs_info,
|
|
129
162
|
};
|
|
130
163
|
|
|
@@ -230,7 +263,7 @@ fn compute_sha256_hash(path: &Path) -> Result<String> {
|
|
|
230
263
|
let mut file = std::fs::File::open(path)
|
|
231
264
|
.with_context(|| format!("Failed to open image for hashing: {}", path.display()))?;
|
|
232
265
|
let mut hasher = Sha256::new();
|
|
233
|
-
let mut buffer = [0u8;
|
|
266
|
+
let mut buffer = [0u8; 65536];
|
|
234
267
|
loop {
|
|
235
268
|
let bytes_read = file
|
|
236
269
|
.read(&mut buffer)
|
|
@@ -282,6 +315,11 @@ fn read_sidecar_metadata(image_path: &Path) -> Result<HashMap<String, Value>> {
|
|
|
282
315
|
})
|
|
283
316
|
}
|
|
284
317
|
|
|
318
|
+
struct PreparedImage {
|
|
319
|
+
path: PathBuf,
|
|
320
|
+
key: String,
|
|
321
|
+
}
|
|
322
|
+
|
|
285
323
|
fn upload_images(
|
|
286
324
|
images: Vec<ImageInfo>,
|
|
287
325
|
org: &str,
|
|
@@ -294,33 +332,43 @@ fn upload_images(
|
|
|
294
332
|
let expiration = ExpirationPolicy::from_str(&options.objectstore.expiration_policy)
|
|
295
333
|
.context("Failed to parse expiration policy from upload options")?;
|
|
296
334
|
|
|
297
|
-
let
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
335
|
+
let mut builder = ClientBuilder::new(options.objectstore.url);
|
|
336
|
+
if let Some(token) = options.objectstore.auth_token {
|
|
337
|
+
builder = builder.token(token.expose_secret().to_owned());
|
|
338
|
+
}
|
|
339
|
+
let builder = builder;
|
|
340
|
+
|
|
341
|
+
let sentry_token = match authenticated_api.auth() {
|
|
342
|
+
Auth::Token(token) => token.raw().expose_secret().to_owned(),
|
|
343
|
+
};
|
|
344
|
+
let sentry_token = format!("Bearer {sentry_token}")
|
|
345
|
+
.parse()
|
|
346
|
+
// Ignore original error to avoid leaking the token (even though it's invalid)
|
|
347
|
+
.map_err(|_| anyhow::anyhow!("Invalid auth token"))?;
|
|
348
|
+
let client = builder
|
|
349
|
+
.configure_reqwest(|r| {
|
|
350
|
+
let mut headers = http::HeaderMap::new();
|
|
351
|
+
headers.insert(http::header::AUTHORIZATION, sentry_token);
|
|
352
|
+
r.connect_timeout(Duration::from_secs(10))
|
|
353
|
+
.default_headers(headers)
|
|
304
354
|
})
|
|
305
|
-
.configure_reqwest(|r| r.connect_timeout(Duration::from_secs(10)))
|
|
306
355
|
.build()?;
|
|
307
356
|
|
|
357
|
+
let scopes = options.objectstore.scopes;
|
|
358
|
+
|
|
359
|
+
let find_scope = |name: &str| {
|
|
360
|
+
scopes
|
|
361
|
+
.iter()
|
|
362
|
+
.find(|(k, _)| k == name)
|
|
363
|
+
.map(|(_, v)| v.clone())
|
|
364
|
+
};
|
|
365
|
+
let org_id = find_scope("org").context("Missing org in UploadOptions scope")?;
|
|
366
|
+
let project_id = find_scope("project").context("Missing project in UploadOptions scope")?;
|
|
367
|
+
|
|
308
368
|
let mut scope = Usecase::new("preprod").scope();
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
scope = scope.push(&key, value.clone());
|
|
312
|
-
if key == "org" {
|
|
313
|
-
org_id = Some(value);
|
|
314
|
-
} else if key == "project" {
|
|
315
|
-
project_id = Some(value);
|
|
316
|
-
}
|
|
369
|
+
for (key, value) in scopes {
|
|
370
|
+
scope = scope.push(&key, value);
|
|
317
371
|
}
|
|
318
|
-
let Some(org_id) = org_id else {
|
|
319
|
-
anyhow::bail!("Missing org in UploadOptions scope");
|
|
320
|
-
};
|
|
321
|
-
let Some(project_id) = project_id else {
|
|
322
|
-
anyhow::bail!("Missing project in UploadOptions scope");
|
|
323
|
-
};
|
|
324
372
|
|
|
325
373
|
let session = scope.session(&client)?;
|
|
326
374
|
|
|
@@ -329,46 +377,27 @@ fn upload_images(
|
|
|
329
377
|
.build()
|
|
330
378
|
.context("Failed to create tokio runtime")?;
|
|
331
379
|
|
|
332
|
-
let mut many_builder = session.many();
|
|
333
380
|
let mut manifest_entries = HashMap::new();
|
|
334
|
-
let mut
|
|
335
|
-
let mut
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
.
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
.into_owned();
|
|
381
|
+
let mut duplicates: Vec<String> = Vec::new();
|
|
382
|
+
let mut uploads = Vec::with_capacity(images.len());
|
|
383
|
+
|
|
384
|
+
let hashed_images: Vec<_> = images
|
|
385
|
+
.into_par_iter()
|
|
386
|
+
.map(|image| {
|
|
387
|
+
let hash = compute_sha256_hash(&image.path)?;
|
|
388
|
+
Ok((image, hash))
|
|
389
|
+
})
|
|
390
|
+
.collect::<Result<Vec<_>>>()?;
|
|
345
391
|
|
|
346
|
-
|
|
392
|
+
for (image, hash) in hashed_images {
|
|
393
|
+
let image_key = crate::utils::fs::path_as_url(&image.relative_path);
|
|
347
394
|
|
|
348
|
-
if manifest_entries.contains_key(&
|
|
349
|
-
|
|
350
|
-
.entry(image_file_name)
|
|
351
|
-
.or_default()
|
|
352
|
-
.push(relative_path);
|
|
395
|
+
if manifest_entries.contains_key(&image_key) {
|
|
396
|
+
duplicates.push(image_key);
|
|
353
397
|
continue;
|
|
354
398
|
}
|
|
355
399
|
|
|
356
|
-
let hash = compute_sha256_hash(&image.path)?;
|
|
357
|
-
let file = runtime
|
|
358
|
-
.block_on(tokio::fs::File::open(&image.path))
|
|
359
|
-
.with_context(|| {
|
|
360
|
-
format!("Failed to open image for upload: {}", image.path.display())
|
|
361
|
-
})?;
|
|
362
|
-
|
|
363
400
|
let key = format!("{org_id}/{project_id}/{hash}");
|
|
364
|
-
info!("Queueing {} as {key}", image.relative_path.display());
|
|
365
|
-
|
|
366
|
-
many_builder = many_builder.push(
|
|
367
|
-
session
|
|
368
|
-
.put_file(file)
|
|
369
|
-
.key(&key)
|
|
370
|
-
.expiration_policy(expiration),
|
|
371
|
-
);
|
|
372
401
|
|
|
373
402
|
let mut extra = read_sidecar_metadata(&image.path).unwrap_or_else(|err| {
|
|
374
403
|
warn!("Error reading sidecar metadata, ignoring it instead: {err:#}");
|
|
@@ -376,48 +405,52 @@ fn upload_images(
|
|
|
376
405
|
});
|
|
377
406
|
extra.insert("content_hash".to_owned(), serde_json::Value::String(hash));
|
|
378
407
|
|
|
379
|
-
|
|
408
|
+
uploads.push(PreparedImage {
|
|
409
|
+
path: image.path,
|
|
410
|
+
key,
|
|
411
|
+
});
|
|
380
412
|
manifest_entries.insert(
|
|
381
|
-
|
|
413
|
+
image_key,
|
|
382
414
|
ImageMetadata::new(image.width, image.height, extra),
|
|
383
415
|
);
|
|
384
416
|
}
|
|
385
417
|
|
|
386
|
-
if !
|
|
387
|
-
let
|
|
388
|
-
|
|
389
|
-
let mut all_paths = vec![kept_paths[name].as_str()];
|
|
390
|
-
all_paths.extend(excluded_paths.iter().map(|s| s.as_str()));
|
|
391
|
-
details.push_str(&format!("\n {name}: {}", all_paths.join(", ")));
|
|
392
|
-
}
|
|
393
|
-
warn!("Some images share identical file names. Only the first occurrence of each is included:{details}");
|
|
418
|
+
if !duplicates.is_empty() {
|
|
419
|
+
let paths = duplicates.join(", ");
|
|
420
|
+
warn!("Duplicate paths encountered, skipping: {paths}");
|
|
394
421
|
}
|
|
395
422
|
|
|
396
|
-
let
|
|
423
|
+
let total_count = uploads.len();
|
|
397
424
|
|
|
398
|
-
let
|
|
425
|
+
let mut many_builder = session.many();
|
|
426
|
+
for prepared in uploads {
|
|
427
|
+
many_builder = many_builder.push(
|
|
428
|
+
session
|
|
429
|
+
.put_path(prepared.path.clone())
|
|
430
|
+
.key(&prepared.key)
|
|
431
|
+
.expiration_policy(expiration),
|
|
432
|
+
);
|
|
433
|
+
}
|
|
399
434
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
);
|
|
408
|
-
Ok(manifest_entries)
|
|
409
|
-
}
|
|
410
|
-
Err(errors) => {
|
|
411
|
-
eprintln!("There were errors uploading images:");
|
|
412
|
-
let mut error_count = 0;
|
|
413
|
-
for error in errors {
|
|
414
|
-
let error = anyhow::Error::new(error);
|
|
415
|
-
eprintln!(" {}", style(format!("{error:#}")).red());
|
|
416
|
-
error_count += 1;
|
|
417
|
-
}
|
|
418
|
-
anyhow::bail!("Failed to upload {error_count} out of {uploaded_count} images")
|
|
435
|
+
let result = runtime.block_on(async { many_builder.send().await.error_for_failures().await });
|
|
436
|
+
if let Err(errors) = result {
|
|
437
|
+
let errors: Vec<_> = errors.collect();
|
|
438
|
+
let error_count = errors.len();
|
|
439
|
+
eprintln!("There were errors uploading images:");
|
|
440
|
+
for error in errors {
|
|
441
|
+
let error = anyhow::Error::new(error);
|
|
442
|
+
eprintln!(" {}", style(format!("{error:#}")).red());
|
|
419
443
|
}
|
|
444
|
+
anyhow::bail!("Failed to upload {error_count} images");
|
|
420
445
|
}
|
|
446
|
+
|
|
447
|
+
println!(
|
|
448
|
+
"{} Uploaded {} image {}",
|
|
449
|
+
style(">").dim(),
|
|
450
|
+
style(total_count).yellow(),
|
|
451
|
+
if total_count == 1 { "file" } else { "files" }
|
|
452
|
+
);
|
|
453
|
+
Ok(manifest_entries)
|
|
421
454
|
}
|
|
422
455
|
|
|
423
456
|
#[cfg(test)]
|